Merge branch 'master' into vulkan

This commit is contained in:
Lynix 2020-02-23 00:46:48 +01:00
commit 8be2342f25
382 changed files with 50494 additions and 5037 deletions

3
.gitignore vendored
View File

@ -67,6 +67,9 @@ build/**/*.nativecodeanalysis.all.xml
build/**/*.nativecodeanalysis.xml
build/**/*.VC.opendb
build/**/*.VC.db*
build/**/*.json
build/**/*.sqlite
build/**/*.FileListAbsolute.txt
# Compiled Object files
build/**/*.slo

5
AUTHORS Normal file
View File

@ -0,0 +1,5 @@
Nazara Engine was originally created in early 2012.
It follows a complete overhaul of a previous project in order to offer more features and modularity.
Jérôme "Lynix" Leclercq - main developper (lynix680@gmail.com)
Full Cycle Games - sponsor and contributor since January 2017.

View File

@ -17,6 +17,11 @@ Miscellaneous:
- NDEBUG is now defined in Release
- Replaced typedefs keywords with modern using keywords
- When supported, projects are now parts of a virtual "workspace group" according to their kind
- Fixed .dll copy when building Nazara occuring on Linux when targeting Windows (MinGW)
- ⚠ Appveyor nightlies are now compiled with VS2017
- Set libraries' rpath to current folder (.)
- Add ReleaseWithDebug target
- ⚠ **Default font has been changed from Cabin to OpenSans**
Nazara Engine:
- VertexMapper:GetComponentPtr no longer throw an error if component is disabled or incompatible with template type, instead a null pointer is returned.
@ -52,7 +57,7 @@ Nazara Engine:
- Fix RigidBody3D copy constructor not copying all physics states (angular/linear damping/velocity, mass center, position and rotation)
- Add RigidBody3D simulation control (via EnableSimulation and IsSimulationEnabled), which allows to disable physics and collisions at will.
- Fix some uninitialized values (found by Valgrind) in Network module
- Fix possible infinite recursion when outputting a Thread::Id object
- Fix possible infinite recursion when outputting a Thread::Id object
- ⚠️ Replaced implicit conversion from a Nz::String to a std::string by an explicit method ToStdString()
- Fix LuaInstance movement constructor/assignment operator which was corrupting Lua memory
- Fix potential bug on SocketImpl::Connect (used by TcpClient::Connect) on POSIX platforms
@ -107,7 +112,9 @@ Nazara Engine:
- Added AbstractViewer::Project and AbstractViewer::Unproject methods
- Added AbstractViewer::ProjectDepth method
- Fixed SocketPoller not be able to recover from some errors (like invalid sockets and such)
- ⚠️ Replaced currentBitPos and currentByte fields by [read|write][BitPos][Byte] to handle properly bit reading/writing.
- Add LuaImplQuery implementation for std::vector
- Fixed LuaState::PushGlobal & LuaState::PushField to copy the object before moving it
- ⚠️ Replaced currentBitPos and currentByte fields by [read|write][BitPos][Byte] to handle properly bit reading/writing.
- InstancedRenderable::SetMaterial methods are now public.
- Fixed Model copy constructor not copying materials
- ⚠️ Added InstancedRenderable::Clone() method
@ -115,6 +122,106 @@ Nazara Engine:
- ⚠️ SocketPoller::Wait now returns the number of socket marked as ready, and takes an additional optional parameter allowing to query the last error.
- SocketPoller will now silently ignore "interrupt errors"
- Added RigidBody2D::ClosestPointQuery
- Fix Sprite copy constructor not copying corner colors
- Added ObjectLibrary::Clear method
- ⚠️ StackArray class and macro was moved from Core/MemoryHelper.hpp to Core/StackArray.hpp
- ⚠️ Renamed NazaraStackAllocation[NoInit] macro to NazaraStackArray[NoInit]
- Added StackVector class
- ⚠️ Removed Vector[2|3]::Distancef method and made Distance method templated
- Added Vector2::Distance static method
- ⚠️ Fixed compilation errors on MSVC with flag /permissive- on CullingList class
- Added LuaImplQueryArg & LuaImplReplyVal functions for Vector[2|3]<int>
- Fixed bug in ENet implementation causing legit reliable packets to be dropped on sequence number overflow
- Fixed bug where index wouldn't be used in String::FindLast and String::FindWord
- Physics 2D contact callbacks now include an arbiter allowing to query/set parameters about the collision
- Added movement with Ctrl in TextAreaWidget
- Added Unicode Data downloader/parser
- Integrated Unicode Data
- Added CullingList::FillWithAllEntries method
- Fixed ObjectHandle movement sometimes not resetting its internal pointer
- Added BoxCollider2D::GetRadius
- Added CircleCollider2D::GetOffset
- Added ConvexCollider2D::GetVertices
- Added SegmentCollider2D::GetThickness
- Fixed vertices generation/render queue submit when using multiples materials on a Tilemap
- It is now possible to prevent CompoundCollider2D to override individual colliders properties
- Fixed TcpClient::WaitForConnected possible failure (although connected) on Windows/Linux
- CullingList now handles box tests
- ⚠️ CullingList now handles full and partial visibility testing
- Added math class Angle, capable of handling both degrees and radians angles and converting them to euler angles/quaternions to improve 2D interface.
- ⚠️ AbstractSocket::OnStateChange has been replaced by OnStateChanged, which is now called after state has been changed (with oldState and newState as parameters).
- ⚠️ TcpClient::WaitForconnected now returns the new socket state.
- Added TcpClient::PollForConnected
- ⚠️ Use of the new Angle class instead of floating point angle
- It is now possible to set elasticity/friction/surface bodies of 2D colliders and change it at runtime on RigidBody2D
- ObjectHandle were remade and should be way more optimized now
- Added ENetHost and ENetPeer accessor to total packet/data received/sent/lost
- ⚠ **Changed the way resources were Loaded, almost every LoadFromX and OpenFromX methods are now static and create the object themselves.**
- ⚠ SoundStream is now responsible for loaders instead of Music, and is now threadsafe (you can now load a stream only once and play it multiple times at the same time)
- Added LuaState::RawEqual
- Fixed LuaCoroutine movement assignation operator
- Added Arbiter2D::GetBodies
- Added RigidBody2D::ForEachArbiter
- Added possibility to change the RigidBody2D velocity function called by the physics engine
- Fixed MouseButtonEvent and MouseMoveEvent mouse absolute position being unsigned (now signed)
- Fixed Window::SetCursor changing cursor even if window was in foreground on Windows
- Fixed SystemCursor_Move not showing up on Windows
- Fixed Window movement constructor/assignation operator
- Window::PushEvent is now public (useful for pushing external events ie. when using Qt or similar framework controlling window)
- Fixed TileMap not rendering the right materials if it had no tile using some materials in-between
- Added Vector[2|3|4](u)i64 typedefs
- Fixed missing static Vector4::DotProduct implementation
- ⚠ **By default, Nazara now computes the mass center of all 2D physics object when calling SetGeom**
- ⚠ Added Collider2D::ComputeCenterOfMass
- Signal now implement a copy constructor and copy assignation operator for convenience
- Fixed ENet UnreliableFragment packets sent as Unreliable (and such being incomplete upon reception)
- ENet DisconnectLater now reflects libenet behavior (and is waiting for unreliable commands to be sent before disconnecting for good)
- ⚠ Collider3D::ForEachPolygon now takes a void(Vector3f\*, std::size_t) callback (instead of void(float\*, std::size_t))
- Added Collider2D::ForEachPolygon method
- Added RigidBody::[Get|Set]PositionOffset allowing set an offset between body logic position and body physics position (center of mass position)
- ⚠ Default TextureSampler WrapMode is now Clamp (instead of Repeat)
- Fixed StateMachine ignoring transitions made in Enter/Leave events of states
- Fixed Material::Configure resetting textures
- ⚠ Renamed TextStyleFlags enum to TextStyle, introduced Flags specialization of TextStyle as TextStyleFlags
- ⚠ Font, FontData and SimpleTextDrawer now use a proper TextStyleFlags instead of a UInt32
- Almost all Math algorithms are now constexpr
- PhysWorld2D: Fixed callbacks not properly replacing each others when registering twice with the same collisionId (pair)
- ⚠ **Font, FontData and SimpleTextDrawer now supports text outlining.**
- Fixed TextSprite not handling multiple textures well
- ⚠ TextSprite will now use multiple render layers by itself (the current one and the one right before, ex: [-1, 0] if base layer is 0) if you use text outlines.
- ⚠ SimpleTextDrawer no longer supports faux bold rendering
- Added PhysWorld2D::[RaycastQuery, RegionQuery] overloads taking a callback
- Added x and y mouse position to MouseWheelEvent
- Added SimpleTextDrawer::[Get|Set]MaxLineWidth (which does line wrap)
- TypeTag helper struct now includes a Type using
- GuillotineBinPack::Insert overload taking multiple rectangles no longer does a heap allocation
- StackArray and StackVector now have a default constructor initializing them with no size/capacity
- StackArray and StackVector are now movable
- Fixed RigidBody2D::Copy not copying kinematic/dynamic/static status
- Fixed out-of-bounds access in LuaInstance::LoadLibraries
- Add Flags<E>::Clear(Flags) helper method, to clear one or more flags.
- Add Flags<E>::Clear() helper method, to reset flags
- Add Flags<E>::Set(Flags) helper method, to enable flags
- ⚠ Constraint2D are no longer managed by references and are now handled objects
- ⚠ Removed all Set methods from math classes taking their own type (e.g. Box::Set(Box))
- Added Matrix4::Decompose
- ⚠ Node::Get[Position|Rotation|Scale] now defaults to local space
- Fixed Node rotation when using a negative scale
- Added HandledObject::OnHandledObjectDestruction signal
- Added physics function to control sleeping behavior
- String::Number is now locale-independent
- Added ENetPeer::GetTotalByte[Received|Sent]
- Added ENetPeer::GetTotalPacketSent
- ⚠ ENetHost::GetTotalReceivedPackets now returns the number of commands received (instead of the number of UDP packets received)
- Added EmptyStream class, useful to measure how many bytes some writing operations will take
- SegmentCollider2D: Add support for neighbors (aka "ghost vertices"), allowing to prevent seams collisions
- ⚠ OBJLoader flips UV by default, fixing a lot of models UV
- On Windows, Thread::Set(Current)Name now uses `SetThreadDescription` Win32 function if possible instead of triggering a debugger exception. MinGW builds will use this if available too.
- ⚠ Removed Texture(const Image\*) constructor, use Texture::LoadFromImage instead
- ⚠ TextDrawers now use floating-point internally and to exposes their Bounds (AbstractTextDrawer::GetBounds() now returns a Rectf)
- Added [SimpleTextDrawer|RichTextDrawer] character and line spacing offset properties
- Added ENetHost::AllowsIncomingConnections(bool) to disable/re-enable server peers connection
- Added ByteArrayPool and PoolByteStream classes
Nazara Development Kit:
- Added ImageWidget (#139)
@ -158,14 +265,65 @@ Nazara Development Kit:
- Fix GraphicsComponent bounding volume not taking local matrix in account
- ⚠️ Rewrote all render queue system, which should be more efficient, take scissor box into account
- ⚠️ All widgets are now bound to a scissor box when rendering
- Add DebugComponent (a component able to show aabb/obb/collision mesh)
- Add DebugComponent (a component able to show aabb/obb/collision mesh 2D and 3D)
- ⚠️ TextAreaWidget now support text selection (WIP)
- ⚠️ TextAreaWidget::GetHoveredGlyph now returns a two-dimensional position instead of a single glyph position
- Fixed Entity::OnEntityDestruction signal not being properly moved and thus not being called.
- Fixed EntityOwner move assignment which was losing entity ownership
- Add GraphicsComponent:ForEachRenderable method
- Added GraphicsComponent:ForEachRenderable method
- Fixed GraphicsComponent reflective material count which was not initialized
- Added PhysicsComponent2D::ClosestPointQuery
- Fixed GraphicsComponent copy constructor not copying scissor rect
- Force parent parameter to be present in widgets constructor
- Added the possibility to write only specific characters with a predicate in TextAreaWidget
- Enable write of Tab character in TextAreaWidget
- It is now possible to disable object culling in the RenderSystem
- Make Nz::PhysWorld2D& Ndk::PhysicsSystem2D::GetWorld private and rename it into GetPhysWorld
- Make Ndk::PhysicsSystem2D an interface of Nz::PhysWorld2D
- ⚠️ GraphicsComponent no longer has a BoundingVolume, it instead has only an AABB with its attached InstancedRenderable getting a BoundingVolume of their own, improving culling possibilities.
- RenderSystem now does cull InstancedRenderables attached to a GraphicsComponent, improving performance.
- ⚠️ Widgets have been reworked and no longer have padding, but instead have preferred, maximum and minimum size.
- ⚠️ BaseWidget::SetSize has been renamed to BaseWidget::Resize
- Added BaseWidget::ForEachWidgetChild
- Added experimental BoxLayout class
- RenderSystem now resolve skinning before render
- EntityOwner constructor taking a Entity* is no longer explicit
- PhysicsComponent2D now allows massless bodies (zero mass)
- ⚠️ Use of the new Angle class instead of floating point angle
- Added EntityOwner::Release
- Add missing `recomputeMoment` parameter to PhysicsComponent2D::SetMass
- Added possibility of disabling synchronization between PhysicsComponent2D and NodeComponent
- Fixed GraphicsComponent not invalidating render queue on material change (causing crashes or visual errors)
- Added CollisionComponent2D::SetGeomOffset and CollisionComponent2D::Recenter
- Added LifetimeComponent and LifetimeSystem
- Fixed a subtle bug regarding entities invalidation and kill (ex: if an entity #2 kills entity #1 during Entity::Destroy callbacks, entity #1 will survive destruction).
- Added PhysicsSystem2D::[RaycastQuery, RegionQuery] overloads taking a callback
- Added TextAreaWidget support for outline
- Fixed possible crash when disabling BaseWidget background
- Added BaseWidget::OnMouseWheelMoved
- Added Entity::OnEntity[Disabled|Enabled] signals
- Added BaseWidget::SetParent
- BaseWidget::Show will no longer show entities disabled by the widget
- BaseWidget now has a rendering rect property (allowing to tell a widget what part of it will be rendered)
- Added ScrollAreaWidget
- Console has been remade with widgets (allowing to scroll back history, select text, etc.)
- Added TextAreaWidget line wrap option
- TextAreaWidget will now shift the text to the left/right in order to keep the cursor visible
- Added TextAreaWidget::[Get|Set]TextFont
- ⚠️ TextAreaWidget::OnTextAreaCursorMove signal now uses a Vector2ui* position as its second argument (instead of a std::size_t*)
- Added TextAreaWidget::OnTextAreaSelection
- ⚠️ Console class is no longer bound to a LuaState and now has a OnCommand signal
- ⚠️ Made AbstractTextAreaWidget which is inherited by TextAreaWidget
- ⚠️ Added RichTextAreaWidget
- ⚠️ Console now supports text color in history
- Added World::CloneEntity overload taking an EntityHandle const reference, allowing to copy entities from other worlds
- Fixed PhysicsComponent2D copy not copying physics attributes
- Added Entity::DropComponent which detaches a component without necessarily destroying it
- ⚠ ConstraintComponent2D has been reworked to handle entity destruction and remove constraints at will
- Fixed crash when pressing up/down key with no history in the console
- (Rich)TextAreaWidget text style is now alterable
- Added CameraComponent::SetProjectionScale
- Added (Rich)TextAreaWidget character and line spacing offset properties
# 0.4:
@ -253,8 +411,8 @@ Nazara Engine:
- Added [Nz::TcpClient::SendMultiple](https://nazara.digitalpulsesoftware.net/doc/class_nz_1_1_tcp_client.html#a495c32beb46ed9192699a3b82d358035) method, allowing to send multiple buffers at once.
- Added [Nz::PlacementDestroy](https://nazara.digitalpulsesoftware.net/doc/namespace_nz.html#a27c8667def991fc896c5beff3e62668a). (ea985fa76586762f008e4054938db3234eeaf0cb)
- Added [Nz::String::Format](https://nazara.digitalpulsesoftware.net/doc/class_nz_1_1_string.html#a4b699982e7f9ea38f6d44b43ac1e2040) and [Nz::String::FormatVA](https://nazara.digitalpulsesoftware.net/doc/class_nz_1_1_string.html#abe0fcbce11224b157ac756b60e8dee92) static methods. (cc6e4127dc6c61799a64404770992cef0804ad34).
- Added [Nz::ParticleGroup::GetBuffer](https://nazara.digitalpulsesoftware.net/doc/class_nz_1_1_particle_mapper.html#aefe1b251efc8c9b8668842275561be0c) method. (4dc85789b59e50d964c83321dbd4b6485c04bef6)
- Added Nz::ParticleMapper::GetPointer method. (1f4e6c2d1594b7bb9dd6f4ea5480fdd16cf5f208)
- Added [Nz::ParticleGroup::GetBuffer](https://nazara.digitalpulsesoftware.net/doc/class_nz_1_1_particle_mapper.html#aefe1b251efc8c9b8668842275561be0c) method. (4dc85789b59e50d964c83321dbd4b6485c04bef6)
- Added Nz::ParticleMapper::GetPointer method. (1f4e6c2d1594b7bb9dd6f4ea5480fdd16cf5f208)
- ⚠️ Structures provied by ParticleStruct header now have a float life. (472d964d587d906764ad1e05bfcc9ab1bf979483)
- Fixed scale property of Nz::TextSprite not affecting its bounding volume. (52b29bac775823294c4ad7de70f4dc3f4adfa743)
- ⚠️ Nz:MeshParams::flipUVs has been replaced by texCoordOffset and texCoordScale. (a1a7d908adc060fd7a43491c903dfe3b501d98e5)
@ -281,7 +439,7 @@ Nazara Engine:
- All noises classes now uses std::mt19937 as a random number generator, to ensure the same results on every machine. (1f5ea9839016964c173d919263827dee69ecb65d)
Nazara Development Kit:
- **Added basic widgets**. (c8a12083b3133e946bf60dd060331a4b4631f8d8)
- **Added basic widgets**. (c8a12083b3133e946bf60dd060331a4b4631f8d8)
- VelocitySystem will no longer affect entities with PhysicsComponent2D. (a6853234412c744cdcb28344f02f7b0c92704d77)
- Fixed EulerAngles constructor in Lua. (d55149a0a70f6230b6f1c3fb50e37dc82a2feb9f)
- Fixed Component::OnDetached not being called on entity destruction. (5b777eb4853639d7aeb232ca46d17f0d432f47ca)
@ -292,7 +450,7 @@ Nazara Engine:
Nazara Engine:
- Nazara binaries are now compiled with Run-Time Type-Information. (a70acdc8f44010627a65282fd3099202116d3e13)
- Nazara demos are now compiled with relative dependencies on Linux.
- Nazara demos are now compiled with relative dependencies on Linux.
(d6fbb4c408d48c4a768fad7b43460c76a0df1777)
- Added [**Nz::BitCount**](https://nazara.digitalpulsesoftware.net/doc/group__core.html#ga6bfbcff78eb6cfbe3ddaedcfc8c04196) function. (82e31a3ec8449da6618f41690164c2e1d883edb4)
- Added [**Nz::Bitset::AppendBits**](https://nazara.digitalpulsesoftware.net/doc/class_nz_1_1_bitset.html#a5ca8f365006c86d6d699d02471904f7e) method. (b018a400499a2356c4455a40d9f6a6c12b3cb36b)

53
INSTALL.md Normal file
View File

@ -0,0 +1,53 @@
# Installation
> **Notice**: For french speakers, a more detailed explanation of the instructions is provided here: [Instructions pour compiler](wiki/(FR)-Compiler-le-moteur).
The first step to using the engine is to recover it. This can currently be done in two ways:
1) This can be don either from the original github (only the development is continuously evolving):
```git clone https://github.com/DigitalPulseSoftware/NazaraEngine.git```
2) Or by downloading a [zip file](https://github.com/DigitalPulseSoftware/NazaraEngine/archive/master.zip) containing the entire source code of the engine.
All you have to do is go to the "build/" folder. The compilation system uses [premake](https://premake.github.io/) to generate build systems.
## Windows
For Windows users, they can directly use ".bat" files such as: "Build_VS2017.bat". It will generate a solution "NazaraEngine.sln" ready to use that you can directly build to produce the libs or execute the samples.
## Linux
Linux users, can type: "./premake5-linux64 gmake" or with the additional argument "--cc=clang" to configure the C++ compiler used.
Some additional libraries will be required for compilation depending on the modules used:
#### Audio module (OpenAL and libsndfile)
- with apt: `sudo apt-get install libopenal-dev libsndfile1-dev`
- with pacman: `sudo pacman -S openal libsndfile`
#### Platform module (Freetype):
- with apt: `sudo apt-get install libfreetype6-dev`
- with pacman: `sudo pacman -S freetype2`
#### Utility module (XCB + X11):
- with apt: `sudo apt-get install libxcb-cursor-dev libxcb-ewmh-dev libxcb-randr0-dev libxcb-icccm4-dev libxcb-keysyms1-dev libx11-dev`
- with pacman: `sudo pacman -S libxcb libx11`
#### OpenGL renderer module:
- with apt: `sudo apt-get install mesa-common-dev libgl1-mesa-dev`
- with pacman: `sudo pacman -S mesa`
#### Plugin Assimp:
- with apt: `sudo apt-get install libassimp-dev`
- with pacman: `sudo pacman -S assimp`
#### The one line command to install everything is:
- with apt: `sudo apt-get install libopenal-dev libsndfile1-dev libfreetype6-dev libxcb-cursor-dev libxcb-ewmh-dev libxcb-randr0-dev libxcb-icccm4-dev libxcb-keysyms1-dev libx11-dev mesa-common-dev libgl1-mesa-dev libassimp-dev`
- with pacman: `sudo pacman -S openal libsndfile freetype2 libxcb libx11 mesa assimp`
## Test
One should now be able to execute the samples provided in the folder "NazaraEngine/examples/bin/" or the unit tests within "NazaraEngine/tests/".

View File

@ -1,95 +0,0 @@
Copyright (c) 2011, Pablo Impallari (www.impallari.com|impallari@gmail.com),
Copyright (c) 2011, Igino Marini. (www.ikern.com|mail@iginomarini.com),
with Reserved Font Name Cabin.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

201
License-OpenSans.txt Normal file
View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -15,6 +15,7 @@
#include <set>
#ifndef NDK_SERVER
#include <NDK/Canvas.hpp>
#include <NDK/Console.hpp>
#include <Nazara/Core/Log.hpp>
#include <Nazara/Lua/LuaInstance.hpp>
@ -81,7 +82,7 @@ namespace Ndk
#ifndef NDK_SERVER
struct ConsoleOverlay
{
std::unique_ptr<Console> console;
Console* console;
Nz::LuaInstance lua;
NazaraSlot(Nz::EventHandler, OnEvent, eventSlot);
@ -114,10 +115,11 @@ namespace Ndk
Nz::RenderTarget* renderTarget;
std::unique_ptr<Nz::Window> window;
std::unique_ptr<ConsoleOverlay> console;
std::unique_ptr<Canvas> canvas;
std::unique_ptr<FPSCounterOverlay> fpsCounter;
std::unique_ptr<World> overlayWorld;
};
void SetupConsole(WindowInfo& info);
void SetupFPSCounter(WindowInfo& info);
void SetupOverlay(WindowInfo& info);

View File

@ -112,7 +112,6 @@ namespace Ndk
}
m_overlayFlags |= OverlayFlags_Console;
}
else
{

View File

@ -26,8 +26,6 @@ namespace Ndk
friend Canvas;
public:
struct Padding;
BaseWidget(BaseWidget* parent);
BaseWidget(const BaseWidget&) = delete;
BaseWidget(BaseWidget&&) = delete;
@ -41,54 +39,79 @@ namespace Ndk
inline void CenterVertical();
void ClearFocus();
inline void ClearRenderingRect();
void Destroy();
void EnableBackground(bool enable);
template<typename F> void ForEachWidgetChild(F iterator);
template<typename F> void ForEachWidgetChild(F iterator) const;
//virtual BaseWidget* Clone() const = 0;
inline const Nz::Color& GetBackgroundColor() const;
inline Canvas* GetCanvas();
inline Nz::SystemCursor GetCursor() const;
inline const Padding& GetPadding() const;
inline Nz::Vector2f GetContentOrigin() const;
inline const Nz::Vector2f& GetContentSize() const;
inline float GetHeight() const;
inline float GetMaximumHeight() const;
inline Nz::Vector2f GetMaximumSize() const;
inline float GetMaximumWidth() const;
inline float GetMinimumHeight() const;
inline Nz::Vector2f GetMinimumSize() const;
inline float GetMinimumWidth() const;
inline float GetPreferredHeight() const;
inline Nz::Vector2f GetPreferredSize() const;
inline float GetPreferredWidth() const;
inline const Nz::Rectf& GetRenderingRect() const;
inline Nz::Vector2f GetSize() const;
inline float GetWidth() const;
inline std::size_t GetWidgetChildCount() const;
bool HasFocus() const;
inline bool IsVisible() const;
virtual void ResizeToContent() = 0;
void Resize(const Nz::Vector2f& size);
void SetBackgroundColor(const Nz::Color& color);
void SetCursor(Nz::SystemCursor systemCursor);
inline void SetContentSize(const Nz::Vector2f& size);
void SetFocus();
inline void SetPadding(float left, float top, float right, float bottom);
void SetSize(const Nz::Vector2f& size);
void SetParent(BaseWidget* widget);
inline void SetFixedHeight(float fixedHeight);
inline void SetFixedSize(const Nz::Vector2f& fixedSize);
inline void SetFixedWidth(float fixedWidth);
inline void SetMaximumHeight(float maximumHeight);
inline void SetMaximumSize(const Nz::Vector2f& maximumSize);
inline void SetMaximumWidth(float maximumWidth);
inline void SetMinimumHeight(float minimumHeight);
inline void SetMinimumSize(const Nz::Vector2f& minimumSize);
inline void SetMinimumWidth(float minimumWidth);
virtual void SetRenderingRect(const Nz::Rectf& renderingRect);
void Show(bool show = true);
BaseWidget& operator=(const BaseWidget&) = delete;
BaseWidget& operator=(BaseWidget&&) = delete;
struct Padding
{
float left;
float top;
float right;
float bottom;
};
protected:
const EntityHandle& CreateEntity(bool isContentEntity);
const EntityHandle& CreateEntity();
void DestroyEntity(Entity* entity);
virtual void Layout();
void InvalidateNode() override;
Nz::Rectf GetScissorRect() const;
virtual bool IsFocusable() const;
virtual void OnFocusLost();
virtual void OnFocusReceived();
@ -98,14 +121,17 @@ namespace Ndk
virtual void OnMouseMoved(int x, int y, int deltaX, int deltaY);
virtual void OnMouseButtonPress(int x, int y, Nz::Mouse::Button button);
virtual void OnMouseButtonRelease(int x, int y, Nz::Mouse::Button button);
virtual void OnMouseWheelMoved(int x, int y, float delta);
virtual void OnMouseExit();
virtual void OnParentResized(const Nz::Vector2f& newSize);
virtual void OnTextEntered(char32_t character, bool repeated);
inline void SetPreferredSize(const Nz::Vector2f& preferredSize);
private:
inline BaseWidget();
inline void DestroyChild(BaseWidget* widget);
void DestroyChild(BaseWidget* widget);
void DestroyChildren();
inline bool IsRegisteredToCanvas() const;
inline void NotifyParentResized(const Nz::Vector2f& newSize);
@ -117,7 +143,10 @@ namespace Ndk
struct WidgetEntity
{
EntityOwner handle;
bool isContent;
bool isEnabled = true;
NazaraSlot(Ndk::Entity, OnEntityDisabled, onDisabledSlot);
NazaraSlot(Ndk::Entity, OnEntityEnabled, onEnabledSlot);
};
static constexpr std::size_t InvalidCanvasIndex = std::numeric_limits<std::size_t>::max();
@ -127,12 +156,15 @@ namespace Ndk
std::vector<std::unique_ptr<BaseWidget>> m_children;
Canvas* m_canvas;
EntityOwner m_backgroundEntity;
Padding m_padding;
WorldHandle m_world;
Nz::Color m_backgroundColor;
Nz::Rectf m_renderingRect;
Nz::SpriteRef m_backgroundSprite;
Nz::SystemCursor m_cursor;
Nz::Vector2f m_contentSize;
Nz::Vector2f m_maximumSize;
Nz::Vector2f m_minimumSize;
Nz::Vector2f m_preferredSize;
Nz::Vector2f m_size;
BaseWidget* m_widgetParent;
bool m_visible;
};

View File

@ -5,6 +5,7 @@
#include <NDK/BaseWidget.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Math/Algorithm.hpp>
#include <limits>
namespace Ndk
{
@ -12,12 +13,15 @@ namespace Ndk
m_canvasIndex(InvalidCanvasIndex),
m_canvas(nullptr),
m_backgroundColor(Nz::Color(230, 230, 230, 255)),
m_renderingRect(-std::numeric_limits<float>::infinity(), -std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity()),
m_cursor(Nz::SystemCursor_Default),
m_contentSize(50.f, 50.f),
m_maximumSize(std::numeric_limits<float>::infinity()),
m_minimumSize(0.f),
m_preferredSize(-1),
m_size(50.f, 50.f),
m_widgetParent(nullptr),
m_visible(true)
{
SetPadding(5.f, 5.f, 5.f, 5.f);
}
template<typename T, typename... Args>
@ -64,6 +68,25 @@ namespace Ndk
SetPosition(GetPosition(Nz::CoordSys_Local).x, (parentSize.y - mySize.y) / 2.f);
}
inline void BaseWidget::ClearRenderingRect()
{
SetRenderingRect(Nz::Rectf(-std::numeric_limits<float>::infinity(), -std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity()));
}
template<typename F>
inline void BaseWidget::ForEachWidgetChild(F iterator)
{
for (const auto& child : m_children)
iterator(child.get());
}
template<typename F>
inline void BaseWidget::ForEachWidgetChild(F iterator) const
{
for (const auto& child : m_children)
iterator(static_cast<const BaseWidget*>(child.get()));
}
inline const Nz::Color& BaseWidget::GetBackgroundColor() const
{
return m_backgroundColor;
@ -79,24 +102,74 @@ namespace Ndk
return m_cursor;
}
inline const BaseWidget::Padding& BaseWidget::GetPadding() const
inline float BaseWidget::GetHeight() const
{
return m_padding;
return m_size.y;
}
inline Nz::Vector2f BaseWidget::GetContentOrigin() const
inline float BaseWidget::GetMaximumHeight() const
{
return { m_padding.left, m_padding.top };
return m_maximumSize.y;
}
inline const Nz::Vector2f& BaseWidget::GetContentSize() const
inline Nz::Vector2f BaseWidget::GetMaximumSize() const
{
return m_contentSize;
return m_maximumSize;
}
inline float BaseWidget::GetMaximumWidth() const
{
return m_maximumSize.x;
}
inline float BaseWidget::GetMinimumHeight() const
{
return m_minimumSize.y;
}
inline Nz::Vector2f BaseWidget::GetMinimumSize() const
{
return m_minimumSize;
}
inline float BaseWidget::GetMinimumWidth() const
{
return m_minimumSize.x;
}
inline float BaseWidget::GetPreferredHeight() const
{
return m_preferredSize.y;
}
inline Nz::Vector2f BaseWidget::GetPreferredSize() const
{
return m_preferredSize;
}
inline float BaseWidget::GetPreferredWidth() const
{
return m_preferredSize.x;
}
inline const Nz::Rectf& BaseWidget::GetRenderingRect() const
{
return m_renderingRect;
}
inline Nz::Vector2f BaseWidget::GetSize() const
{
return Nz::Vector2f(m_contentSize.x + m_padding.left + m_padding.right, m_contentSize.y + m_padding.top + m_padding.bottom);
return Nz::Vector2f(GetWidth(), GetHeight());
}
inline float BaseWidget::GetWidth() const
{
return m_size.x;
}
inline std::size_t BaseWidget::GetWidgetChildCount() const
{
return m_children.size();
}
inline bool BaseWidget::IsVisible() const
@ -104,22 +177,79 @@ namespace Ndk
return m_visible;
}
inline void BaseWidget::SetContentSize(const Nz::Vector2f& size)
inline void BaseWidget::SetFixedHeight(float fixedHeight)
{
NotifyParentResized(size);
m_contentSize = size;
Layout();
SetMaximumHeight(fixedHeight);
SetMinimumHeight(fixedHeight);
}
inline void BaseWidget::SetPadding(float left, float top, float right, float bottom)
inline void BaseWidget::SetFixedSize(const Nz::Vector2f& fixedSize)
{
m_padding.left = left;
m_padding.top = top;
m_padding.bottom = bottom;
m_padding.right = right;
SetMaximumSize(fixedSize);
SetMinimumSize(fixedSize);
}
Layout();
inline void BaseWidget::SetFixedWidth(float fixedWidth)
{
SetMaximumWidth(fixedWidth);
SetMinimumWidth(fixedWidth);
}
inline void BaseWidget::SetMaximumHeight(float maximumHeight)
{
Nz::Vector2f maximumSize = GetMaximumSize();
maximumSize.y = maximumHeight;
SetMaximumSize(maximumSize);
}
inline void BaseWidget::SetMaximumSize(const Nz::Vector2f& maximumSize)
{
m_maximumSize = maximumSize;
Nz::Vector2f size = GetSize();
if (size.x > m_maximumSize.x || size.y > m_maximumSize.y)
Resize(size); //< Will clamp automatically
}
inline void BaseWidget::SetMaximumWidth(float maximumWidth)
{
Nz::Vector2f maximumSize = GetMaximumSize();
maximumSize.x = maximumWidth;
SetMaximumSize(maximumSize);
}
inline void BaseWidget::SetMinimumHeight(float minimumHeight)
{
Nz::Vector2f minimumSize = GetMinimumSize();
minimumSize.y = minimumHeight;
SetMinimumSize(minimumSize);
}
inline void BaseWidget::SetMinimumSize(const Nz::Vector2f& minimumSize)
{
m_minimumSize = minimumSize;
Nz::Vector2f size = GetSize();
if (size.x < m_minimumSize.x || size.y < m_minimumSize.y)
Resize(size); //< Will clamp automatically
}
inline void BaseWidget::SetMinimumWidth(float minimumWidth)
{
Nz::Vector2f minimumSize = GetMinimumSize();
minimumSize.x = minimumWidth;
SetMinimumSize(minimumSize);
}
inline void BaseWidget::SetPreferredSize(const Nz::Vector2f& preferredSize)
{
m_preferredSize = preferredSize;
//Resize(m_preferredSize);
}
inline bool BaseWidget::IsRegisteredToCanvas() const

View File

@ -28,11 +28,12 @@ namespace Ndk
inline const WorldHandle& GetWorld() const;
void ResizeToContent() override;
Canvas& operator=(const Canvas&) = delete;
Canvas& operator=(Canvas&&) = delete;
NazaraSignal(OnUnhandledKeyPressed, const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::KeyEvent& /*event*/);
NazaraSignal(OnUnhandledKeyReleased, const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::KeyEvent& /*event*/);
protected:
inline void ClearKeyboardOwner(std::size_t canvasIndex);
@ -50,8 +51,9 @@ namespace Ndk
private:
void OnEventMouseButtonPressed(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::MouseButtonEvent& event);
void OnEventMouseButtonRelease(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::MouseButtonEvent& event);
void OnEventMouseMoved(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::MouseMoveEvent& event);
void OnEventMouseLeft(const Nz::EventHandler* eventHandler);
void OnEventMouseMoved(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::MouseMoveEvent& event);
void OnEventMouseWheelMoved(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::MouseWheelEvent& event);
void OnEventKeyPressed(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::KeyEvent& event);
void OnEventKeyReleased(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::KeyEvent& event);
void OnEventTextEntered(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::TextEvent& event);
@ -67,8 +69,9 @@ namespace Ndk
NazaraSlot(Nz::EventHandler, OnKeyReleased, m_keyReleasedSlot);
NazaraSlot(Nz::EventHandler, OnMouseButtonPressed, m_mouseButtonPressedSlot);
NazaraSlot(Nz::EventHandler, OnMouseButtonReleased, m_mouseButtonReleasedSlot);
NazaraSlot(Nz::EventHandler, OnMouseMoved, m_mouseMovedSlot);
NazaraSlot(Nz::EventHandler, OnMouseLeft, m_mouseLeftSlot);
NazaraSlot(Nz::EventHandler, OnMouseMoved, m_mouseMovedSlot);
NazaraSlot(Nz::EventHandler, OnMouseWheelMoved, m_mouseWheelMovedSlot);
NazaraSlot(Nz::EventHandler, OnTextEntered, m_textEnteredSlot);
std::size_t m_keyboardOwner;

View File

@ -24,12 +24,10 @@ namespace Ndk
m_keyReleasedSlot.Connect(eventHandler.OnKeyReleased, this, &Canvas::OnEventKeyReleased);
m_mouseButtonPressedSlot.Connect(eventHandler.OnMouseButtonPressed, this, &Canvas::OnEventMouseButtonPressed);
m_mouseButtonReleasedSlot.Connect(eventHandler.OnMouseButtonReleased, this, &Canvas::OnEventMouseButtonRelease);
m_mouseMovedSlot.Connect(eventHandler.OnMouseMoved, this, &Canvas::OnEventMouseMoved);
m_mouseLeftSlot.Connect(eventHandler.OnMouseLeft, this, &Canvas::OnEventMouseLeft);
m_mouseMovedSlot.Connect(eventHandler.OnMouseMoved, this, &Canvas::OnEventMouseMoved);
m_mouseWheelMovedSlot.Connect(eventHandler.OnMouseWheelMoved, this, &Canvas::OnEventMouseWheelMoved);
m_textEnteredSlot.Connect(eventHandler.OnTextEntered, this, &Canvas::OnEventTextEntered);
// Disable padding by default
SetPadding(0.f, 0.f, 0.f, 0.f);
}
inline Canvas::~Canvas()
@ -61,7 +59,7 @@ namespace Ndk
{
WidgetEntry& entry = m_widgetEntries[index];
Nz::Vector3f pos = entry.widget->GetPosition();
Nz::Vector3f pos = entry.widget->GetPosition(Nz::CoordSys_Global);
Nz::Vector2f size = entry.widget->GetSize();
entry.box.Set(pos.x, pos.y, pos.z, size.x, size.y, 1.f);

View File

@ -12,7 +12,7 @@
namespace Ndk
{
template<typename ComponentType>
class Component : public BaseComponent
class Component : public BaseComponent, public Nz::HandledObject<ComponentType>
{
public:
Component();

View File

@ -11,6 +11,7 @@
#include <NDK/Components/ConstraintComponent2D.hpp>
#include <NDK/Components/DebugComponent.hpp>
#include <NDK/Components/GraphicsComponent.hpp>
#include <NDK/Components/LifetimeComponent.hpp>
#include <NDK/Components/LightComponent.hpp>
#include <NDK/Components/ListenerComponent.hpp>
#include <NDK/Components/NodeComponent.hpp>

View File

@ -22,7 +22,7 @@ namespace Ndk
using CameraComponentHandle = Nz::ObjectHandle<CameraComponent>;
class NDK_API CameraComponent : public Component<CameraComponent>, public Nz::AbstractViewer, public Nz::HandledObject<CameraComponent>
class NDK_API CameraComponent : public Component<CameraComponent>, public Nz::AbstractViewer
{
public:
inline CameraComponent();
@ -43,6 +43,7 @@ namespace Ndk
const Nz::Frustumf& GetFrustum() const override;
inline unsigned int GetLayer() const;
const Nz::Matrix4f& GetProjectionMatrix() const override;
inline const Nz::Vector3f& GetProjectionScale() const;
Nz::ProjectionType GetProjectionType() const override;
inline const Nz::Vector2f& GetSize() const;
const Nz::RenderTarget* GetTarget() const override;
@ -54,6 +55,7 @@ namespace Ndk
inline void SetFOV(float fov);
void SetLayer(unsigned int layer);
inline void SetProjectionScale(const Nz::Vector3f& scale);
inline void SetProjectionType(Nz::ProjectionType projection);
inline void SetSize(const Nz::Vector2f& size);
inline void SetSize(float width, float height);
@ -99,6 +101,7 @@ namespace Ndk
mutable Nz::Recti m_viewport;
const Nz::RenderTarget* m_target;
Nz::Vector2f m_size;
Nz::Vector3f m_projectionScale;
mutable bool m_frustumUpdated;
mutable bool m_projectionMatrixUpdated;
mutable bool m_viewMatrixUpdated;

View File

@ -17,6 +17,7 @@ namespace Ndk
m_targetRegion(0.f, 0.f, 1.f, 1.f),
m_target(nullptr),
m_size(0.f),
m_projectionScale(1.f, 1.f, 1.f),
m_frustumUpdated(false),
m_projectionMatrixUpdated(false),
m_viewMatrixUpdated(false),
@ -38,12 +39,12 @@ namespace Ndk
inline CameraComponent::CameraComponent(const CameraComponent& camera) :
Component(camera),
AbstractViewer(camera),
HandledObject(camera),
m_visibilityHash(camera.m_visibilityHash),
m_projectionType(camera.m_projectionType),
m_targetRegion(camera.m_targetRegion),
m_target(nullptr),
m_size(camera.m_size),
m_projectionScale(camera.m_projectionScale),
m_frustumUpdated(false),
m_projectionMatrixUpdated(false),
m_viewMatrixUpdated(false),
@ -116,11 +117,19 @@ namespace Ndk
return m_layer;
}
/*!
* \brief Gets the projection scale of the camera
* \return Projection scale
*/
const Nz::Vector3f& CameraComponent::GetProjectionScale() const
{
return m_projectionScale;
}
/*!
* \brief Gets the size of the camera
* \return Size of the camera
*/
inline const Nz::Vector2f & CameraComponent::GetSize() const
{
return m_size;
@ -152,12 +161,23 @@ namespace Ndk
InvalidateProjectionMatrix();
}
/*!
* \brief Sets the camera projection scale
*
* \param scale New projection scale
*/
inline void CameraComponent::SetProjectionScale(const Nz::Vector3f& scale)
{
m_projectionScale = scale;
InvalidateProjectionMatrix();
}
/*!
* \brief Sets the projection type of the camera
*
* \param projectionType Projection type of the camera
*/
inline void CameraComponent::SetProjectionType(Nz::ProjectionType projectionType)
{
m_projectionType = projectionType;

View File

@ -14,10 +14,15 @@
namespace Ndk
{
class CollisionComponent2D;
using CollisionComponent2DHandle = Nz::ObjectHandle<CollisionComponent2D>;
class NDK_API CollisionComponent2D : public Component<CollisionComponent2D>
{
friend class PhysicsSystem2D;
friend class ConstraintComponent2D;
friend class PhysicsComponent2D;
friend class PhysicsSystem2D;
public:
CollisionComponent2D(Nz::Collider2DRef geom = Nz::Collider2DRef());
@ -26,8 +31,12 @@ namespace Ndk
Nz::Rectf GetAABB() const;
const Nz::Collider2DRef& GetGeom() const;
const Nz::Vector2f& GetGeomOffset() const;
void Recenter(const Nz::Vector2f& origin);
void SetGeom(Nz::Collider2DRef geom);
void SetGeomOffset(const Nz::Vector2f& geomOffset);
CollisionComponent2D& operator=(Nz::Collider2DRef geom);
CollisionComponent2D& operator=(CollisionComponent2D&& collision) = default;
@ -36,7 +45,10 @@ namespace Ndk
private:
void InitializeStaticBody();
Nz::RigidBody2D* GetRigidBody();
const Nz::RigidBody2D* GetRigidBody() const;
Nz::RigidBody2D* GetStaticBody();
const Nz::RigidBody2D* GetStaticBody() const;
void OnAttached() override;
void OnComponentAttached(BaseComponent& component) override;

View File

@ -28,16 +28,6 @@ namespace Ndk
{
}
/*!
* \brief Gets the collision box representing the entity
* \return The physics collision box
*/
inline Nz::Rectf CollisionComponent2D::GetAABB() const
{
return m_staticBody->GetAABB();
}
/*!
* \brief Gets the geometry representing the entity
* \return A constant reference to the physics geometry
@ -62,13 +52,13 @@ namespace Ndk
return *this;
}
/*!
* \brief Gets the static body used by the entity
* \return A pointer to the entity
*/
inline Nz::RigidBody2D* CollisionComponent2D::GetStaticBody()
{
return m_staticBody.get();
}
inline const Nz::RigidBody2D* CollisionComponent2D::GetStaticBody() const
{
return m_staticBody.get();
}
}

View File

@ -14,6 +14,10 @@
namespace Ndk
{
class CollisionComponent3D;
using CollisionComponent3DHandle = Nz::ObjectHandle<CollisionComponent3D>;
class NDK_API CollisionComponent3D : public Component<CollisionComponent3D>
{
friend class PhysicsSystem3D;

View File

@ -1,30 +1,47 @@
// Copyright (C) 2019 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
#pragma once
#ifndef NDK_COMPONENTS_CONSTRAINTCOMPONENT2D_HPP
#define NDK_COMPONENTS_CONSTRAINTCOMPONENT2D_HPP
#include <NDK/Component.hpp>
#include <Nazara/Physics2D/Constraint2D.hpp>
#include <Nazara/Math/Vector3.hpp>
#include <vector>
#include <NDK/Component.hpp>
#include <NDK/Entity.hpp>
#include <memory>
#include <vector>
namespace Ndk
{
class ConstraintComponent2D;
using ConstraintComponent2DHandle = Nz::ObjectHandle<ConstraintComponent2D>;
class NDK_API ConstraintComponent2D : public Component<ConstraintComponent2D>
{
public:
ConstraintComponent2D() = default;
ConstraintComponent2D(const ConstraintComponent2D& joint) = default;
ConstraintComponent2D(const ConstraintComponent2D& joint);
ConstraintComponent2D(ConstraintComponent2D&& joint) = default;
template<typename T, typename... Args> inline Nz::ObjectRef<T> CreateConstraint(const Ndk::EntityHandle& first, const Ndk::EntityHandle& second, Args&&... args);
template<typename T, typename... Args> T* CreateConstraint(const Ndk::EntityHandle& first, const Ndk::EntityHandle& second, Args&&... args);
bool RemoveConstraint(Nz::Constraint2D* constraint);
static ComponentIndex componentIndex;
private:
struct ConstraintData
{
std::unique_ptr<Nz::Constraint2D> constraint;
std::vector<Nz::Constraint2DRef> m_constraints;
NazaraSlot(Ndk::Entity, OnEntityDestruction, onBodyADestruction);
NazaraSlot(Ndk::Entity, OnEntityDestruction, onBodyBDestruction);
};
std::vector<ConstraintData> m_constraints;
};
}

View File

@ -1,3 +1,7 @@
// Copyright (C) 2019 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
#include <NDK/Components/ConstraintComponent2D.hpp>
#include <NDK/Components/PhysicsComponent2D.hpp>
#include <NDK/Components/CollisionComponent2D.hpp>
@ -5,7 +9,7 @@
namespace Ndk
{
template<typename T, typename ...Args>
Nz::ObjectRef<T> ConstraintComponent2D::CreateConstraint(const Ndk::EntityHandle& first, const Ndk::EntityHandle& second, Args && ...args)
T* ConstraintComponent2D::CreateConstraint(const Ndk::EntityHandle& first, const Ndk::EntityHandle& second, Args&& ...args)
{
auto FetchBody = [](const Ndk::EntityHandle& entity) -> Nz::RigidBody2D*
{
@ -23,9 +27,20 @@ namespace Ndk
Nz::RigidBody2D* secondBody = FetchBody(second);
NazaraAssert(secondBody, "Second entity has no CollisionComponent2D nor PhysicsComponent2D component");
Nz::ObjectRef<T> constraint = T::New(*firstBody, *secondBody, std::forward<Args>(args)...);
m_constraints.push_back(constraint);
m_constraints.emplace_back();
auto& constraintData = m_constraints.back();
constraintData.constraint = std::make_unique<T>(*firstBody, *secondBody, std::forward<Args>(args)...);
return constraint;
constraintData.onBodyADestruction.Connect(first->OnEntityDestruction, [this, constraint = constraintData.constraint.get()](const Ndk::Entity* /*entity*/)
{
RemoveConstraint(constraint);
});
constraintData.onBodyBDestruction.Connect(second->OnEntityDestruction, [this, constraint = constraintData.constraint.get()](const Ndk::Entity* /*entity*/)
{
RemoveConstraint(constraint);
});
return static_cast<T*>(constraintData.constraint.get());
}
}

View File

@ -16,7 +16,7 @@ namespace Ndk
{
enum class DebugDraw
{
//TODO: Collider2D
Collider2D,
Collider3D,
GraphicsAABB,
GraphicsOBB,
@ -40,6 +40,11 @@ namespace Ndk
constexpr DebugDrawFlags DebugDraw_None = 0;
class DebugComponent;
class GraphicsComponent;
using DebugComponentHandle = Nz::ObjectHandle<DebugComponent>;
class NDK_API DebugComponent : public Component<DebugComponent>
{
friend class DebugSystem;
@ -61,8 +66,14 @@ namespace Ndk
static ComponentIndex componentIndex;
private:
void DetachDebugRenderables(GraphicsComponent& gfxComponent);
inline const Nz::InstancedRenderableRef& GetDebugRenderable(DebugDraw option) const;
inline DebugDrawFlags GetEnabledFlags() const;
void OnComponentDetached(BaseComponent& component) override;
void OnDetached() override;
inline void UpdateDebugRenderable(DebugDraw option, Nz::InstancedRenderableRef renderable);
inline void UpdateEnabledFlags(DebugDrawFlags flags);

View File

@ -10,6 +10,7 @@
#include <Nazara/Graphics/CullingList.hpp>
#include <Nazara/Graphics/InstancedRenderable.hpp>
#include <Nazara/Math/Frustum.hpp>
#include <Nazara/Utility/Node.hpp>
#include <NDK/Component.hpp>
#include <unordered_map>
@ -21,7 +22,7 @@ namespace Ndk
using GraphicsComponentCullingList = Nz::CullingList<GraphicsComponent>;
using GraphicsComponentHandle = Nz::ObjectHandle<GraphicsComponent>;
class NDK_API GraphicsComponent : public Component<GraphicsComponent>, public Nz::HandledObject<GraphicsComponent>
class NDK_API GraphicsComponent : public Component<GraphicsComponent>
{
friend class RenderSystem;
@ -34,6 +35,7 @@ namespace Ndk
inline void AddToCullingList(GraphicsComponentCullingList* cullingList) const;
void AddToRenderQueue(Nz::AbstractRenderQueue* renderQueue) const;
void AddToRenderQueueByCulling(const Nz::Frustumf& frustum, Nz::AbstractRenderQueue* renderQueue) const;
inline void Attach(Nz::InstancedRenderableRef renderable, int renderOrder = 0);
void Attach(Nz::InstancedRenderableRef renderable, const Nz::Matrix4f& localMatrix, int renderOrder = 0);
@ -44,15 +46,19 @@ namespace Ndk
inline bool DoesRequireRealTimeReflections() const;
inline void EnsureBoundingVolumesUpdate() const;
inline void EnsureTransformMatrixUpdate() const;
template<typename Func> void ForEachRenderable(const Func& func) const;
inline void EnsureBoundingVolumeUpdate() const;
inline void EnsureTransformMatrixUpdate() const;
inline const Nz::Boxf& GetAABB() const;
inline void GetAttachedRenderables(RenderableList* renderables) const;
inline std::size_t GetAttachedRenderableCount() const;
inline const Nz::BoundingVolumef& GetBoundingVolume() const;
inline const Nz::BoundingVolumef& GetBoundingVolume(std::size_t renderableIndex) const;
inline const Nz::Matrix4f& GetLocalMatrix(std::size_t renderableIndex) const;
inline const Nz::Matrix4f& GetTransformMatrix(std::size_t renderableIndex) const;
inline void RemoveFromCullingList(GraphicsComponentCullingList* cullingList) const;
@ -68,7 +74,8 @@ namespace Ndk
void ConnectInstancedRenderableSignals(Renderable& renderable);
inline void InvalidateBoundingVolume() const;
inline void ForceCullingInvalidation();
inline void InvalidateAABB() const;
void InvalidateRenderableData(const Nz::InstancedRenderable* renderable, Nz::UInt32 flags, std::size_t index);
void InvalidateRenderableMaterial(const Nz::InstancedRenderable* renderable, std::size_t skinIndex, std::size_t matIndex, const Nz::MaterialRef& newMat);
inline void InvalidateRenderables();
@ -89,11 +96,20 @@ namespace Ndk
void UnregisterMaterial(Nz::Material* material);
void UpdateBoundingVolume() const;
void UpdateBoundingVolumes() const;
void UpdateTransformMatrix() const;
NazaraSlot(Nz::Node, OnNodeInvalidation, m_nodeInvalidationSlot);
using CullingListBoxEntry = GraphicsComponentCullingList::BoxEntry;
struct CullingBoxEntry
{
CullingListBoxEntry listEntry;
NazaraSlot(GraphicsComponentCullingList, OnCullingListRelease, cullingListReleaseSlot);
};
struct MaterialEntry
{
NazaraSlot(Nz::Material, OnMaterialReflectionModeChange, reflectionModelChangeSlot);
@ -128,29 +144,21 @@ namespace Ndk
NazaraSlot(Nz::InstancedRenderable, OnInstancedRenderableResetMaterials, renderableResetMaterialsSlot);
NazaraSlot(Nz::InstancedRenderable, OnInstancedRenderableSkinChange, renderableSkinChangeSlot);
mutable Nz::BoundingVolumef boundingVolume;
mutable Nz::InstancedRenderable::InstanceData data;
Nz::InstancedRenderableRef renderable;
mutable bool dataUpdated;
};
using VolumeCullingListEntry = GraphicsComponentCullingList::VolumeEntry;
struct VolumeCullingEntry
{
VolumeCullingListEntry listEntry;
NazaraSlot(GraphicsComponentCullingList, OnCullingListRelease, cullingListReleaseSlot);
};
std::size_t m_reflectiveMaterialCount;
mutable std::vector<VolumeCullingEntry> m_volumeCullingEntries;
mutable std::vector<CullingBoxEntry> m_cullingBoxEntries;
std::vector<Renderable> m_renderables;
std::unordered_map<const Nz::Material*, MaterialEntry> m_materialEntries;
mutable Nz::BoundingVolumef m_boundingVolume;
mutable Nz::Boxf m_aabb;
mutable Nz::Matrix4f m_transformMatrix;
Nz::Recti m_scissorRect;
Nz::TextureRef m_reflectionMap;
mutable bool m_boundingVolumeUpdated;
mutable bool m_boundingVolumesUpdated;
mutable bool m_transformMatrixUpdated;
unsigned int m_reflectionMapSize;
};

View File

@ -22,11 +22,11 @@ namespace Ndk
*/
inline GraphicsComponent::GraphicsComponent(const GraphicsComponent& graphicsComponent) :
Component(graphicsComponent),
HandledObject(graphicsComponent),
m_reflectiveMaterialCount(0),
m_boundingVolume(graphicsComponent.m_boundingVolume),
m_aabb(graphicsComponent.m_aabb),
m_transformMatrix(graphicsComponent.m_transformMatrix),
m_boundingVolumeUpdated(graphicsComponent.m_boundingVolumeUpdated),
m_scissorRect(graphicsComponent.m_scissorRect),
m_boundingVolumesUpdated(graphicsComponent.m_boundingVolumesUpdated),
m_transformMatrixUpdated(graphicsComponent.m_transformMatrixUpdated)
{
m_renderables.reserve(graphicsComponent.m_renderables.size());
@ -36,12 +36,12 @@ namespace Ndk
inline void GraphicsComponent::AddToCullingList(GraphicsComponentCullingList* cullingList) const
{
m_volumeCullingEntries.emplace_back(VolumeCullingEntry{});
VolumeCullingEntry& entry = m_volumeCullingEntries.back();
m_cullingBoxEntries.emplace_back();
CullingBoxEntry& entry = m_cullingBoxEntries.back();
entry.cullingListReleaseSlot.Connect(cullingList->OnCullingListRelease, this, &GraphicsComponent::RemoveFromCullingList);
entry.listEntry = cullingList->RegisterVolumeTest(this);
entry.listEntry = cullingList->RegisterBoxTest(this);
InvalidateBoundingVolume();
InvalidateAABB();
}
/*!
@ -70,7 +70,7 @@ namespace Ndk
InvalidateReflectionMap();
}
InvalidateBoundingVolume();
InvalidateAABB();
}
/*!
@ -85,13 +85,15 @@ namespace Ndk
{
if (it->renderable == renderable)
{
InvalidateBoundingVolume();
InvalidateAABB();
std::size_t materialCount = renderable->GetMaterialCount();
for (std::size_t i = 0; i < materialCount; ++i)
UnregisterMaterial(renderable->GetMaterial(i));
m_renderables.erase(it);
ForceCullingInvalidation();
break;
}
}
@ -109,26 +111,14 @@ namespace Ndk
return m_reflectiveMaterialCount != 0 && m_reflectionMap;
}
/*!
* \brief Calls a function for every renderable attached to this component
*
* \param func Callback function which will be called with renderable data
*/
template<typename Func>
void GraphicsComponent::ForEachRenderable(const Func& func) const
{
for (const auto& renderableData : m_renderables)
func(renderableData.renderable, renderableData.data.localMatrix, renderableData.data.renderOrder);
}
/*!
* \brief Ensures the bounding volume is up to date
*/
inline void GraphicsComponent::EnsureBoundingVolumeUpdate() const
inline void GraphicsComponent::EnsureBoundingVolumesUpdate() const
{
if (!m_boundingVolumeUpdated)
UpdateBoundingVolume();
if (!m_boundingVolumesUpdated)
UpdateBoundingVolumes();
}
/*!
@ -141,6 +131,17 @@ namespace Ndk
UpdateTransformMatrix();
}
/*!
* \brief Gets the axis-aligned bounding box of the entity
* \return A constant reference to the AABB
*/
inline const Nz::Boxf& GraphicsComponent::GetAABB() const
{
EnsureBoundingVolumesUpdate();
return m_aabb;
}
/*!
* \brief Gets the set of renderable elements
*
@ -168,28 +169,50 @@ namespace Ndk
return m_renderables.size();
}
/*!
* \brief Gets the bouding volume of the entity
* \return A constant reference to the bounding volume
*/
inline const Nz::BoundingVolumef& GraphicsComponent::GetBoundingVolume() const
inline const Nz::BoundingVolumef& GraphicsComponent::GetBoundingVolume(std::size_t renderableIndex) const
{
EnsureBoundingVolumeUpdate();
EnsureBoundingVolumesUpdate();
return m_boundingVolume;
assert(renderableIndex < m_renderables.size());
return m_renderables[renderableIndex].boundingVolume;
}
inline const Nz::Matrix4f& GraphicsComponent::GetLocalMatrix(std::size_t renderableIndex) const
{
assert(renderableIndex < m_renderables.size());
return m_renderables[renderableIndex].data.localMatrix;
}
inline const Nz::Matrix4f& GraphicsComponent::GetTransformMatrix(std::size_t renderableIndex) const
{
EnsureBoundingVolumesUpdate();
assert(renderableIndex < m_renderables.size());
return m_renderables[renderableIndex].data.transformMatrix;
}
/*!
* \brief Calls a function for every renderable attached to this component
*
* \param func Callback function which will be called with renderable data
*/
template<typename Func>
void GraphicsComponent::ForEachRenderable(const Func& func) const
{
for (const auto& renderableData : m_renderables)
func(renderableData.renderable, renderableData.data.localMatrix, renderableData.data.renderOrder);
}
inline void GraphicsComponent::RemoveFromCullingList(GraphicsComponentCullingList* cullingList) const
{
for (auto it = m_volumeCullingEntries.begin(); it != m_volumeCullingEntries.end(); ++it)
for (auto it = m_cullingBoxEntries.begin(); it != m_cullingBoxEntries.end(); ++it)
{
if (it->listEntry.GetParent() == cullingList)
{
if (m_volumeCullingEntries.size() > 1)
*it = std::move(m_volumeCullingEntries.back());
if (m_cullingBoxEntries.size() > 1)
*it = std::move(m_cullingBoxEntries.back());
m_volumeCullingEntries.pop_back();
m_cullingBoxEntries.pop_back();
break;
}
}
@ -199,7 +222,7 @@ namespace Ndk
{
m_scissorRect = scissorRect;
for (VolumeCullingEntry& entry : m_volumeCullingEntries)
for (CullingBoxEntry& entry : m_cullingBoxEntries)
entry.listEntry.ForceInvalidation(); //< Invalidate render queues
}
@ -211,7 +234,7 @@ namespace Ndk
{
renderable.data.localMatrix = localMatrix;
InvalidateBoundingVolume();
InvalidateAABB();
break;
}
}
@ -233,9 +256,15 @@ namespace Ndk
* \brief Invalidates the bounding volume
*/
inline void GraphicsComponent::InvalidateBoundingVolume() const
inline void GraphicsComponent::ForceCullingInvalidation()
{
m_boundingVolumeUpdated = false;
for (CullingBoxEntry& entry : m_cullingBoxEntries)
entry.listEntry.ForceInvalidation(); //< Invalidate render queues
}
inline void GraphicsComponent::InvalidateAABB() const
{
m_boundingVolumesUpdated = false;
}
/*!
@ -256,7 +285,7 @@ namespace Ndk
{
m_transformMatrixUpdated = false;
InvalidateBoundingVolume();
InvalidateAABB();
InvalidateRenderables();
}
}

View File

@ -0,0 +1,40 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
#pragma once
#ifndef NDK_COMPONENTS_LIFETIMECOMPONENT_HPP
#define NDK_COMPONENTS_LIFETIMECOMPONENT_HPP
#include <NDK/Component.hpp>
namespace Ndk
{
class LifetimeComponent;
using LifetimeComponentHandle = Nz::ObjectHandle<LifetimeComponent>;
class NDK_API LifetimeComponent : public Component<LifetimeComponent>
{
friend class LifetimeSystem;
public:
inline LifetimeComponent(float lifetime);
LifetimeComponent(const LifetimeComponent&) = default;
~LifetimeComponent() = default;
inline float GetRemainingTime() const;
static ComponentIndex componentIndex;
private:
inline bool UpdateLifetime(float elapsedTime);
float m_lifetime;
};
}
#include <NDK/Components/LifetimeComponent.inl>
#endif // NDK_COMPONENTS_LIFETIMECOMPONENT_HPP

View File

@ -0,0 +1,24 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
#include <NDK/Components/LifetimeComponent.hpp>
namespace Ndk
{
inline LifetimeComponent::LifetimeComponent(float lifetime) :
m_lifetime(lifetime)
{
}
inline float Ndk::LifetimeComponent::GetRemainingTime() const
{
return m_lifetime;
}
inline bool LifetimeComponent::UpdateLifetime(float elapsedTime)
{
m_lifetime -= elapsedTime;
return m_lifetime < 0.f;
}
}

View File

@ -1,4 +1,4 @@
// Copyright (C) 2017 Jérôme Leclercq
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
@ -13,6 +13,10 @@
namespace Ndk
{
class LightComponent;
using LightComponentHandle = Nz::ObjectHandle<LightComponent>;
class NDK_API LightComponent : public Component<LightComponent>, public Nz::Light
{
public:

View File

@ -12,6 +12,10 @@
namespace Ndk
{
class ListenerComponent;
using ListenerComponentHandle = Nz::ObjectHandle<ListenerComponent>;
class NDK_API ListenerComponent : public Component<ListenerComponent>
{
public:

View File

@ -17,7 +17,7 @@ namespace Ndk
using NodeComponentHandle = Nz::ObjectHandle<NodeComponent>;
class NDK_API NodeComponent : public Component<NodeComponent>, public Nz::Node, public Nz::HandledObject<NodeComponent>
class NDK_API NodeComponent : public Component<NodeComponent>, public Nz::Node
{
public:
NodeComponent() = default;

View File

@ -13,6 +13,10 @@
namespace Ndk
{
class ParticleEmitterComponent;
using ParticleEmitterComponentHandle = Nz::ObjectHandle<ParticleEmitterComponent>;
class NDK_API ParticleEmitterComponent : public Component<ParticleEmitterComponent>, public Nz::ParticleEmitter
{
public:

View File

@ -17,7 +17,7 @@ namespace Ndk
using ParticleGroupComponentHandle = Nz::ObjectHandle<ParticleGroupComponent>;
class NDK_API ParticleGroupComponent : public Component<ParticleGroupComponent>, public Nz::ParticleGroup, public Nz::HandledObject<ParticleGroupComponent>
class NDK_API ParticleGroupComponent : public Component<ParticleGroupComponent>, public Nz::ParticleGroup
{
public:
inline ParticleGroupComponent(unsigned int maxParticleCount, Nz::ParticleLayout layout);
@ -38,4 +38,4 @@ namespace Ndk
#include <NDK/Components/ParticleGroupComponent.inl>
#endif // NDK_COMPONENTS_PARTICLEGROUPCOMPONENT_HPP
#endif // NDK_SERVER
#endif // NDK_SERVER

View File

@ -13,6 +13,10 @@
namespace Ndk
{
class PhysicsComponent2D;
using PhysicsComponent2DHandle = Nz::ObjectHandle<PhysicsComponent2D>;
class NDK_API PhysicsComponent2D : public Component<PhysicsComponent2D>
{
friend class CollisionComponent2D;
@ -20,39 +24,75 @@ namespace Ndk
friend class ConstraintComponent2D;
public:
PhysicsComponent2D() = default;
using VelocityFunc = Nz::RigidBody2D::VelocityFunc;
PhysicsComponent2D();
PhysicsComponent2D(const PhysicsComponent2D& physics);
~PhysicsComponent2D() = default;
void AddForce(const Nz::Vector2f& force, Nz::CoordSys coordSys = Nz::CoordSys_Global);
void AddForce(const Nz::Vector2f& force, const Nz::Vector2f& point, Nz::CoordSys coordSys = Nz::CoordSys_Global);
void AddImpulse(const Nz::Vector2f& impulse, Nz::CoordSys coordSys = Nz::CoordSys_Global);
void AddImpulse(const Nz::Vector2f& impulse, const Nz::Vector2f& point, Nz::CoordSys coordSys = Nz::CoordSys_Global);
void AddTorque(float torque);
inline void AddForce(const Nz::Vector2f& force, Nz::CoordSys coordSys = Nz::CoordSys_Global);
inline void AddForce(const Nz::Vector2f& force, const Nz::Vector2f& point, Nz::CoordSys coordSys = Nz::CoordSys_Global);
inline void AddImpulse(const Nz::Vector2f& impulse, Nz::CoordSys coordSys = Nz::CoordSys_Global);
inline void AddImpulse(const Nz::Vector2f& impulse, const Nz::Vector2f& point, Nz::CoordSys coordSys = Nz::CoordSys_Global);
inline void AddTorque(const Nz::RadianAnglef& torque);
bool ClosestPointQuery(const Nz::Vector2f& position, Nz::Vector2f* closestPoint, float* closestDistance) const;
inline bool ClosestPointQuery(const Nz::Vector2f& position, Nz::Vector2f* closestPoint, float* closestDistance) const;
Nz::Rectf GetAABB() const;
float GetAngularVelocity() const;
Nz::Vector2f GetCenterOfGravity(Nz::CoordSys coordSys = Nz::CoordSys_Local) const;
float GetMass() const;
Nz::Vector2f GetPosition() const;
float GetRotation() const;
Nz::Vector2f GetVelocity() const;
inline void EnableNodeSynchronization(bool nodeSynchronization);
bool IsSleeping() const;
inline void ForceSleep();
inline void ForEachArbiter(const std::function<void(Nz::Arbiter2D&)>& callback);
void SetAngularVelocity(float angularVelocity);
void SetMass(float mass);
void SetMassCenter(const Nz::Vector2f& center);
void SetPosition(const Nz::Vector2f& position);
void SetRotation(float rotation);
void SetVelocity(const Nz::Vector2f& velocity);
inline Nz::Rectf GetAABB() const;
inline float GetAngularDamping() const;
inline Nz::RadianAnglef GetAngularVelocity() const;
NAZARA_DEPRECATED("Name error, please use GetMassCenter")
inline Nz::Vector2f GetCenterOfGravity(Nz::CoordSys coordSys = Nz::CoordSys_Local) const;
inline float GetElasticity(std::size_t shapeIndex = 0) const;
inline float GetFriction(std::size_t shapeIndex = 0) const;
inline float GetMass() const;
inline Nz::Vector2f GetMassCenter(Nz::CoordSys coordSys = Nz::CoordSys_Local) const;
inline float GetMomentOfInertia() const;
inline Nz::Vector2f GetPosition() const;
inline Nz::RadianAnglef GetRotation() const;
inline Nz::Vector2f GetSurfaceVelocity(std::size_t shapeIndex = 0) const;
inline std::size_t GetShapeCount() const;
inline Nz::Vector2f GetVelocity() const;
const VelocityFunc& GetVelocityFunction() const;
inline bool IsNodeSynchronizationEnabled() const;
inline bool IsSleeping() const;
inline bool IsValid() const;
inline void ResetVelocityFunction();
inline void SetAngularDamping(float angularDamping);
inline void SetAngularVelocity(const Nz::RadianAnglef& angularVelocity);
inline void SetElasticity(float elasticity);
inline void SetElasticity(std::size_t shapeIndex, float friction);
inline void SetFriction(float friction);
inline void SetFriction(std::size_t shapeIndex, float friction);
inline void SetMass(float mass, bool recomputeMoment = true);
inline void SetMassCenter(const Nz::Vector2f& center, Nz::CoordSys coordSys = Nz::CoordSys_Local);
inline void SetMomentOfInertia(float moment);
inline void SetPosition(const Nz::Vector2f& position);
inline void SetRotation(const Nz::RadianAnglef& rotation);
inline void SetSurfaceVelocity(const Nz::Vector2f& velocity);
inline void SetSurfaceVelocity(std::size_t shapeIndex, const Nz::Vector2f& velocity);
inline void SetVelocity(const Nz::Vector2f& velocity);
inline void SetVelocityFunction(VelocityFunc velocityFunc);
inline void UpdateVelocity(const Nz::Vector2f& gravity, float damping, float deltaTime);
inline void Wakeup();
static ComponentIndex componentIndex;
private:
inline void ApplyPhysicsState(Nz::RigidBody2D& rigidBody) const;
inline void CopyPhysicsState(const Nz::RigidBody2D& rigidBody);
Nz::RigidBody2D* GetRigidBody();
const Nz::RigidBody2D* GetRigidBody() const;
void OnAttached() override;
void OnComponentAttached(BaseComponent& component) override;
@ -60,7 +100,28 @@ namespace Ndk
void OnDetached() override;
void OnEntityDestruction() override;
struct PendingPhysObjectStates
{
struct ShapeStates
{
Nz::Vector2f surfaceVelocity;
float elasticity;
float friction;
};
VelocityFunc velocityFunc;
std::vector<ShapeStates> shapes;
Nz::RadianAnglef angularVelocity;
Nz::Vector2f massCenter;
Nz::Vector2f velocity;
bool valid = false;
float mass;
float momentOfInertia;
};
std::unique_ptr<Nz::RigidBody2D> m_object;
PendingPhysObjectStates m_pendingStates;
bool m_nodeSynchronizationEnabled;
};
}

View File

@ -7,16 +7,22 @@
namespace Ndk
{
/*!
* \brief Constructs a PhysicsComponent2D object by default
*/
inline PhysicsComponent2D::PhysicsComponent2D() :
m_nodeSynchronizationEnabled(true)
{
}
/*!
* \brief Constructs a PhysicsComponent2D object by copy semantic
*
* \param physics PhysicsComponent2D to copy
*/
inline PhysicsComponent2D::PhysicsComponent2D(const PhysicsComponent2D& physics)
{
// No copy of physical object (because we only create it when attached to an entity)
NazaraUnused(physics);
CopyPhysicsState(*physics.GetRigidBody());
}
/*!
@ -91,7 +97,7 @@ namespace Ndk
* \remark Produces a NazaraAssert if the physics object is invalid
*/
inline void PhysicsComponent2D::AddTorque(float torque)
inline void PhysicsComponent2D::AddTorque(const Nz::RadianAnglef& torque)
{
NazaraAssert(m_object, "Invalid physics object");
@ -115,6 +121,41 @@ namespace Ndk
return m_object->ClosestPointQuery(position, closestPoint, closestDistance);
}
/*!
* \brief Enables position/rotation synchronization with the NodeComponent
*
* By default, at every update of the PhysicsSystem2D, the NodeComponent's position and rotation (if any) will be synchronized with
* the values of the PhysicsComponent2D. This function allows to enable/disable this behavior on a per-entity basis.
*
* \param nodeSynchronization Should synchronization occur between NodeComponent and PhysicsComponent2D
*/
inline void PhysicsComponent2D::EnableNodeSynchronization(bool nodeSynchronization)
{
m_nodeSynchronizationEnabled = nodeSynchronization;
if (m_entity)
m_entity->Invalidate();
}
/*!
TODO
*/
inline void PhysicsComponent2D::ForceSleep()
{
NazaraAssert(m_object, "Invalid physics object");
return m_object->ForceSleep();
}
/*!
TODO
*/
inline void PhysicsComponent2D::ForEachArbiter(const std::function<void(Nz::Arbiter2D&)>& callback)
{
NazaraAssert(m_object, "Invalid physics object");
return m_object->ForEachArbiter(callback);
}
/*!
* \brief Gets the AABB of the physics object
* \return AABB of the object
@ -128,6 +169,22 @@ namespace Ndk
return m_object->GetAABB();
}
/*!
* \brief Gets the angular damping or moment of inertia of the physics object
* \return Angular damping of the object
*
* \remark Produces a NazaraAssert if the physics object is invalid
*
* \see GetMomentOfInertia
*/
inline float PhysicsComponent2D::GetAngularDamping() const
{
NazaraAssert(m_object, "Invalid physics object");
return m_object->GetAngularDamping();
}
/*!
* \brief Gets the angular velocity of the physics object
* \return Angular velocity of the object
@ -135,7 +192,7 @@ namespace Ndk
* \remark Produces a NazaraAssert if the physics object is invalid
*/
inline float PhysicsComponent2D::GetAngularVelocity() const
inline Nz::RadianAnglef PhysicsComponent2D::GetAngularVelocity() const
{
NazaraAssert(m_object, "Invalid physics object");
@ -155,7 +212,37 @@ namespace Ndk
{
NazaraAssert(m_object, "Invalid physics object");
return m_object->GetCenterOfGravity(coordSys);
return m_object->GetMassCenter(coordSys);
}
/*!
* \brief Gets the elasticity of a shape belonging to this physics object
* \return Elasticity of the shape
*
* \param shapeIndex Shape index of the collider we're interested
*
* \remark Produces a NazaraAssert if the physics object is invalid
*/
inline float PhysicsComponent2D::GetElasticity(std::size_t shapeIndex) const
{
NazaraAssert(m_object, "Invalid physics object");
return m_object->GetElasticity(shapeIndex);
}
/*!
* \brief Gets the friction of a shape belonging to this physics object
* \return Friction of the shape
*
* \param shapeIndex Shape index of the collider we're interested
*
* \remark Produces a NazaraAssert if the physics object is invalid
*/
inline float PhysicsComponent2D::GetFriction(std::size_t shapeIndex) const
{
NazaraAssert(m_object, "Invalid physics object");
return m_object->GetFriction(shapeIndex);
}
/*!
@ -164,7 +251,6 @@ namespace Ndk
*
* \remark Produces a NazaraAssert if the physics object is invalid
*/
inline float PhysicsComponent2D::GetMass() const
{
NazaraAssert(m_object, "Invalid physics object");
@ -172,6 +258,38 @@ namespace Ndk
return m_object->GetMass();
}
/*!
* \brief Gets the gravity center of the physics object
* \return Gravity center of the object
*
* \param coordSys System coordinates to consider
*
* \remark Produces a NazaraAssert if the physics object is invalid
*/
inline Nz::Vector2f PhysicsComponent2D::GetMassCenter(Nz::CoordSys coordSys) const
{
NazaraAssert(m_object, "Invalid physics object");
return m_object->GetMassCenter(coordSys);
}
/*!
* \brief Gets the angular damping or moment of inertia of the physics object
* \return Moment of inertia of the object
*
* \remark Produces a NazaraAssert if the physics object is invalid
*
* \see GetAngularDamping
*/
inline float PhysicsComponent2D::GetMomentOfInertia() const
{
NazaraAssert(m_object, "Invalid physics object");
return m_object->GetMomentOfInertia();
}
/*!
* \brief Gets the position of the physics object
* \return Position of the object
@ -192,21 +310,43 @@ namespace Ndk
*
* \remark Produces a NazaraAssert if the physics object is invalid
*/
inline float PhysicsComponent2D::GetRotation() const
inline Nz::RadianAnglef PhysicsComponent2D::GetRotation() const
{
NazaraAssert(m_object, "Invalid physics object");
return m_object->GetRotation();
}
/*!
* \brief Gets the surface velocity of a shape belonging to this physics object
* \return Surface velocity of the shape
*
* \param shapeIndex Shape index of the collider we're interested
*
* \remark Produces a NazaraAssert if the physics object is invalid
*/
inline Nz::Vector2f PhysicsComponent2D::GetSurfaceVelocity(std::size_t shapeIndex) const
{
return m_object->GetSurfaceVelocity(shapeIndex);
}
/*!
* \brief Gets the rotation of the physics object
* \return Shape count of the object
*
* \remark Produces a NazaraAssert if the physics object is invalid
*/
inline std::size_t PhysicsComponent2D::GetShapeCount() const
{
return m_object->GetShapeCount();
}
/*!
* \brief Gets the velocity of the physics object
* \return Velocity of the object
*
* \remark Produces a NazaraAssert if the physics object is invalid
*/
inline Nz::Vector2f PhysicsComponent2D::GetVelocity() const
{
NazaraAssert(m_object, "Invalid physics object");
@ -214,13 +354,36 @@ namespace Ndk
return m_object->GetVelocity();
}
/*!
* \brief Gets the custom velocity function of the physics object
* \return Velocity function of the object (may be empty if default function is used)
*
* \remark Produces a NazaraAssert if the physics object is invalid
*/
inline auto PhysicsComponent2D::GetVelocityFunction() const -> const VelocityFunc&
{
NazaraAssert(m_object, "Invalid physics object");
return m_object->GetVelocityFunction();
}
/*!
* \brief Checks if position & rotation are synchronized with NodeComponent
* \return true If synchronization is enabled
*
* \see EnableNodeSynchronization
*/
inline bool PhysicsComponent2D::IsNodeSynchronizationEnabled() const
{
return m_nodeSynchronizationEnabled;
}
/*!
* \brief Checks whether the entity is currently sleeping
* \return true If it is the case
*
* \remark Produces a NazaraAssert if the physics object is invalid
*/
inline bool PhysicsComponent2D::IsSleeping() const
{
NazaraAssert(m_object, "Invalid physics object");
@ -228,6 +391,47 @@ namespace Ndk
return m_object->IsSleeping();
}
/*!
* \brief Checks if this component is bound to a valid rigid body
*
* A component may not be bound to a rigid body if the component is not bound to an entity or if this entity is being destroyed
*
* \return true If bound, false otherwise
*/
inline bool PhysicsComponent2D::IsValid() const
{
return bool(m_object);
}
/*!
* \brief Reset velocity function to default one
*
* \remark Produces a NazaraAssert if the physics object is invalid
*/
inline void PhysicsComponent2D::ResetVelocityFunction()
{
NazaraAssert(m_object, "Invalid physics object");
return m_object->ResetVelocityFunction();
}
/*!
* \brief Sets the angular damping or moment of inertia of the physics object
*
* \param angularDamping Angular damping of the object
*
* \remark Produces a NazaraAssert if the physics object is invalid
*
* \see SetMomentOfInertia
*/
inline void PhysicsComponent2D::SetAngularDamping(float angularDamping)
{
NazaraAssert(m_object, "Invalid physics object");
m_object->SetAngularDamping(angularDamping);
}
/*!
* \brief Sets the angular velocity of the physics object
*
@ -235,29 +439,93 @@ namespace Ndk
*
* \remark Produces a NazaraAssert if the physics object is invalid
*/
inline void PhysicsComponent2D::SetAngularVelocity(float angularVelocity)
inline void PhysicsComponent2D::SetAngularVelocity(const Nz::RadianAnglef& angularVelocity)
{
NazaraAssert(m_object, "Invalid physics object");
m_object->SetAngularVelocity(angularVelocity);
}
/*!
* \brief Sets the elasticity of the whole physics object
*
* Overrides all shapes elasticity with a single value
*
* \param elasticity Elasticity to be applied
*
* \remark Elasticity must be positive or zero
*/
inline void PhysicsComponent2D::SetElasticity(float elasticity)
{
NazaraAssert(m_object, "Invalid physics object");
NazaraAssert(elasticity >= 0.f, "Friction must be positive");
m_object->SetElasticity(elasticity);
}
/*!
* \brief Sets the elasticity of a single shape of the physics object
*
* \param shapeIndex Target shape index
* \param elasticity Elasticity to be applied
*
* \remark Elasticity must be positive or zero
*/
inline void PhysicsComponent2D::SetElasticity(std::size_t shapeIndex, float elasticity)
{
NazaraAssert(m_object, "Invalid physics object");
NazaraAssert(elasticity >= 0.f, "Friction must be positive");
m_object->SetElasticity(shapeIndex, elasticity);
}
/*!
* \brief Sets the friction of the whole physics object
*
* Overrides all shapes friction with a single value
*
* \param friction Friction to be applied
*
* \remark Friction must be positive or zero
*/
inline void PhysicsComponent2D::SetFriction(float friction)
{
NazaraAssert(m_object, "Invalid physics object");
NazaraAssert(friction >= 0.f, "Friction must be positive");
m_object->SetFriction(friction);
}
/*!
* \brief Sets the friction of a single shape of the physics object
*
* \param shapeIndex Target shape index
* \param friction Friction to be applied
*
* \remark Friction must be positive or zero
*/
inline void PhysicsComponent2D::SetFriction(std::size_t shapeIndex, float friction)
{
NazaraAssert(m_object, "Invalid physics object");
NazaraAssert(friction >= 0.f, "Friction must be positive");
m_object->SetFriction(shapeIndex, friction);
}
/*!
* \brief Sets the mass of the physics object
*
* \param mass Mass of the object
* \param recomputeMoment Should the moment of inertia be recomputed according to the new mass
*
* \remark Produces a NazaraAssert if the physics object is invalid
* \remark Produces a NazaraAssert if the mass is negative
* \remark Mass must be positive or zero
*/
inline void PhysicsComponent2D::SetMass(float mass)
inline void PhysicsComponent2D::SetMass(float mass, bool recomputeMoment)
{
NazaraAssert(m_object, "Invalid physics object");
NazaraAssert(mass > 0.f, "Mass should be positive");
NazaraAssert(mass >= 0.f, "Mass should be positive");
m_object->SetMass(mass);
m_object->SetMass(mass, recomputeMoment);
}
/*!
@ -267,12 +535,27 @@ namespace Ndk
*
* \remark Produces a NazaraAssert if the physics object is invalid
*/
inline void PhysicsComponent2D::SetMassCenter(const Nz::Vector2f& center)
inline void PhysicsComponent2D::SetMassCenter(const Nz::Vector2f& center, Nz::CoordSys coordSys)
{
NazaraAssert(m_object, "Invalid physics object");
m_object->SetMassCenter(center);
m_object->SetMassCenter(center, coordSys);
}
/*!
* \brief Sets the angular damping or moment of inertia of the physics object
*
* \param moment Moment of inertia of the object
*
* \remark Produces a NazaraAssert if the physics object is invalid
*
* \see SetAngularDamping
*/
inline void PhysicsComponent2D::SetMomentOfInertia(float moment)
{
NazaraAssert(m_object, "Invalid physics object");
m_object->SetMomentOfInertia(moment);
}
/*!
@ -282,7 +565,6 @@ namespace Ndk
*
* \remark Produces a NazaraAssert if the physics object is invalid
*/
inline void PhysicsComponent2D::SetPosition(const Nz::Vector2f& position)
{
NazaraAssert(m_object, "Invalid physics object");
@ -297,22 +579,45 @@ namespace Ndk
*
* \remark Produces a NazaraAssert if the physics object is invalid
*/
inline void PhysicsComponent2D::SetRotation(float rotation)
inline void PhysicsComponent2D::SetRotation(const Nz::RadianAnglef& rotation)
{
NazaraAssert(m_object, "Invalid physics object");
m_object->SetRotation(rotation);
}
/*!
* \brief Sets the surface velocity of the whole physics object
*
* Overrides all shapes surface velocity with a single value
*
* \param velocity Surface velocity to be applied
*/
inline void PhysicsComponent2D::SetSurfaceVelocity(const Nz::Vector2f& velocity)
{
NazaraAssert(m_object, "Invalid physics object");
m_object->SetSurfaceVelocity(velocity);
}
/*!
* \brief Sets the surface velocity of a single shape of the physics object
*
* \param shapeIndex Target shape index
* \param velocity Surface velocity to be applied
*/
inline void PhysicsComponent2D::SetSurfaceVelocity(std::size_t shapeIndex, const Nz::Vector2f& velocity)
{
NazaraAssert(m_object, "Invalid physics object");
m_object->SetSurfaceVelocity(shapeIndex, velocity);
}
/*!
* \brief Sets the velocity of the physics object
*
* \param velocity Velocity of the object
*
* \remark Produces a NazaraAssert if the physics object is invalid
*/
inline void PhysicsComponent2D::SetVelocity(const Nz::Vector2f& velocity)
{
NazaraAssert(m_object, "Invalid physics object");
@ -320,13 +625,101 @@ namespace Ndk
m_object->SetVelocity(velocity);
}
/*!
* \brief Sets a custom velocity function for the physics object
*
* A velocity function is called (for non-kinematic and non-static objects) at every physics update to compute the new velocity of the object.
* You may call UpdateVelocity (the default velocity function) to let the physics engine compute that itself and then adjust it using GetVelocity/SetVelocity as you need.
*
* \param velocityFunc New custom velocity function
*
* \remark Passing an empty VelocityFunc has the same effect as calling ResetVelocityFunction
* \see ResetVelocityFunction
* \see UpdateVelocity
*/
inline void PhysicsComponent2D::SetVelocityFunction(VelocityFunc velocityFunc)
{
NazaraAssert(m_object, "Invalid physics object");
m_object->SetVelocityFunction(std::move(velocityFunc));
}
/*!
* \brief Calls the physics engine default velocity function
*
* \param gravity Physics system gravity
* \param damping Physics system damping (adjusted to deltaTime)
* \param deltaTime Elapsed time since last physics update
*/
inline void PhysicsComponent2D::UpdateVelocity(const Nz::Vector2f& gravity, float damping, float deltaTime)
{
NazaraAssert(m_object, "Invalid physics object");
m_object->UpdateVelocity(gravity, damping, deltaTime);
}
/*!
TODO
*/
inline void PhysicsComponent2D::Wakeup()
{
NazaraAssert(m_object, "Invalid physics object");
return m_object->Wakeup();
}
inline void PhysicsComponent2D::ApplyPhysicsState(Nz::RigidBody2D& rigidBody) const
{
assert(m_pendingStates.valid);
rigidBody.SetAngularVelocity(m_pendingStates.angularVelocity);
rigidBody.SetMass(m_pendingStates.mass);
rigidBody.SetMassCenter(m_pendingStates.massCenter);
rigidBody.SetMomentOfInertia(m_pendingStates.momentOfInertia);
rigidBody.SetVelocity(m_pendingStates.velocity);
rigidBody.SetVelocityFunction(m_pendingStates.velocityFunc);
for (std::size_t i = 0; i < m_pendingStates.shapes.size(); ++i)
{
auto& shapeData = m_pendingStates.shapes[i];
rigidBody.SetElasticity(i, shapeData.elasticity);
rigidBody.SetFriction(i, shapeData.friction);
rigidBody.SetSurfaceVelocity(i, shapeData.surfaceVelocity);
}
}
inline void PhysicsComponent2D::CopyPhysicsState(const Nz::RigidBody2D& rigidBody)
{
m_pendingStates.valid = true;
m_pendingStates.angularVelocity = rigidBody.GetAngularVelocity();
m_pendingStates.mass = rigidBody.GetMass();
m_pendingStates.massCenter = rigidBody.GetMassCenter();
m_pendingStates.momentOfInertia = rigidBody.GetMomentOfInertia();
m_pendingStates.velocity = rigidBody.GetVelocity();
m_pendingStates.velocityFunc = rigidBody.GetVelocityFunction();
m_pendingStates.shapes.resize(rigidBody.GetShapeCount());
for (std::size_t i = 0; i < m_pendingStates.shapes.size(); ++i)
{
auto& shapeData = m_pendingStates.shapes[i];
shapeData.elasticity = rigidBody.GetElasticity(i);
shapeData.friction = rigidBody.GetFriction(i);
shapeData.surfaceVelocity = rigidBody.GetSurfaceVelocity(i);
}
}
/*!
* \brief Gets the underlying physics object
* \return A reference to the physics object
*/
inline Nz::RigidBody2D* PhysicsComponent2D::GetRigidBody()
{
return m_object.get();
}
inline const Nz::RigidBody2D* PhysicsComponent2D::GetRigidBody() const
{
return m_object.get();
}
}

View File

@ -13,6 +13,10 @@
namespace Ndk
{
class PhysicsComponent3D;
using PhysicsComponent3DHandle = Nz::ObjectHandle<PhysicsComponent3D>;
class NDK_API PhysicsComponent3D : public Component<PhysicsComponent3D>
{
friend class CollisionComponent3D;
@ -23,49 +27,49 @@ namespace Ndk
PhysicsComponent3D(const PhysicsComponent3D& physics);
~PhysicsComponent3D() = default;
void AddForce(const Nz::Vector3f& force, Nz::CoordSys coordSys = Nz::CoordSys_Global);
void AddForce(const Nz::Vector3f& force, const Nz::Vector3f& point, Nz::CoordSys coordSys = Nz::CoordSys_Global);
void AddTorque(const Nz::Vector3f& torque, Nz::CoordSys coordSys = Nz::CoordSys_Global);
inline void AddForce(const Nz::Vector3f& force, Nz::CoordSys coordSys = Nz::CoordSys_Global);
inline void AddForce(const Nz::Vector3f& force, const Nz::Vector3f& point, Nz::CoordSys coordSys = Nz::CoordSys_Global);
inline void AddTorque(const Nz::Vector3f& torque, Nz::CoordSys coordSys = Nz::CoordSys_Global);
void EnableAutoSleep(bool autoSleep);
void EnableNodeSynchronization(bool nodeSynchronization);
inline void EnableAutoSleep(bool autoSleep);
inline void EnableNodeSynchronization(bool nodeSynchronization);
Nz::Boxf GetAABB() const;
Nz::Vector3f GetAngularDamping() const;
Nz::Vector3f GetAngularVelocity() const;
float GetGravityFactor() const;
float GetLinearDamping() const;
Nz::Vector3f GetLinearVelocity() const;
float GetMass() const;
Nz::Vector3f GetMassCenter(Nz::CoordSys coordSys = Nz::CoordSys_Local) const;
const Nz::Matrix4f& GetMatrix() const;
Nz::Vector3f GetPosition() const;
Nz::Quaternionf GetRotation() const;
inline Nz::Boxf GetAABB() const;
inline Nz::Vector3f GetAngularDamping() const;
inline Nz::Vector3f GetAngularVelocity() const;
inline float GetGravityFactor() const;
inline float GetLinearDamping() const;
inline Nz::Vector3f GetLinearVelocity() const;
inline float GetMass() const;
inline Nz::Vector3f GetMassCenter(Nz::CoordSys coordSys = Nz::CoordSys_Local) const;
inline const Nz::Matrix4f& GetMatrix() const;
inline Nz::Vector3f GetPosition() const;
inline Nz::Quaternionf GetRotation() const;
bool IsAutoSleepEnabled() const;
bool IsMoveable() const;
bool IsNodeSynchronizationEnabled() const;
bool IsSleeping() const;
inline bool IsAutoSleepEnabled() const;
inline bool IsMoveable() const;
inline bool IsNodeSynchronizationEnabled() const;
inline bool IsSleeping() const;
void SetAngularDamping(const Nz::Vector3f& angularDamping);
void SetAngularVelocity(const Nz::Vector3f& angularVelocity);
void SetGravityFactor(float gravityFactor);
void SetLinearDamping(float damping);
void SetLinearVelocity(const Nz::Vector3f& velocity);
void SetMass(float mass);
void SetMassCenter(const Nz::Vector3f& center);
void SetMaterial(const Nz::String& materialName);
void SetMaterial(int materialIndex);
void SetPosition(const Nz::Vector3f& position);
void SetRotation(const Nz::Quaternionf& rotation);
inline void SetAngularDamping(const Nz::Vector3f& angularDamping);
inline void SetAngularVelocity(const Nz::Vector3f& angularVelocity);
inline void SetGravityFactor(float gravityFactor);
inline void SetLinearDamping(float damping);
inline void SetLinearVelocity(const Nz::Vector3f& velocity);
inline void SetMass(float mass);
inline void SetMassCenter(const Nz::Vector3f& center);
inline void SetMaterial(const Nz::String& materialName);
inline void SetMaterial(int materialIndex);
inline void SetPosition(const Nz::Vector3f& position);
inline void SetRotation(const Nz::Quaternionf& rotation);
static ComponentIndex componentIndex;
private:
void ApplyPhysicsState(Nz::RigidBody3D& rigidBody) const;
void CopyPhysicsState(const Nz::RigidBody3D& rigidBody);
Nz::RigidBody3D* GetRigidBody();
const Nz::RigidBody3D& GetRigidBody() const;
inline void ApplyPhysicsState(Nz::RigidBody3D& rigidBody) const;
inline void CopyPhysicsState(const Nz::RigidBody3D& rigidBody);
inline Nz::RigidBody3D* GetRigidBody();
inline const Nz::RigidBody3D& GetRigidBody() const;
void OnAttached() override;
void OnComponentAttached(BaseComponent& component) override;

View File

@ -16,13 +16,14 @@ namespace Ndk
using VelocityComponentHandle = Nz::ObjectHandle<VelocityComponent>;
class NDK_API VelocityComponent : public Component<VelocityComponent>, public Nz::HandledObject<VelocityComponent>
class NDK_API VelocityComponent : public Component<VelocityComponent>
{
public:
VelocityComponent(const Nz::Vector3f& velocity = Nz::Vector3f::Zero());
VelocityComponent(const Nz::Vector3f& velocity = Nz::Vector3f::Zero(), Nz::CoordSys coordSystem = Nz::CoordSys_Global);
~VelocityComponent() = default;
Nz::Vector3f linearVelocity;
Nz::CoordSys coordSys;
VelocityComponent& operator=(const Nz::Vector3f& vel);

View File

@ -16,8 +16,9 @@ namespace Ndk
* \param velocity Linear velocity
*/
inline VelocityComponent::VelocityComponent(const Nz::Vector3f& velocity) :
linearVelocity(velocity)
inline VelocityComponent::VelocityComponent(const Nz::Vector3f& velocity, Nz::CoordSys coordSystem) :
linearVelocity(velocity),
coordSys(coordSystem)
{
}

View File

@ -14,24 +14,29 @@
#include <Nazara/Graphics/TextSprite.hpp>
#include <Nazara/Utility/Node.hpp>
#include <Nazara/Utility/SimpleTextDrawer.hpp>
#include <NDK/BaseWidget.hpp>
#include <NDK/EntityOwner.hpp>
namespace Nz
{
class LuaState;
struct WindowEvent;
}
namespace Ndk
{
class AbstractTextAreaWidget;
class Console;
class Entity;
class RichTextAreaWidget;
class ScrollAreaWidget;
class TextAreaWidget;
using ConsoleHandle = Nz::ObjectHandle<Console>;
class NDK_API Console : public Nz::Node, public Nz::HandledObject<Console>
class NDK_API Console : public BaseWidget, public Nz::HandledObject<Console>
{
public:
Console(World& world, const Nz::Vector2f& size, Nz::LuaState& state);
Console(BaseWidget* parent);
Console(const Console& console) = delete;
Console(Console&& console) = default;
~Console() = default;
@ -39,34 +44,25 @@ namespace Ndk
void AddLine(const Nz::String& text, const Nz::Color& color = Nz::Color::White);
void Clear();
void ClearFocus();
inline unsigned int GetCharacterSize() const;
inline const EntityHandle& GetHistory() const;
inline const EntityHandle& GetHistoryBackground() const;
inline const EntityHandle& GetInput() const;
inline const EntityHandle& GetInputBackground() const;
inline const Nz::Vector2f& GetSize() const;
inline const RichTextAreaWidget* GetHistory() const;
inline const TextAreaWidget* GetInput() const;
inline const Nz::FontRef& GetTextFont() const;
inline bool IsVisible() const;
void SendCharacter(char32_t character);
void SendEvent(const Nz::WindowEvent& event);
void SetCharacterSize(unsigned int size);
void SetSize(const Nz::Vector2f& size);
void SetFocus();
void SetTextFont(Nz::FontRef font);
void Show(bool show = true);
Console& operator=(const Console& console) = delete;
Console& operator=(Console&& console) = default;
NazaraSignal(OnCommand, Console* /*console*/, const Nz::String& /*command*/);
private:
void AddLineInternal(const Nz::String& text, const Nz::Color& color = Nz::Color::White);
void ExecuteInput();
void Layout();
void RefreshHistory();
void ExecuteInput(const AbstractTextAreaWidget* textArea, bool* ignoreDefaultAction);
void Layout() override;
struct Line
{
@ -77,20 +73,10 @@ namespace Ndk
std::size_t m_historyPosition;
std::vector<Nz::String> m_commandHistory;
std::vector<Line> m_historyLines;
EntityOwner m_historyBackground;
EntityOwner m_history;
EntityOwner m_input;
EntityOwner m_inputBackground;
ScrollAreaWidget* m_historyArea;
RichTextAreaWidget* m_history;
TextAreaWidget* m_input;
Nz::FontRef m_defaultFont;
Nz::LuaState& m_state;
Nz::SpriteRef m_historyBackgroundSprite;
Nz::SpriteRef m_inputBackgroundSprite;
Nz::SimpleTextDrawer m_historyDrawer;
Nz::SimpleTextDrawer m_inputDrawer;
Nz::TextSpriteRef m_historyTextSprite;
Nz::TextSpriteRef m_inputTextSprite;
Nz::Vector2f m_size;
bool m_opened;
unsigned int m_characterSize;
unsigned int m_maxHistoryLines;
};

View File

@ -19,51 +19,21 @@ namespace Ndk
* \return History of the console
*/
inline const EntityHandle& Console::GetHistory() const
inline const RichTextAreaWidget* Console::GetHistory() const
{
return m_history;
}
/*!
* \brief Gets the entity representing the background of the console's history
* \return Background history of the console
*/
inline const EntityHandle& Console::GetHistoryBackground() const
{
return m_historyBackground;
}
/*!
* \brief Gets the entity representing the input of the console
* \return Input of the console
*/
inline const EntityHandle& Console::GetInput() const
inline const TextAreaWidget* Console::GetInput() const
{
return m_input;
}
/*!
* \brief Gets the entity representing the background of the console's input
* \return Background input of the console
*/
inline const EntityHandle& Console::GetInputBackground() const
{
return m_inputBackground;
}
/*!
* \brief Gets the size of the console
* \return Size (Width, Height) of the console
*/
inline const Nz::Vector2f& Console::GetSize() const
{
return m_size;
}
/*!
* \brief Gets the font used by the console
* \return A reference to the font currenty used
@ -73,14 +43,4 @@ namespace Ndk
{
return m_defaultFont;
}
/*!
* \brief Checks whether the console is visible
* \return true If it is the case
*/
inline bool Console::IsVisible() const
{
return m_opened;
}
}

View File

@ -8,8 +8,8 @@
#define NDK_ENTITY_HPP
#include <Nazara/Core/Bitset.hpp>
#include <Nazara/Core/HandledObject.hpp>
#include <Nazara/Core/MovablePtr.hpp>
#include <Nazara/Core/ObjectHandle.hpp>
#include <Nazara/Core/Signal.hpp>
#include <NDK/Algorithm.hpp>
#include <NDK/Prerequisites.hpp>
@ -43,6 +43,10 @@ namespace Ndk
const EntityHandle& Clone() const;
inline void Disable();
std::unique_ptr<BaseComponent> DropComponent(ComponentIndex index);
template<typename ComponentType> std::unique_ptr<BaseComponent> DropComponent();
void Enable(bool enable = true);
inline BaseComponent& GetComponent(ComponentIndex index);
@ -61,6 +65,7 @@ namespace Ndk
void Invalidate();
inline bool IsEnabled() const;
bool IsDying() const;
inline bool IsValid() const;
inline void RemoveAllComponents();
@ -73,6 +78,8 @@ namespace Ndk
Entity& operator=(Entity&&) = delete;
NazaraSignal(OnEntityDestruction, Entity* /*entity*/);
NazaraSignal(OnEntityDisabled, Entity* /*entity*/);
NazaraSignal(OnEntityEnabled, Entity* /*entity*/);
private:
Entity(World* world, EntityId id);
@ -80,8 +87,6 @@ namespace Ndk
void Create();
void Destroy();
void DestroyComponent(ComponentIndex index);
inline Nz::Bitset<>& GetRemovedComponentBits();
inline void RegisterEntityList(EntityList* list);

View File

@ -64,6 +64,15 @@ namespace Ndk
* \remark Produces a NazaraAssert if component is not available in this entity
*/
template<typename ComponentType>
std::unique_ptr<BaseComponent> Entity::DropComponent()
{
static_assert(std::is_base_of<BaseComponent, ComponentType>::value, "ComponentType is not a component");
ComponentIndex index = GetComponentIndex<ComponentType>();
return DropComponent(index);
}
template<typename ComponentType>
ComponentType& Entity::GetComponent()
{

View File

@ -15,11 +15,12 @@ namespace Ndk
{
public:
EntityOwner() = default;
explicit EntityOwner(Entity* entity);
EntityOwner(Entity* entity);
EntityOwner(const EntityOwner& handle) = delete;
EntityOwner(EntityOwner&& handle) noexcept = default;
~EntityOwner();
void Release();
void Reset(Entity* entity = nullptr);
void Reset(EntityOwner&& handle);

View File

@ -2,6 +2,7 @@
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
#include <NDK/EntityOwner.hpp>
#include <Nazara/Core/StringStream.hpp>
#include <functional>
#include <limits>
@ -36,16 +37,23 @@ namespace Ndk
Reset(nullptr);
}
/*!
* \brief Release the ownership of the entity without killing it
*/
inline void EntityOwner::Release()
{
EntityHandle::Reset(nullptr);
}
/*!
* \brief Resets the ownership of the entity, previous is killed
*
* \param entity Entity to own
*/
inline void EntityOwner::Reset(Entity* entity)
{
if (m_object)
m_object->Kill();
if (IsValid())
GetObject()->Kill();
EntityHandle::Reset(entity);
}
@ -55,11 +63,10 @@ namespace Ndk
*
* \param handle EntityOwner to move into this
*/
inline void EntityOwner::Reset(EntityOwner&& handle)
{
Reset(handle.GetObject());
handle.m_object = nullptr;
handle.Release();
}
/*!

View File

@ -125,14 +125,14 @@ namespace Nz
state.Pop();
}
mat->Set(values);
*mat = Matrix4d(values);
return 1;
}
default:
{
if (state.IsOfType(index, "Matrix4"))
mat->Set(*static_cast<Matrix4d*>(state.ToUserdata(index)));
*mat = *static_cast<Matrix4d*>(state.ToUserdata(index));
return 1;
}
@ -269,6 +269,15 @@ namespace Nz
return ret;
}
inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Vector2i* vec, TypeTag<Vector2i>)
{
Vector2d vecDouble;
unsigned int ret = LuaImplQueryArg(state, index, &vecDouble, TypeTag<Vector2d>());
vec->Set(vecDouble);
return ret;
}
inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Vector3d* vec, TypeTag<Vector3d>)
{
switch (state.GetType(index))
@ -308,6 +317,15 @@ namespace Nz
return ret;
}
inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Vector3i* vec, TypeTag<Vector3i>)
{
Vector3d vecDouble;
unsigned int ret = LuaImplQueryArg(state, index, &vecDouble, TypeTag<Vector3d>());
vec->Set(vecDouble);
return ret;
}
inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Ndk::Entity** handle, TypeTag<Ndk::Entity*>)
{
if (!state.IsOfType(index, LuaType_Nil))
@ -384,7 +402,7 @@ namespace Nz
return 1;
}
inline unsigned int LuaImplQueryArg(const LuaState& state, int index, MusicParams* params, TypeTag<MusicParams>)
inline unsigned int LuaImplQueryArg(const LuaState& state, int index, SoundBufferParams* params, TypeTag<SoundBufferParams>)
{
state.CheckType(index, Nz::LuaType_Table);
@ -393,7 +411,7 @@ namespace Nz
return 1;
}
inline unsigned int LuaImplQueryArg(const LuaState& state, int index, SoundBufferParams* params, TypeTag<SoundBufferParams>)
inline unsigned int LuaImplQueryArg(const LuaState& state, int index, SoundStreamParams* params, TypeTag<SoundStreamParams>)
{
state.CheckType(index, Nz::LuaType_Table);
@ -538,6 +556,12 @@ namespace Nz
return 1;
}
inline int LuaImplReplyVal(const LuaState& state, Vector2i&& val, TypeTag<Vector2i>)
{
state.PushInstance<Vector2d>("Vector2", val);
return 1;
}
inline int LuaImplReplyVal(const LuaState& state, Vector3d&& val, TypeTag<Vector3d>)
{
state.PushInstance<Vector3d>("Vector3", val);
@ -556,6 +580,12 @@ namespace Nz
return 1;
}
inline int LuaImplReplyVal(const LuaState& state, Vector3i&& val, TypeTag<Vector3i>)
{
state.PushInstance<Vector3d>("Vector3", val);
return 1;
}
inline int LuaImplReplyVal(const LuaState& state, Ndk::Entity* ptr, TypeTag<Ndk::Entity*>)
{
state.PushInstance<Ndk::EntityHandle>("Entity", ptr);
@ -605,12 +635,24 @@ namespace Nz
return 1;
}
inline int LuaImplReplyVal(const LuaState& state, ModelRef&& handle, TypeTag<ModelRef>)
{
state.PushInstance<ModelRef>("Model", handle);
return 1;
}
inline int LuaImplReplyVal(const LuaState& state, const SoundBuffer* val, TypeTag<const SoundBuffer*>)
{
state.PushInstance<SoundBufferConstRef>("SoundBuffer", val);
return 1;
}
inline int LuaImplReplyVal(const LuaState& state, SoundBufferRef&& handle, TypeTag<SoundBufferRef>)
{
state.PushInstance<SoundBufferRef>("SoundBuffer", handle);
return 1;
}
inline int LuaImplReplyVal(const LuaState& state, SpriteRef&& handle, TypeTag<SpriteRef>)
{
state.PushInstance<SpriteRef>("Sprite", handle);

View File

@ -159,8 +159,13 @@ namespace Ndk
*/
inline bool StateMachine::Update(float elapsedTime)
{
for (StateTransition& transition : m_transitions)
// Use a classic for instead of a range-for because some state may push/pop on enter/leave, adding new transitions as we iterate
// (range-for is a problem here because it doesn't handle mutable containers)
for (std::size_t i = 0; i < m_transitions.size(); ++i)
{
StateTransition& transition = m_transitions[i];
switch (transition.type)
{
case TransitionType::Pop:

View File

@ -6,6 +6,7 @@
#define NDK_SYSTEMS_GLOBAL_HPP
#include <NDK/Systems/DebugSystem.hpp>
#include <NDK/Systems/LifetimeSystem.hpp>
#include <NDK/Systems/ListenerSystem.hpp>
#include <NDK/Systems/ParticleSystem.hpp>
#include <NDK/Systems/PhysicsSystem2D.hpp>

View File

@ -22,26 +22,33 @@ namespace Ndk
DebugSystem();
~DebugSystem() = default;
void EnableDepthBuffer(bool enable);
inline bool IsDepthBufferEnabled() const;
static SystemIndex systemIndex;
private:
Nz::InstancedRenderableRef GenerateBox(Nz::Boxf box);
Nz::InstancedRenderableRef GenerateCollision2DMesh(Entity* entity, Nz::Vector3f* offset);
Nz::InstancedRenderableRef GenerateCollision3DMesh(Entity* entity);
Nz::MaterialRef GetAABBMaterial();
Nz::MaterialRef GetCollisionMaterial();
Nz::MaterialRef GetOBBMaterial();
std::pair<Nz::IndexBufferRef, Nz::VertexBufferRef> GetBoxMesh();
Nz::MaterialRef GetCollisionMaterial();
Nz::MaterialRef GetGlobalAABBMaterial();
Nz::MaterialRef GetLocalAABBMaterial();
Nz::MaterialRef GetOBBMaterial();
void OnEntityValidation(Entity* entity, bool justAdded) override;
void OnUpdate(float elapsedTime) override;
Nz::MaterialRef m_aabbMaterial;
Nz::MaterialRef m_globalAabbMaterial;
Nz::MaterialRef m_localAabbMaterial;
Nz::MaterialRef m_collisionMaterial;
Nz::MaterialRef m_obbMaterial;
Nz::IndexBufferRef m_boxMeshIndexBuffer;
Nz::VertexBufferRef m_boxMeshVertexBuffer;
bool m_isDepthBufferEnabled;
};
}

View File

@ -4,3 +4,10 @@
#include <NDK/Systems/DebugSystem.hpp>
namespace Ndk
{
inline bool DebugSystem::IsDepthBufferEnabled() const
{
return m_isDepthBufferEnabled;
}
}

View File

@ -0,0 +1,29 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
#pragma once
#ifndef NDK_SYSTEMS_LIFETIMESYSTEM_HPP
#define NDK_SYSTEMS_LIFETIMESYSTEM_HPP
#include <NDK/System.hpp>
namespace Ndk
{
class NDK_API LifetimeSystem : public System<LifetimeSystem>
{
public:
LifetimeSystem();
~LifetimeSystem() = default;
static SystemIndex systemIndex;
private:
void OnUpdate(float elapsedTime) override;
};
}
#include <NDK/Systems/LifetimeSystem.inl>
#endif // NDK_SYSTEMS_LIFETIMESYSTEM_HPP

View File

@ -0,0 +1,3 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp

View File

@ -16,24 +16,114 @@ namespace Ndk
{
class NDK_API PhysicsSystem2D : public System<PhysicsSystem2D>
{
friend class CollisionComponent2D;
friend class PhysicsComponent2D;
using ContactEndCallback = std::function<void(PhysicsSystem2D& world, Nz::Arbiter2D& arbiter, const EntityHandle& bodyA, const EntityHandle& bodyB, void* userdata)>;
using ContactPreSolveCallback = std::function<bool(PhysicsSystem2D& world, Nz::Arbiter2D& arbiter, const EntityHandle& bodyA, const EntityHandle& bodyB, void* userdata)>;
using ContactPostSolveCallback = std::function<void(PhysicsSystem2D& world, Nz::Arbiter2D& arbiter, const EntityHandle& bodyA, const EntityHandle& bodyB, void* userdata)>;
using ContactStartCallback = std::function<bool(PhysicsSystem2D& world, Nz::Arbiter2D& arbiter, const EntityHandle& bodyA, const EntityHandle& bodyB, void* userdata)>;
using DebugDrawCircleCallback = std::function<void(const Nz::Vector2f& origin, const Nz::RadianAnglef& rotation, float radius, Nz::Color outlineColor, Nz::Color fillColor, void* userdata)>;
using DebugDrawDotCallback = std::function<void(const Nz::Vector2f& origin, float radius, Nz::Color color, void* userdata)>;
using DebugDrawPolygonCallback = std::function<void(const Nz::Vector2f* vertices, std::size_t vertexCount, float radius, Nz::Color outlineColor, Nz::Color fillColor, void* userdata)>;
using DebugDrawSegmentCallback = std::function<void(const Nz::Vector2f& first, const Nz::Vector2f& second, Nz::Color color, void* userdata)>;
using DebugDrawTickSegmentCallback = std::function<void(const Nz::Vector2f& first, const Nz::Vector2f& second, float thickness, Nz::Color outlineColor, Nz::Color fillColor, void* userdata)>;
using DebugDrawGetColorCallback = std::function<Nz::Color(const EntityHandle& body, std::size_t shapeIndex, void* userdata)>;
public:
struct Callback;
struct DebugDrawOptions;
struct NearestQueryResult;
struct RaycastHit;
PhysicsSystem2D();
PhysicsSystem2D(const PhysicsSystem2D& system);
~PhysicsSystem2D() = default;
Nz::PhysWorld2D& GetWorld();
const Nz::PhysWorld2D& GetWorld() const;
void DebugDraw(const DebugDrawOptions& options, bool drawShapes = true, bool drawConstraints = true, bool drawCollisions = true);
inline float GetDamping() const;
inline Nz::Vector2f GetGravity() const;
inline std::size_t GetIterationCount() const;
inline std::size_t GetMaxStepCount() const;
inline float GetStepSize() const;
bool NearestBodyQuery(const Nz::Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, EntityHandle* nearestBody = nullptr);
bool NearestBodyQuery(const Nz::Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, NearestQueryResult* result);
void RaycastQuery(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, const std::function<void(const RaycastHit&)>& callback);
bool RaycastQuery(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector<RaycastHit>* hitInfos);
bool RaycastQueryFirst(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, RaycastHit* hitInfo = nullptr);
void RegionQuery(const Nz::Rectf& boundingBox, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, const std::function<void(const EntityHandle&)>& callback);
void RegionQuery(const Nz::Rectf& boundingBox, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector<EntityHandle>* bodies);
void RegisterCallbacks(unsigned int collisionId, Callback callbacks);
void RegisterCallbacks(unsigned int collisionIdA, unsigned int collisionIdB, Callback callbacks);
inline void SetDamping(float dampingValue);
inline void SetGravity(const Nz::Vector2f& gravity);
inline void SetIterationCount(std::size_t iterationCount);
inline void SetMaxStepCount(std::size_t maxStepCount);
inline void SetSleepTime(float sleepTime);
inline void SetStepSize(float stepSize);
inline void UseSpatialHash(float cellSize, std::size_t entityCount);
struct Callback
{
ContactEndCallback endCallback = nullptr;
ContactPreSolveCallback preSolveCallback = nullptr;
ContactPostSolveCallback postSolveCallback = nullptr;
ContactStartCallback startCallback = nullptr;
void* userdata;
};
struct DebugDrawOptions
{
Nz::Color constraintColor;
Nz::Color collisionPointColor;
Nz::Color shapeOutlineColor;
DebugDrawCircleCallback circleCallback;
DebugDrawGetColorCallback colorCallback;
DebugDrawDotCallback dotCallback;
DebugDrawPolygonCallback polygonCallback;
DebugDrawSegmentCallback segmentCallback;
DebugDrawTickSegmentCallback thickSegmentCallback;
void* userdata;
};
struct NearestQueryResult
{
EntityHandle nearestBody;
Nz::Vector2f closestPoint;
Nz::Vector2f fraction;
float distance;
};
struct RaycastHit
{
EntityHandle body;
Nz::Vector2f hitPos;
Nz::Vector2f hitNormal;
float fraction;
};
static SystemIndex systemIndex;
private:
void CreatePhysWorld() const;
const EntityHandle& GetEntityFromBody(const Nz::RigidBody2D& body) const;
inline Nz::PhysWorld2D& GetPhysWorld();
inline const Nz::PhysWorld2D& GetPhysWorld() const;
void OnEntityValidation(Entity* entity, bool justAdded) override;
void OnUpdate(float elapsedTime) override;
EntityList m_dynamicObjects;
EntityList m_staticObjects;
mutable std::unique_ptr<Nz::PhysWorld2D> m_world; ///TODO: std::optional (Should I make a Nz::Optional class?)
mutable std::unique_ptr<Nz::PhysWorld2D> m_physWorld; ///TODO: std::optional (Should I make a Nz::Optional class?)
};
}

View File

@ -2,19 +2,81 @@
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
#include <NDK/Systems/PhysicsSystem2D.hpp>
namespace Ndk
{
inline float PhysicsSystem2D::GetDamping() const
{
return GetPhysWorld().GetDamping();
}
inline Nz::Vector2f PhysicsSystem2D::GetGravity() const
{
return GetPhysWorld().GetGravity();
}
inline std::size_t PhysicsSystem2D::GetIterationCount() const
{
return GetPhysWorld().GetIterationCount();
}
inline std::size_t PhysicsSystem2D::GetMaxStepCount() const
{
return GetPhysWorld().GetMaxStepCount();
}
inline float PhysicsSystem2D::GetStepSize() const
{
return GetPhysWorld().GetStepSize();
}
inline void PhysicsSystem2D::SetDamping(float dampingValue)
{
GetPhysWorld().SetDamping(dampingValue);
}
inline void PhysicsSystem2D::SetGravity(const Nz::Vector2f& gravity)
{
GetPhysWorld().SetGravity(gravity);
}
inline void PhysicsSystem2D::SetIterationCount(std::size_t iterationCount)
{
GetPhysWorld().SetIterationCount(iterationCount);
}
inline void PhysicsSystem2D::SetMaxStepCount(std::size_t maxStepCount)
{
GetPhysWorld().SetMaxStepCount(maxStepCount);
}
inline void PhysicsSystem2D::SetSleepTime(float sleepTime)
{
GetPhysWorld().SetSleepTime(sleepTime);
}
inline void PhysicsSystem2D::SetStepSize(float stepSize)
{
GetPhysWorld().SetStepSize(stepSize);
}
inline void PhysicsSystem2D::UseSpatialHash(float cellSize, std::size_t entityCount)
{
GetPhysWorld().UseSpatialHash(cellSize, entityCount);
}
/*!
* \brief Gets the physical world
* \return A reference to the physical world
*/
inline Nz::PhysWorld2D& PhysicsSystem2D::GetWorld()
inline Nz::PhysWorld2D& PhysicsSystem2D::GetPhysWorld()
{
if (!m_world)
if (!m_physWorld)
CreatePhysWorld();
return *m_world;
return *m_physWorld;
}
/*!
@ -22,11 +84,11 @@ namespace Ndk
* \return A constant reference to the physical world
*/
inline const Nz::PhysWorld2D& PhysicsSystem2D::GetWorld() const
inline const Nz::PhysWorld2D& PhysicsSystem2D::GetPhysWorld() const
{
if (!m_world)
if (!m_physWorld)
CreatePhysWorld();
return *m_world;
return *m_physWorld;
}
}

View File

@ -25,12 +25,13 @@ namespace Ndk
{
public:
RenderSystem();
inline RenderSystem(const RenderSystem& renderSystem);
~RenderSystem() = default;
template<typename T> T& ChangeRenderTechnique();
inline Nz::AbstractRenderTechnique& ChangeRenderTechnique(std::unique_ptr<Nz::AbstractRenderTechnique>&& renderTechnique);
inline void EnableCulling(bool enable);
inline const Nz::BackgroundRef& GetDefaultBackground() const;
inline const Nz::Matrix4f& GetCoordinateSystemMatrix() const;
inline Nz::Vector3f GetGlobalForward() const;
@ -38,6 +39,8 @@ namespace Ndk
inline Nz::Vector3f GetGlobalUp() const;
inline Nz::AbstractRenderTechnique& GetRenderTechnique() const;
inline bool IsCullingEnabled() const;
inline void SetDefaultBackground(Nz::BackgroundRef background);
inline void SetGlobalForward(const Nz::Vector3f& direction);
inline void SetGlobalRight(const Nz::Vector3f& direction);
@ -72,6 +75,7 @@ namespace Ndk
Nz::RenderTexture m_shadowRT;
bool m_coordinateSystemInvalidated;
bool m_forceRenderQueueInvalidation;
bool m_isCullingEnabled;
};
}

View File

@ -2,6 +2,8 @@
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
#include <NDK/Systems/RenderSystem.hpp>
namespace Ndk
{
/*!
@ -26,7 +28,24 @@ namespace Ndk
inline Nz::AbstractRenderTechnique& RenderSystem::ChangeRenderTechnique(std::unique_ptr<Nz::AbstractRenderTechnique>&& renderTechnique)
{
m_renderTechnique = std::move(renderTechnique);
return *m_renderTechnique.get();
return *m_renderTechnique;
}
/*!
* \brief Enables/disables object culling
*
* Object culling is an algorithm used by the render system to detect invisible objects (which will not appear on screen) before they are rendered.
* This includes Frustum Culling and potentially Occlusion Culling.
*
* Disabling this is not recommended, as the system will draw every object in the world which could induce a performance loss.
*
* \param enable Whether to enable or disable culling
*
* \see IsCullingEnabled
*/
inline void RenderSystem::EnableCulling(bool enable)
{
m_isCullingEnabled = enable;
}
/*!
@ -89,6 +108,17 @@ namespace Ndk
return *m_renderTechnique.get();
}
/*!
* \brief Query if culling is enabled (enabled by default)
* \return True if culling is enabled, false otherwise
*
* \see EnableCulling
*/
inline bool RenderSystem::IsCullingEnabled() const
{
return m_isCullingEnabled;
}
/*!
* \brief Sets the background used for rendering
*

View File

@ -5,12 +5,16 @@
#ifndef NDK_WIDGETS_GLOBAL_HPP
#define NDK_WIDGETS_GLOBAL_HPP
#include <NDK/Widgets/AbstractTextAreaWidget.hpp>
#include <NDK/Widgets/BoxLayout.hpp>
#include <NDK/Widgets/ButtonWidget.hpp>
#include <NDK/Widgets/CheckboxWidget.hpp>
#include <NDK/Widgets/Enums.hpp>
#include <NDK/Widgets/ImageWidget.hpp>
#include <NDK/Widgets/LabelWidget.hpp>
#include <NDK/Widgets/ProgressBarWidget.hpp>
#include <NDK/Widgets/RichTextAreaWidget.hpp>
#include <NDK/Widgets/ScrollAreaWidget.hpp>
#include <NDK/Widgets/TextAreaWidget.hpp>
#endif // NDK_WIDGETS_GLOBAL_HPP

View File

@ -0,0 +1,135 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
#pragma once
#ifndef NDK_WIDGETS_ABSTRACTTEXTAREAWIDGET_HPP
#define NDK_WIDGETS_ABSTRACTTEXTAREAWIDGET_HPP
#include <Nazara/Graphics/TextSprite.hpp>
#include <Nazara/Utility/AbstractTextDrawer.hpp>
#include <NDK/BaseWidget.hpp>
#include <NDK/Widgets/Enums.hpp>
#include <functional>
#include <vector>
namespace Ndk
{
class NDK_API AbstractTextAreaWidget : public BaseWidget
{
public:
using CharacterFilter = std::function<bool(char32_t)>;
AbstractTextAreaWidget(BaseWidget* parent);
AbstractTextAreaWidget(const AbstractTextAreaWidget&) = delete;
AbstractTextAreaWidget(AbstractTextAreaWidget&&) = default;
~AbstractTextAreaWidget() = default;
virtual void Clear();
//virtual TextAreaWidget* Clone() const = 0;
void EnableLineWrap(bool enable = true);
inline void EnableMultiline(bool enable = true);
inline void EnableTabWriting(bool enable = true);
inline void Erase(std::size_t glyphPosition);
virtual void Erase(std::size_t firstGlyph, std::size_t lastGlyph) = 0;
inline void EraseSelection();
inline const CharacterFilter& GetCharacterFilter() const;
inline const Nz::Vector2ui& GetCursorPosition() const;
inline Nz::Vector2ui GetCursorPosition(std::size_t glyphIndex) const;
inline EchoMode GetEchoMode() const;
inline std::size_t GetGlyphIndex() const;
inline std::size_t GetGlyphIndex(const Nz::Vector2ui& cursorPosition) const;
inline const Nz::String& GetText() const;
Nz::Vector2ui GetHoveredGlyph(float x, float y) const;
inline bool HasSelection() const;
inline bool IsLineWrapEnabled() const;
inline bool IsMultilineEnabled() const;
inline bool IsReadOnly() const;
inline bool IsTabWritingEnabled() const;
inline void MoveCursor(int offset);
inline void MoveCursor(const Nz::Vector2i& offset);
inline Nz::Vector2ui NormalizeCursorPosition(Nz::Vector2ui cursorPosition) const;
inline void SetCharacterFilter(CharacterFilter filter);
inline void SetCursorPosition(std::size_t glyphIndex);
inline void SetCursorPosition(Nz::Vector2ui cursorPosition);
inline void SetEchoMode(EchoMode echoMode);
inline void SetReadOnly(bool readOnly = true);
inline void SetSelection(Nz::Vector2ui fromPosition, Nz::Vector2ui toPosition);
inline void Write(const Nz::String& text);
inline void Write(const Nz::String& text, const Nz::Vector2ui& glyphPosition);
virtual void Write(const Nz::String& text, std::size_t glyphPosition) = 0;
AbstractTextAreaWidget& operator=(const AbstractTextAreaWidget&) = delete;
AbstractTextAreaWidget& operator=(AbstractTextAreaWidget&&) = default;
NazaraSignal(OnTextAreaCursorMove, const AbstractTextAreaWidget* /*textArea*/, Nz::Vector2ui* /*newCursorPosition*/);
NazaraSignal(OnTextAreaKeyBackspace, const AbstractTextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/);
NazaraSignal(OnTextAreaKeyDown, const AbstractTextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/);
NazaraSignal(OnTextAreaKeyEnd, const AbstractTextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/);
NazaraSignal(OnTextAreaKeyHome, const AbstractTextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/);
NazaraSignal(OnTextAreaKeyLeft, const AbstractTextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/);
NazaraSignal(OnTextAreaKeyReturn, const AbstractTextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/);
NazaraSignal(OnTextAreaKeyRight, const AbstractTextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/);
NazaraSignal(OnTextAreaKeyUp, const AbstractTextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/);
NazaraSignal(OnTextAreaSelection, const AbstractTextAreaWidget* /*textArea*/, Nz::Vector2ui* /*start*/, Nz::Vector2ui* /*end*/);
protected:
virtual Nz::AbstractTextDrawer& GetTextDrawer() = 0;
virtual const Nz::AbstractTextDrawer& GetTextDrawer() const = 0;
void Layout() override;
virtual void HandleIndentation(bool add) = 0;
virtual void HandleSelectionIndentation(bool add) = 0;
virtual void HandleWordCursorMove(bool left) = 0;
bool IsFocusable() const override;
void OnFocusLost() override;
void OnFocusReceived() override;
bool OnKeyPressed(const Nz::WindowEvent::KeyEvent& key) override;
void OnKeyReleased(const Nz::WindowEvent::KeyEvent& key) override;
void OnMouseButtonPress(int /*x*/, int /*y*/, Nz::Mouse::Button button) override;
void OnMouseButtonRelease(int /*x*/, int /*y*/, Nz::Mouse::Button button) override;
void OnMouseEnter() override;
void OnMouseMoved(int x, int y, int deltaX, int deltaY) override;
void OnTextEntered(char32_t character, bool repeated) override;
inline void SetCursorPositionInternal(std::size_t glyphIndex);
inline void SetCursorPositionInternal(Nz::Vector2ui cursorPosition);
void RefreshCursor();
virtual void UpdateDisplayText() = 0;
void UpdateTextSprite();
CharacterFilter m_characterFilter;
EchoMode m_echoMode;
EntityHandle m_cursorEntity;
EntityHandle m_textEntity;
Nz::TextSpriteRef m_textSprite;
Nz::Vector2ui m_cursorPositionBegin;
Nz::Vector2ui m_cursorPositionEnd;
Nz::Vector2ui m_selectionCursor;
std::vector<Nz::SpriteRef> m_cursorSprites;
bool m_isLineWrapEnabled;
bool m_isMouseButtonDown;
bool m_multiLineEnabled;
bool m_readOnly;
bool m_tabEnabled; // writes (Shift+)Tab character if set to true
};
}
#include <NDK/Widgets/AbstractTextAreaWidget.inl>
#endif // NDK_WIDGETS_ABSTRACTTEXTAREAWIDGET_HPP

View File

@ -0,0 +1,252 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
#include <NDK/Widgets/AbstractTextAreaWidget.hpp>
namespace Ndk
{
inline void AbstractTextAreaWidget::EnableMultiline(bool enable)
{
m_multiLineEnabled = enable;
}
inline void AbstractTextAreaWidget::EnableTabWriting(bool enable)
{
m_tabEnabled = enable;
}
inline void AbstractTextAreaWidget::Erase(std::size_t glyphPosition)
{
Erase(glyphPosition, glyphPosition + 1U);
}
inline void AbstractTextAreaWidget::EraseSelection()
{
if (!HasSelection())
return;
Erase(GetGlyphIndex(m_cursorPositionBegin), GetGlyphIndex(m_cursorPositionEnd));
}
inline const AbstractTextAreaWidget::CharacterFilter& AbstractTextAreaWidget::GetCharacterFilter() const
{
return m_characterFilter;
}
inline const Nz::Vector2ui& AbstractTextAreaWidget::GetCursorPosition() const
{
return m_cursorPositionBegin;
}
Nz::Vector2ui AbstractTextAreaWidget::GetCursorPosition(std::size_t glyphIndex) const
{
const Nz::AbstractTextDrawer& textDrawer = GetTextDrawer();
glyphIndex = std::min(glyphIndex, GetTextDrawer().GetGlyphCount());
std::size_t lineCount = textDrawer.GetLineCount();
std::size_t line = 0U;
for (std::size_t i = line + 1; i < lineCount; ++i)
{
if (textDrawer.GetLine(i).glyphIndex > glyphIndex)
break;
line = i;
}
const auto& lineInfo = textDrawer.GetLine(line);
Nz::Vector2ui cursorPos;
cursorPos.y = static_cast<unsigned int>(line);
cursorPos.x = static_cast<unsigned int>(glyphIndex - lineInfo.glyphIndex);
return cursorPos;
}
inline EchoMode AbstractTextAreaWidget::GetEchoMode() const
{
return m_echoMode;
}
inline std::size_t AbstractTextAreaWidget::GetGlyphIndex() const
{
return GetGlyphIndex(m_cursorPositionBegin);
}
inline std::size_t AbstractTextAreaWidget::GetGlyphIndex(const Nz::Vector2ui& cursorPosition) const
{
const Nz::AbstractTextDrawer& textDrawer = GetTextDrawer();
std::size_t glyphIndex = textDrawer.GetLine(cursorPosition.y).glyphIndex + cursorPosition.x;
if (textDrawer.GetLineCount() > cursorPosition.y + 1)
glyphIndex = std::min(glyphIndex, textDrawer.GetLine(cursorPosition.y + 1).glyphIndex - 1);
else
glyphIndex = std::min(glyphIndex, textDrawer.GetGlyphCount());
return glyphIndex;
}
inline bool AbstractTextAreaWidget::HasSelection() const
{
return m_cursorPositionBegin != m_cursorPositionEnd;
}
inline bool AbstractTextAreaWidget::IsLineWrapEnabled() const
{
return m_isLineWrapEnabled;
}
inline bool AbstractTextAreaWidget::IsMultilineEnabled() const
{
return m_multiLineEnabled;
}
inline bool AbstractTextAreaWidget::IsTabWritingEnabled() const
{
return m_tabEnabled;
}
inline bool AbstractTextAreaWidget::IsReadOnly() const
{
return m_readOnly;
}
inline void AbstractTextAreaWidget::MoveCursor(int offset)
{
std::size_t cursorGlyph = GetGlyphIndex(m_cursorPositionBegin);
if (offset >= 0)
SetCursorPosition(cursorGlyph + static_cast<std::size_t>(offset));
else
{
std::size_t nOffset = static_cast<std::size_t>(-offset);
if (nOffset >= cursorGlyph)
SetCursorPosition(0);
else
SetCursorPosition(cursorGlyph - nOffset);
}
}
inline void AbstractTextAreaWidget::MoveCursor(const Nz::Vector2i& offset)
{
auto ClampOffset = [] (unsigned int cursorPosition, int cursorOffset) -> unsigned int
{
if (cursorOffset >= 0)
return cursorPosition + cursorOffset;
else
{
unsigned int nOffset = static_cast<unsigned int>(-cursorOffset);
if (nOffset >= cursorPosition)
return 0;
else
return cursorPosition - nOffset;
}
};
Nz::Vector2ui cursorPosition = m_cursorPositionBegin;
cursorPosition.x = ClampOffset(static_cast<unsigned int>(cursorPosition.x), offset.x);
cursorPosition.y = ClampOffset(static_cast<unsigned int>(cursorPosition.y), offset.y);
SetCursorPosition(cursorPosition);
}
inline Nz::Vector2ui AbstractTextAreaWidget::NormalizeCursorPosition(Nz::Vector2ui cursorPosition) const
{
const Nz::AbstractTextDrawer& textDrawer = GetTextDrawer();
std::size_t lineCount = textDrawer.GetLineCount();
if (cursorPosition.y >= lineCount)
cursorPosition.y = static_cast<unsigned int>(lineCount - 1);
const auto& lineInfo = textDrawer.GetLine(cursorPosition.y);
if (cursorPosition.y + 1 < lineCount)
{
const auto& nextLineInfo = textDrawer.GetLine(cursorPosition.y + 1);
cursorPosition.x = std::min(cursorPosition.x, static_cast<unsigned int>(nextLineInfo.glyphIndex - lineInfo.glyphIndex - 1));
}
return cursorPosition;
}
inline void AbstractTextAreaWidget::SetCharacterFilter(CharacterFilter filter)
{
m_characterFilter = std::move(filter);
}
inline void AbstractTextAreaWidget::SetCursorPosition(std::size_t glyphIndex)
{
Nz::Vector2ui position = GetCursorPosition(glyphIndex);
Nz::Vector2ui newPosition = position;
OnTextAreaCursorMove(this, &newPosition);
if (position == newPosition)
SetCursorPositionInternal(position);
else
SetCursorPositionInternal(GetGlyphIndex(newPosition));
}
inline void AbstractTextAreaWidget::SetCursorPosition(Nz::Vector2ui cursorPosition)
{
OnTextAreaCursorMove(this, &cursorPosition);
return SetCursorPositionInternal(NormalizeCursorPosition(cursorPosition));
}
inline void AbstractTextAreaWidget::SetEchoMode(EchoMode echoMode)
{
m_echoMode = echoMode;
UpdateDisplayText();
}
inline void AbstractTextAreaWidget::SetReadOnly(bool readOnly)
{
m_readOnly = readOnly;
m_cursorEntity->Enable(!m_readOnly && HasFocus());
}
inline void AbstractTextAreaWidget::SetSelection(Nz::Vector2ui fromPosition, Nz::Vector2ui toPosition)
{
// Ensure begin is before end
if (toPosition.y < fromPosition.y || (toPosition.y == fromPosition.y && toPosition.x < fromPosition.x))
std::swap(fromPosition, toPosition);
if (m_cursorPositionBegin != fromPosition || m_cursorPositionEnd != toPosition)
{
OnTextAreaSelection(this, &fromPosition, &toPosition);
// Ensure begin is before end a second time (in case signal changed it)
if (toPosition.y < fromPosition.y || (toPosition.y == fromPosition.y && toPosition.x < fromPosition.x))
std::swap(fromPosition, toPosition);
m_cursorPositionBegin = NormalizeCursorPosition(fromPosition);
m_cursorPositionEnd = NormalizeCursorPosition(toPosition);
RefreshCursor();
}
}
inline void AbstractTextAreaWidget::Write(const Nz::String& text)
{
Write(text, GetGlyphIndex(m_cursorPositionBegin));
}
inline void AbstractTextAreaWidget::Write(const Nz::String& text, const Nz::Vector2ui& glyphPosition)
{
Write(text, GetGlyphIndex(glyphPosition));
}
void AbstractTextAreaWidget::SetCursorPositionInternal(std::size_t glyphIndex)
{
return SetCursorPositionInternal(GetCursorPosition(glyphIndex));
}
inline void AbstractTextAreaWidget::SetCursorPositionInternal(Nz::Vector2ui cursorPosition)
{
m_cursorPositionBegin = cursorPosition;
m_cursorPositionEnd = m_cursorPositionBegin;
RefreshCursor();
}
}

View File

@ -0,0 +1,48 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
#pragma once
#ifndef NDK_WIDGETS_BOXLAYOUT_HPP
#define NDK_WIDGETS_BOXLAYOUT_HPP
#include <NDK/Prerequisites.hpp>
#include <NDK/BaseWidget.hpp>
#include <NDK/Widgets/Enums.hpp>
#include <vector>
namespace Ndk
{
class NDK_API BoxLayout : public BaseWidget
{
public:
inline BoxLayout(BaseWidget* parent, BoxLayoutOrientation orientation);
BoxLayout(const BoxLayout&) = delete;
BoxLayout(BoxLayout&&) = default;
~BoxLayout() = default;
void Layout() override;
BoxLayout& operator=(const BoxLayout&) = delete;
BoxLayout& operator=(BoxLayout&&) = default;
private:
struct ChildInfo
{
BaseWidget* widget;
bool isConstrained;
float maximumSize;
float minimumSize;
float size;
};
std::vector<ChildInfo> m_childInfos;
BoxLayoutOrientation m_orientation;
float m_spacing;
};
}
#include <NDK/Widgets/BoxLayout.inl>
#endif // NDK_WIDGETS_BOXLAYOUT_HPP

View File

@ -0,0 +1,15 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
#include <NDK/Widgets/BoxLayout.hpp>
namespace Ndk
{
BoxLayout::BoxLayout(BaseWidget* parent, BoxLayoutOrientation orientation) :
BaseWidget(parent),
m_orientation(orientation),
m_spacing(5.f)
{
}
}

View File

@ -23,15 +23,11 @@ namespace Ndk
class NDK_API ButtonWidget : public BaseWidget
{
public:
ButtonWidget(BaseWidget* parent = nullptr);
ButtonWidget(BaseWidget* parent);
ButtonWidget(const ButtonWidget&) = delete;
ButtonWidget(ButtonWidget&&) = default;
~ButtonWidget() = default;
//virtual ButtonWidget* Clone() const = 0;
void ResizeToContent() override;
inline const Nz::Color& GetColor() const;
inline const Nz::Color& GetCornerColor() const;
inline const Nz::Color& GetHoverColor() const;

View File

@ -93,6 +93,10 @@ namespace Ndk
{
m_textSprite->Update(drawer);
Nz::Vector2f textSize = Nz::Vector2f(m_textSprite->GetBoundingVolume().obb.localBox.GetLengths());
SetMinimumSize(textSize);
SetPreferredSize(textSize + Nz::Vector2f(20.f, 10.f));
Layout();
}
}

View File

@ -28,7 +28,7 @@ namespace Ndk
friend class Sdk;
public:
CheckboxWidget(BaseWidget* parent = nullptr);
CheckboxWidget(BaseWidget* parent);
CheckboxWidget(const CheckboxWidget&) = delete;
CheckboxWidget(CheckboxWidget&&) = default;
~CheckboxWidget() = default;
@ -53,7 +53,6 @@ namespace Ndk
void SetState(CheckboxState state);
inline void SetTextMargin(float margin);
void ResizeToContent() override;
inline void UpdateText(const Nz::AbstractTextDrawer& drawer);
@ -68,6 +67,7 @@ namespace Ndk
void Layout() override;
void UpdateCheckbox();
void UpdateSize();
void OnMouseButtonRelease(int x, int y, Nz::Mouse::Button button) override;
inline bool ContainsCheckbox(int x, int y) const;

View File

@ -65,6 +65,7 @@ namespace Ndk
m_checkboxBackgroundSprite->SetSize(size - GetCheckboxBorderSize() * 2.f);
m_checkboxContentSprite->SetSize(GetCheckboxSize() - GetCheckboxBorderSize() * 2.f - Nz::Vector2f { 4.f, 4.f });
UpdateSize();
Layout();
}
@ -77,6 +78,8 @@ namespace Ndk
inline void CheckboxWidget::UpdateText(const Nz::AbstractTextDrawer& drawer)
{
m_textSprite->Update(drawer);
UpdateSize();
Layout();
}

View File

@ -9,6 +9,12 @@
namespace Ndk
{
enum BoxLayoutOrientation
{
BoxLayoutOrientation_Horizontal,
BoxLayoutOrientation_Vertical
};
enum CheckboxState
{
CheckboxState_Checked,

View File

@ -19,21 +19,19 @@ namespace Ndk
class NDK_API ImageWidget : public BaseWidget
{
public:
ImageWidget(BaseWidget* parent = nullptr);
ImageWidget(BaseWidget* parent);
ImageWidget(const ImageWidget&) = delete;
ImageWidget(ImageWidget&&) = default;
~ImageWidget() = default;
//virtual ImageWidget* Clone() const = 0;
void ResizeToContent() override;
inline const Nz::Color& GetColor() const;
inline const Nz::TextureRef& GetTexture() const;
inline const Nz::Rectf& GetTextureCoords() const;
inline void SetColor(const Nz::Color& color);
inline void SetTexture(const Nz::TextureRef& texture, bool resizeToContent = true);
inline void SetTexture(const Nz::TextureRef& texture);
inline void SetTextureCoords(const Nz::Rectf& coords);
inline void SetTextureRect(const Nz::Rectui& rect);

View File

@ -26,12 +26,13 @@ namespace Ndk
m_sprite->SetColor(color);
}
inline void ImageWidget::SetTexture(const Nz::TextureRef& texture, bool resizeToContent)
inline void ImageWidget::SetTexture(const Nz::TextureRef& texture)
{
m_sprite->SetTexture(texture, false);
if (resizeToContent)
ResizeToContent();
Nz::Vector2f textureSize = Nz::Vector2f(Nz::Vector2ui(m_sprite->GetMaterial()->GetDiffuseMap()->GetSize()));
SetMinimumSize(textureSize);
SetPreferredSize(textureSize);
}
inline void ImageWidget::SetTextureCoords(const Nz::Rectf& coords)

View File

@ -21,23 +21,17 @@ namespace Ndk
class NDK_API LabelWidget : public BaseWidget
{
public:
LabelWidget(BaseWidget* parent = nullptr);
LabelWidget(BaseWidget* parent);
LabelWidget(const LabelWidget&) = delete;
LabelWidget(LabelWidget&&) = default;
~LabelWidget() = default;
//virtual LabelWidget* Clone() const = 0;
void ResizeToContent() override;
inline void UpdateText(const Nz::AbstractTextDrawer& drawer);
LabelWidget& operator=(const LabelWidget&) = delete;
LabelWidget& operator=(LabelWidget&&) = default;
private:
void Layout() override;
EntityHandle m_textEntity;
Nz::TextSpriteRef m_textSprite;
};

View File

@ -9,5 +9,9 @@ namespace Ndk
inline void LabelWidget::UpdateText(const Nz::AbstractTextDrawer& drawer)
{
m_textSprite->Update(drawer);
Nz::Vector2f size = Nz::Vector2f(m_textSprite->GetBoundingVolume().obb.localBox.GetLengths());
SetMinimumSize(size);
SetPreferredSize(size);
}
}

View File

@ -1,4 +1,4 @@
// Copyright (C) 2017 Samy Bensaid
// Copyright (C) 2017 Samy Bensaid
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
@ -23,7 +23,7 @@ namespace Ndk
friend class Sdk;
public:
ProgressBarWidget(BaseWidget* parent = nullptr);
ProgressBarWidget(BaseWidget* parent);
ProgressBarWidget(const ProgressBarWidget&) = delete;
ProgressBarWidget(ProgressBarWidget&&) = default;
~ProgressBarWidget() = default;
@ -67,8 +67,6 @@ namespace Ndk
inline void SetTextMargin(float margin);
inline void SetTextColor(const Nz::Color& color);
inline void ResizeToContent() override {}
NazaraSignal(OnValueChanged, const ProgressBarWidget* /*progressBar*/);
private:

View File

@ -1,4 +1,4 @@
// Copyright (C) 2017 Samy Bensaid
// Copyright (C) 2017 Samy Bensaid
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
@ -148,9 +148,8 @@ namespace Ndk
{
if (IsTextEnabled())
{
Nz::Vector2f size = GetContentSize();
m_textSprite->Update(Nz::SimpleTextDrawer::Draw(Nz::String::Number(m_value).Append('%'),
static_cast<unsigned>(std::min(size.x, size.y) / 2.f), 0u, m_textColor));
Nz::Vector2f size = GetSize();
m_textSprite->Update(Nz::SimpleTextDrawer::Draw(Nz::String::Number(m_value).Append('%'), static_cast<unsigned int>(std::min(size.x, size.y) / 2.f), 0u, m_textColor));
}
}
}

View File

@ -0,0 +1,68 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
#pragma once
#ifndef NDK_WIDGETS_RICHTEXTAREAWIDGET_HPP
#define NDK_WIDGETS_RICHTEXTAREAWIDGET_HPP
#include <Nazara/Utility/RichTextDrawer.hpp>
#include <NDK/Widgets/AbstractTextAreaWidget.hpp>
namespace Ndk
{
class NDK_API RichTextAreaWidget : public AbstractTextAreaWidget
{
public:
RichTextAreaWidget(BaseWidget* parent);
RichTextAreaWidget(const RichTextAreaWidget&) = delete;
RichTextAreaWidget(RichTextAreaWidget&&) = default;
~RichTextAreaWidget() = default;
void AppendText(const Nz::String& text);
void Clear() override;
void Erase(std::size_t firstGlyph, std::size_t lastGlyph) override;
inline unsigned int GetCharacterSize() const;
inline float GetCharacterSpacingOffset() const;
inline float GetLineSpacingOffset() const;
inline const Nz::Color& GetTextColor() const;
inline Nz::Font* GetTextFont() const;
inline const Nz::Color& GetTextOutlineColor() const;
inline float GetTextOutlineThickness() const;
inline Nz::TextStyleFlags GetTextStyle() const;
inline void SetCharacterSize(unsigned int characterSize);
inline void SetCharacterSpacingOffset(float offset);
inline void SetLineSpacingOffset(float offset);
inline void SetTextColor(const Nz::Color& color);
inline void SetTextFont(Nz::FontRef font);
inline void SetTextOutlineColor(const Nz::Color& color);
inline void SetTextOutlineThickness(float thickness);
inline void SetTextStyle(Nz::TextStyleFlags style);
void Write(const Nz::String& text, std::size_t glyphPosition) override;
RichTextAreaWidget& operator=(const RichTextAreaWidget&) = delete;
RichTextAreaWidget& operator=(RichTextAreaWidget&&) = default;
private:
Nz::AbstractTextDrawer& GetTextDrawer() override;
const Nz::AbstractTextDrawer& GetTextDrawer() const override;
void HandleIndentation(bool add) override;
void HandleSelectionIndentation(bool add) override;
void HandleWordCursorMove(bool left) override;
void UpdateDisplayText() override;
Nz::RichTextDrawer m_drawer;
};
}
#include <NDK/Widgets/RichTextAreaWidget.inl>
#endif // NDK_WIDGETS_TEXTAREAWIDGET_HPP

View File

@ -0,0 +1,88 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
#include <NDK/Widgets/RichTextAreaWidget.hpp>
namespace Ndk
{
inline unsigned int RichTextAreaWidget::GetCharacterSize() const
{
return m_drawer.GetDefaultCharacterSize();
}
inline float RichTextAreaWidget::GetCharacterSpacingOffset() const
{
return m_drawer.GetDefaultCharacterSpacingOffset();
}
inline float RichTextAreaWidget::GetLineSpacingOffset() const
{
return m_drawer.GetDefaultLineSpacingOffset();
}
inline const Nz::Color& RichTextAreaWidget::GetTextColor() const
{
return m_drawer.GetDefaultColor();
}
inline Nz::Font* RichTextAreaWidget::GetTextFont() const
{
return m_drawer.GetDefaultFont();
}
inline const Nz::Color& RichTextAreaWidget::GetTextOutlineColor() const
{
return m_drawer.GetDefaultOutlineColor();
}
inline float RichTextAreaWidget::GetTextOutlineThickness() const
{
return m_drawer.GetDefaultOutlineThickness();
}
inline Nz::TextStyleFlags RichTextAreaWidget::GetTextStyle() const
{
return m_drawer.GetDefaultStyle();
}
inline void RichTextAreaWidget::SetCharacterSize(unsigned int characterSize)
{
m_drawer.SetDefaultCharacterSize(characterSize);
}
inline void RichTextAreaWidget::SetCharacterSpacingOffset(float offset)
{
m_drawer.SetDefaultCharacterSpacingOffset(offset);
}
inline void RichTextAreaWidget::SetLineSpacingOffset(float offset)
{
m_drawer.SetDefaultLineSpacingOffset(offset);
}
inline void RichTextAreaWidget::SetTextColor(const Nz::Color& color)
{
m_drawer.SetDefaultColor(color);
}
inline void RichTextAreaWidget::SetTextFont(Nz::FontRef font)
{
m_drawer.SetDefaultFont(std::move(font));
}
inline void RichTextAreaWidget::SetTextOutlineColor(const Nz::Color& color)
{
m_drawer.SetDefaultOutlineColor(color);
}
inline void RichTextAreaWidget::SetTextOutlineThickness(float thickness)
{
m_drawer.SetDefaultOutlineThickness(thickness);
}
inline void RichTextAreaWidget::SetTextStyle(Nz::TextStyleFlags style)
{
m_drawer.SetDefaultStyle(style);
}
}

View File

@ -0,0 +1,74 @@
// Copyright (C) 2019 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
#pragma once
#ifndef NDK_WIDGETS_SCROLLAREAWIDGET_HPP
#define NDK_WIDGETS_SCROLLAREAWIDGET_HPP
#include <NDK/Prerequisites.hpp>
#include <NDK/BaseWidget.hpp>
#include <Nazara/Graphics/TextSprite.hpp>
namespace Ndk
{
class NDK_API ScrollAreaWidget : public BaseWidget
{
public:
ScrollAreaWidget(BaseWidget* parent, BaseWidget* content);
ScrollAreaWidget(const ScrollAreaWidget&) = delete;
ScrollAreaWidget(ScrollAreaWidget&&) = default;
~ScrollAreaWidget() = default;
void EnableScrollbar(bool enable);
inline float GetScrollHeight() const;
inline float GetScrollRatio() const;
inline bool HasScrollbar() const;
inline bool IsScrollbarEnabled() const;
inline bool IsScrollbarVisible() const;
inline void ScrollToHeight(float height);
void ScrollToRatio(float ratio);
ScrollAreaWidget& operator=(const ScrollAreaWidget&) = delete;
ScrollAreaWidget& operator=(ScrollAreaWidget&&) = default;
private:
enum class ScrollBarStatus
{
Grabbed,
Hovered,
None
};
Nz::Rectf GetScrollbarRect() const;
void Layout() override;
void OnMouseButtonPress(int x, int y, Nz::Mouse::Button button) override;
void OnMouseButtonRelease(int x, int y, Nz::Mouse::Button button) override;
void OnMouseExit() override;
void OnMouseMoved(int x, int y, int deltaX, int deltaY) override;
void OnMouseWheelMoved(int x, int y, float delta) override;
void UpdateScrollbarStatus(ScrollBarStatus status);
BaseWidget* m_content;
EntityHandle m_scrollbarBackgroundEntity;
EntityHandle m_scrollbarEntity;
Nz::SpriteRef m_scrollbarBackgroundSprite;
Nz::SpriteRef m_scrollbarSprite;
Nz::Vector2i m_grabbedDelta;
ScrollBarStatus m_scrollbarStatus;
bool m_isScrollbarEnabled;
bool m_hasScrollbar;
float m_scrollRatio;
};
}
#include <NDK/Widgets/ScrollAreaWidget.inl>
#endif // NDK_WIDGETS_SCROLLAREAWIDGET_HPP

View File

@ -0,0 +1,39 @@
// Copyright (C) 2019 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
#include <NDK/Widgets/ScrollAreaWidget.hpp>
namespace Ndk
{
inline float ScrollAreaWidget::GetScrollHeight() const
{
return m_scrollRatio * m_content->GetHeight();
}
inline float ScrollAreaWidget::GetScrollRatio() const
{
return m_scrollRatio;
}
inline bool ScrollAreaWidget::HasScrollbar() const
{
return m_hasScrollbar;
}
inline bool ScrollAreaWidget::IsScrollbarEnabled() const
{
return m_isScrollbarEnabled;
}
inline bool ScrollAreaWidget::IsScrollbarVisible() const
{
return HasScrollbar() && IsScrollbarEnabled();
}
inline void ScrollAreaWidget::ScrollToHeight(float height)
{
float contentHeight = m_content->GetHeight();
ScrollToRatio(height / contentHeight);
}
}

View File

@ -7,108 +7,68 @@
#ifndef NDK_WIDGETS_TEXTAREAWIDGET_HPP
#define NDK_WIDGETS_TEXTAREAWIDGET_HPP
#include <Nazara/Graphics/TextSprite.hpp>
#include <Nazara/Utility/SimpleTextDrawer.hpp>
#include <NDK/BaseWidget.hpp>
#include <NDK/Widgets/Enums.hpp>
#include <vector>
#include <NDK/Widgets/AbstractTextAreaWidget.hpp>
namespace Ndk
{
class NDK_API TextAreaWidget : public BaseWidget
class NDK_API TextAreaWidget : public AbstractTextAreaWidget
{
public:
TextAreaWidget(BaseWidget* parent = nullptr);
TextAreaWidget(BaseWidget* parent);
TextAreaWidget(const TextAreaWidget&) = delete;
TextAreaWidget(TextAreaWidget&&) = default;
~TextAreaWidget() = default;
void AppendText(const Nz::String& text);
inline void Clear();
void Clear() override;
//virtual TextAreaWidget* Clone() const = 0;
inline void EnableMultiline(bool enable = true);
void EraseSelection();
using AbstractTextAreaWidget::Erase;
void Erase(std::size_t firstGlyph, std::size_t lastGlyph) override;
inline unsigned int GetCharacterSize() const;
inline const Nz::Vector2ui& GetCursorPosition() const;
inline Nz::Vector2ui GetCursorPosition(std::size_t glyphIndex) const;
inline const Nz::String& GetDisplayText() const;
inline EchoMode GetEchoMode() const;
inline std::size_t GetGlyphIndex(const Nz::Vector2ui& cursorPosition);
inline float GetCharacterSpacingOffset() const;
inline float GetLineSpacingOffset() const;
inline const Nz::String& GetText() const;
inline const Nz::Color& GetTextColor() const;
Nz::Vector2ui GetHoveredGlyph(float x, float y) const;
inline bool HasSelection() const;
inline bool IsMultilineEnabled() const;
inline bool IsReadOnly() const;
inline void MoveCursor(int offset);
inline void MoveCursor(const Nz::Vector2i& offset);
void ResizeToContent() override;
inline Nz::Font* GetTextFont() const;
inline const Nz::Color& GetTextOulineColor() const;
inline float GetTextOulineThickness() const;
inline Nz::TextStyleFlags GetTextStyle() const;
inline void SetCharacterSize(unsigned int characterSize);
inline void SetCursorPosition(std::size_t glyphIndex);
inline void SetCursorPosition(Nz::Vector2ui cursorPosition);
inline void SetEchoMode(EchoMode echoMode);
inline void SetReadOnly(bool readOnly = true);
inline void SetSelection(Nz::Vector2ui fromPosition, Nz::Vector2ui toPosition);
inline void SetCharacterSpacingOffset(float offset);
inline void SetLineSpacingOffset(float offset);
inline void SetText(const Nz::String& text);
inline void SetTextColor(const Nz::Color& text);
inline void SetTextFont(Nz::FontRef font);
inline void SetTextOutlineColor(const Nz::Color& color);
inline void SetTextOutlineThickness(float thickness);
inline void SetTextStyle(Nz::TextStyleFlags style);
void Write(const Nz::String& text);
using AbstractTextAreaWidget::Write;
void Write(const Nz::String& text, std::size_t glyphPosition) override;
TextAreaWidget& operator=(const TextAreaWidget&) = delete;
TextAreaWidget& operator=(TextAreaWidget&&) = default;
NazaraSignal(OnTextAreaCursorMove, const TextAreaWidget* /*textArea*/, std::size_t* /*newCursorPosition*/);
NazaraSignal(OnTextAreaKeyBackspace, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/);
NazaraSignal(OnTextAreaKeyDown, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/);
NazaraSignal(OnTextAreaKeyEnd, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/);
NazaraSignal(OnTextAreaKeyHome, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/);
NazaraSignal(OnTextAreaKeyLeft, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/);
NazaraSignal(OnTextAreaKeyReturn, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/);
NazaraSignal(OnTextAreaKeyRight, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/);
NazaraSignal(OnTextAreaKeyUp, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/);
NazaraSignal(OnTextChanged, const TextAreaWidget* /*textArea*/, const Nz::String& /*text*/);
NazaraSignal(OnTextChanged, const AbstractTextAreaWidget* /*textArea*/, const Nz::String& /*text*/);
private:
void Layout() override;
Nz::AbstractTextDrawer& GetTextDrawer() override;
const Nz::AbstractTextDrawer& GetTextDrawer() const override;
bool IsFocusable() const override;
void OnFocusLost() override;
void OnFocusReceived() override;
bool OnKeyPressed(const Nz::WindowEvent::KeyEvent& key) override;
void OnKeyReleased(const Nz::WindowEvent::KeyEvent& key) override;
void OnMouseButtonPress(int /*x*/, int /*y*/, Nz::Mouse::Button button) override;
void OnMouseButtonRelease(int /*x*/, int /*y*/, Nz::Mouse::Button button) override;
void OnMouseEnter() override;
void OnMouseMoved(int x, int y, int deltaX, int deltaY) override;
void OnTextEntered(char32_t character, bool repeated) override;
void HandleIndentation(bool add) override;
void HandleSelectionIndentation(bool add) override;
void HandleWordCursorMove(bool left) override;
void RefreshCursor();
void UpdateDisplayText();
void UpdateDisplayText() override;
void UpdateMinimumSize();
EchoMode m_echoMode;
EntityHandle m_cursorEntity;
EntityHandle m_textEntity;
Nz::SimpleTextDrawer m_drawer;
Nz::String m_text;
Nz::TextSpriteRef m_textSprite;
Nz::Vector2ui m_cursorPositionBegin;
Nz::Vector2ui m_cursorPositionEnd;
Nz::Vector2ui m_selectionCursor;
std::vector<Nz::SpriteRef> m_cursorSprites;
bool m_isMouseButtonDown;
bool m_multiLineEnabled;
bool m_readOnly;
};
}

View File

@ -6,75 +6,24 @@
namespace Ndk
{
inline void TextAreaWidget::Clear()
{
m_cursorPositionBegin.MakeZero();
m_cursorPositionEnd.MakeZero();
m_drawer.Clear();
m_text.Clear();
m_textSprite->Update(m_drawer);
RefreshCursor();
OnTextChanged(this, m_text);
}
inline void TextAreaWidget::EnableMultiline(bool enable)
{
m_multiLineEnabled = enable;
}
inline unsigned int TextAreaWidget::GetCharacterSize() const
{
return m_drawer.GetCharacterSize();
}
inline const Nz::Vector2ui& TextAreaWidget::GetCursorPosition() const
{
return m_cursorPositionBegin;
}
Nz::Vector2ui TextAreaWidget::GetCursorPosition(std::size_t glyphIndex) const
{
glyphIndex = std::min(glyphIndex, m_drawer.GetGlyphCount());
std::size_t lineCount = m_drawer.GetLineCount();
std::size_t line = 0U;
for (std::size_t i = line + 1; i < lineCount; ++i)
{
if (m_drawer.GetLine(i).glyphIndex > glyphIndex)
break;
line = i;
}
const auto& lineInfo = m_drawer.GetLine(line);
Nz::Vector2ui cursorPos;
cursorPos.y = static_cast<unsigned int>(line);
cursorPos.x = static_cast<unsigned int>(glyphIndex - lineInfo.glyphIndex);
return cursorPos;
}
inline const Nz::String& TextAreaWidget::GetDisplayText() const
{
return m_drawer.GetText();
}
inline std::size_t TextAreaWidget::GetGlyphIndex(const Nz::Vector2ui& cursorPosition)
inline float TextAreaWidget::GetCharacterSpacingOffset() const
{
std::size_t glyphIndex = m_drawer.GetLine(cursorPosition.y).glyphIndex + cursorPosition.x;
if (m_drawer.GetLineCount() > cursorPosition.y + 1)
glyphIndex = std::min(glyphIndex, m_drawer.GetLine(cursorPosition.y + 1).glyphIndex - 1);
else
glyphIndex = std::min(glyphIndex, m_drawer.GetGlyphCount());
return glyphIndex;
return m_drawer.GetCharacterSpacingOffset();
}
inline EchoMode TextAreaWidget::GetEchoMode() const
inline float TextAreaWidget::GetLineSpacingOffset() const
{
return m_echoMode;
return m_drawer.GetLineSpacingOffset();
}
inline const Nz::String& TextAreaWidget::GetText() const
@ -87,126 +36,47 @@ namespace Ndk
return m_drawer.GetColor();
}
inline bool TextAreaWidget::HasSelection() const
inline Nz::Font* TextAreaWidget::GetTextFont() const
{
return m_cursorPositionBegin != m_cursorPositionEnd;
return m_drawer.GetFont();
}
inline bool TextAreaWidget::IsMultilineEnabled() const
inline const Nz::Color& TextAreaWidget::GetTextOulineColor() const
{
return m_multiLineEnabled;
return m_drawer.GetOutlineColor();
}
inline bool TextAreaWidget::IsReadOnly() const
inline float TextAreaWidget::GetTextOulineThickness() const
{
return m_readOnly;
return m_drawer.GetOutlineThickness();
}
inline void TextAreaWidget::MoveCursor(int offset)
inline Nz::TextStyleFlags TextAreaWidget::GetTextStyle() const
{
std::size_t cursorGlyph = GetGlyphIndex(m_cursorPositionBegin);
if (offset >= 0)
SetCursorPosition(cursorGlyph + static_cast<std::size_t>(offset));
else
{
std::size_t nOffset = static_cast<std::size_t>(-offset);
if (nOffset >= cursorGlyph)
SetCursorPosition(0);
else
SetCursorPosition(cursorGlyph - nOffset);
}
}
inline void TextAreaWidget::MoveCursor(const Nz::Vector2i& offset)
{
auto ClampOffset = [] (unsigned int cursorPosition, int cursorOffset) -> unsigned int
{
if (cursorOffset >= 0)
return cursorPosition + cursorOffset;
else
{
unsigned int nOffset = static_cast<unsigned int>(-cursorOffset);
if (nOffset >= cursorPosition)
return 0;
else
return cursorPosition - nOffset;
}
};
Nz::Vector2ui cursorPosition = m_cursorPositionBegin;
cursorPosition.x = ClampOffset(static_cast<unsigned int>(cursorPosition.x), offset.x);
cursorPosition.y = ClampOffset(static_cast<unsigned int>(cursorPosition.y), offset.y);
SetCursorPosition(cursorPosition);
return m_drawer.GetStyle();
}
inline void TextAreaWidget::SetCharacterSize(unsigned int characterSize)
{
m_drawer.SetCharacterSize(characterSize);
}
inline void TextAreaWidget::SetCursorPosition(std::size_t glyphIndex)
{
OnTextAreaCursorMove(this, &glyphIndex);
m_cursorPositionBegin = GetCursorPosition(glyphIndex);
m_cursorPositionEnd = m_cursorPositionBegin;
RefreshCursor();
}
inline void TextAreaWidget::SetCursorPosition(Nz::Vector2ui cursorPosition)
{
std::size_t lineCount = m_drawer.GetLineCount();
if (cursorPosition.y >= lineCount)
cursorPosition.y = static_cast<unsigned int>(lineCount - 1);
m_cursorPositionBegin = cursorPosition;
const auto& lineInfo = m_drawer.GetLine(cursorPosition.y);
if (cursorPosition.y + 1 < lineCount)
{
const auto& nextLineInfo = m_drawer.GetLine(cursorPosition.y + 1);
cursorPosition.x = std::min(cursorPosition.x, static_cast<unsigned int>(nextLineInfo.glyphIndex - lineInfo.glyphIndex - 1));
}
m_cursorPositionEnd = m_cursorPositionBegin;
std::size_t glyphIndex = lineInfo.glyphIndex + cursorPosition.x;
OnTextAreaCursorMove(this, &glyphIndex);
RefreshCursor();
}
inline void TextAreaWidget::SetEchoMode(EchoMode echoMode)
{
m_echoMode = echoMode;
UpdateMinimumSize();
UpdateDisplayText();
}
inline void TextAreaWidget::SetReadOnly(bool readOnly)
inline void TextAreaWidget::SetCharacterSpacingOffset(float offset)
{
m_readOnly = readOnly;
m_cursorEntity->Enable(!m_readOnly && HasFocus());
m_drawer.SetCharacterSpacingOffset(offset);
UpdateMinimumSize();
UpdateDisplayText();
}
inline void TextAreaWidget::SetSelection(Nz::Vector2ui fromPosition, Nz::Vector2ui toPosition)
inline void TextAreaWidget::SetLineSpacingOffset(float offset)
{
///TODO: Check if position are valid
m_drawer.SetLineSpacingOffset(offset);
// Ensure begin is before end
if (toPosition.y < fromPosition.y || (toPosition.y == fromPosition.y && toPosition.x < fromPosition.x))
std::swap(fromPosition, toPosition);
if (m_cursorPositionBegin != fromPosition || m_cursorPositionEnd != toPosition)
{
m_cursorPositionBegin = fromPosition;
m_cursorPositionEnd = toPosition;
RefreshCursor();
}
UpdateDisplayText();
}
inline void TextAreaWidget::SetText(const Nz::String& text)
@ -221,6 +91,34 @@ namespace Ndk
{
m_drawer.SetColor(text);
m_textSprite->Update(m_drawer);
UpdateDisplayText();
}
inline void TextAreaWidget::SetTextFont(Nz::FontRef font)
{
m_drawer.SetFont(font);
UpdateDisplayText();
}
inline void TextAreaWidget::SetTextOutlineColor(const Nz::Color& color)
{
m_drawer.SetOutlineColor(color);
UpdateDisplayText();
}
inline void TextAreaWidget::SetTextOutlineThickness(float thickness)
{
m_drawer.SetOutlineThickness(thickness);
UpdateDisplayText();
}
inline void TextAreaWidget::SetTextStyle(Nz::TextStyleFlags style)
{
m_drawer.SetStyle(style);
UpdateDisplayText();
}
}

View File

@ -46,6 +46,7 @@ namespace Ndk
void Clear() noexcept;
const EntityHandle& CloneEntity(EntityId id);
const EntityHandle& CloneEntity(const EntityHandle& entity);
inline void DisableProfiler();
inline void EnableProfiler(bool enable = true);
@ -67,6 +68,8 @@ namespace Ndk
inline void KillEntity(Entity* entity);
inline void KillEntities(const EntityVector& list);
inline bool IsEntityDying(const Entity* entity) const;
inline bool IsEntityDying(EntityId id) const;
inline bool IsEntityValid(const Entity* entity) const;
inline bool IsEntityIdValid(EntityId id) const;
inline bool IsProfilerEnabled() const;
@ -96,6 +99,12 @@ namespace Ndk
inline void InvalidateSystemOrder();
void ReorderSystems();
struct DoubleBitset
{
Nz::Bitset<Nz::UInt64> front;
Nz::Bitset<Nz::UInt64> back;
};
struct EntityBlock
{
EntityBlock(Entity&& e) :
@ -117,9 +126,9 @@ namespace Ndk
std::vector<std::unique_ptr<EntityBlock>> m_waitingEntities;
EntityList m_aliveEntities;
ProfilerData m_profilerData;
Nz::Bitset<Nz::UInt64> m_dirtyEntities;
DoubleBitset m_dirtyEntities;
Nz::Bitset<Nz::UInt64> m_freeEntityIds;
Nz::Bitset<Nz::UInt64> m_killedEntities;
DoubleBitset m_killedEntities;
bool m_orderedSystemsUpdated;
bool m_isProfilerEnabled;
};

View File

@ -308,7 +308,7 @@ namespace Ndk
inline void World::KillEntity(Entity* entity)
{
if (IsEntityValid(entity))
m_killedEntities.UnboundedSet(entity->GetId(), true);
m_killedEntities.front.UnboundedSet(entity->GetId(), true);
}
/*!
@ -324,13 +324,34 @@ namespace Ndk
KillEntity(entity);
}
/*!
* \brief Checks whether or not an entity is dying (has been killed this update)
* \return true If the entity exists and is dying
*
* \param entity Pointer to the entity
*/
inline bool World::IsEntityDying(const Entity* entity) const
{
return entity && IsEntityDying(entity->GetId());
}
/*!
* \brief Checks whether or not an entity is dying (has been killed this update)
* \return true If it is the case, false if the entity is alive (and hasn't been killed yet) or if the entity id is invalid
*
* \param id Identifier of the entity
*/
inline bool World::IsEntityDying(EntityId id) const
{
return m_killedEntities.front.UnboundedTest(id);
}
/*!
* \brief Checks whether or not an entity is valid
* \return true If it is the case
*
* \param entity Pointer to the entity
*/
inline bool World::IsEntityValid(const Entity* entity) const
{
return entity && entity->GetWorld() == this && IsEntityIdValid(entity->GetId());
@ -446,13 +467,13 @@ namespace Ndk
inline void World::Invalidate()
{
m_dirtyEntities.Resize(m_entityBlocks.size(), false);
m_dirtyEntities.Set(true); // Activation of all bits
m_dirtyEntities.front.Resize(m_entityBlocks.size(), false);
m_dirtyEntities.front.Set(true); // Activation of all bits
}
inline void World::Invalidate(EntityId id)
{
m_dirtyEntities.UnboundedSet(id, true);
m_dirtyEntities.front.UnboundedSet(id, true);
}
inline void World::InvalidateSystemOrder()

View File

@ -147,16 +147,22 @@ namespace Ndk
Nz::Vector2ui windowDimensions;
if (info.window->IsValid())
{
windowDimensions = info.window->GetSize();
windowDimensions.y /= 4;
}
else
windowDimensions.MakeZero();
overlay->console = std::make_unique<Console>(*info.overlayWorld, Nz::Vector2f(windowDimensions), overlay->lua);
Nz::LuaInstance& lua = overlay->lua;
overlay->console = info.canvas->Add<Console>();
overlay->console->OnCommand.Connect([&lua](Ndk::Console* console, const Nz::String& command)
{
if (!lua.Execute(command))
console->AddLine(lua.GetLastError(), Nz::Color::Red);
});
Console& consoleRef = *overlay->console;
consoleRef.Resize({float(windowDimensions.x), windowDimensions.y / 4.f});
consoleRef.Show(false);
// Redirect logs toward the console
overlay->logSlot.Connect(Nz::Log::OnLogWrite, [&consoleRef] (const Nz::String& str)
@ -164,11 +170,11 @@ namespace Ndk
consoleRef.AddLine(str);
});
overlay->lua.LoadLibraries();
LuaAPI::RegisterClasses(overlay->lua);
lua.LoadLibraries();
LuaAPI::RegisterClasses(lua);
// Override "print" function to add a line in the console
overlay->lua.PushFunction([&consoleRef] (Nz::LuaState& state)
lua.PushFunction([&consoleRef] (Nz::LuaState& state)
{
Nz::StringStream stream;
@ -192,31 +198,37 @@ namespace Ndk
consoleRef.AddLine(stream);
return 0;
});
overlay->lua.SetGlobal("print");
lua.SetGlobal("print");
// Define a few base variables to allow our interface to interact with the application
overlay->lua.PushGlobal("Application", Ndk::Application::Instance());
overlay->lua.PushGlobal("Console", consoleRef.CreateHandle());
lua.PushGlobal("Application", Ndk::Application::Instance());
lua.PushGlobal("Console", consoleRef.CreateHandle());
// Setup a few event callback to handle the console
Nz::EventHandler& eventHandler = info.window->GetEventHandler();
overlay->eventSlot.Connect(eventHandler.OnEvent, [&consoleRef] (const Nz::EventHandler*, const Nz::WindowEvent& event)
{
if (consoleRef.IsVisible())
consoleRef.SendEvent(event);
});
overlay->keyPressedSlot.Connect(eventHandler.OnKeyPressed, [&consoleRef] (const Nz::EventHandler*, const Nz::WindowEvent::KeyEvent& event)
{
if (event.code == Nz::Keyboard::F9)
consoleRef.Show(!consoleRef.IsVisible());
{
// Toggle console visibility and focus
if (consoleRef.IsVisible())
{
consoleRef.ClearFocus();
consoleRef.Show(false);
}
else
{
consoleRef.Show(true);
consoleRef.SetFocus();
}
}
});
overlay->resizedSlot.Connect(info.renderTarget->OnRenderTargetSizeChange, [&consoleRef] (const Nz::RenderTarget* renderTarget)
{
Nz::Vector2ui size = renderTarget->GetSize();
consoleRef.SetSize({float(size.x), size.y / 4.f});
consoleRef.Resize({float(size.x), size.y / 4.f});
});
info.console = std::move(overlay);
@ -238,6 +250,9 @@ namespace Ndk
{
info.overlayWorld = std::make_unique<World>(false); //< No default system
if (info.window->IsValid())
info.canvas = std::make_unique<Canvas>(info.overlayWorld->CreateHandle(), info.window->GetEventHandler(), info.window->GetCursorController().CreateHandle());
RenderSystem& renderSystem = info.overlayWorld->AddSystem<RenderSystem>();
renderSystem.ChangeRenderTechnique<Nz::ForwardRenderTechnique>();
renderSystem.SetDefaultBackground(nullptr);

View File

@ -81,7 +81,7 @@ namespace Ndk
m_backgroundSprite->SetColor(m_backgroundColor);
m_backgroundSprite->SetMaterial(Nz::Material::New((m_backgroundColor.IsOpaque()) ? "Basic2D" : "Translucent2D")); //< TODO: Use a shared material instead of creating one everytime
m_backgroundEntity = CreateEntity(false);
m_backgroundEntity = CreateEntity();
m_backgroundEntity->AddComponent<GraphicsComponent>().Attach(m_backgroundSprite, -1);
m_backgroundEntity->AddComponent<NodeComponent>().SetParent(this);
@ -89,14 +89,15 @@ namespace Ndk
}
else
{
m_backgroundEntity->Kill();
DestroyEntity(m_backgroundEntity);
m_backgroundEntity.Reset();
m_backgroundSprite.Reset();
}
}
/*!
* \brief Checks if this widget has keyboard focus
* \return true if widget has keyboard focus, false otherwhise
* \return true if widget has keyboard focus, false otherwise
*/
bool BaseWidget::HasFocus() const
{
@ -106,6 +107,19 @@ namespace Ndk
return m_canvas->IsKeyboardOwner(m_canvasIndex);
}
void BaseWidget::Resize(const Nz::Vector2f& size)
{
// Adjust new size
Nz::Vector2f newSize = size;
newSize.Maximize(m_minimumSize);
newSize.Minimize(m_maximumSize);
NotifyParentResized(newSize);
m_size = newSize;
Layout();
}
void BaseWidget::SetBackgroundColor(const Nz::Color& color)
{
m_backgroundColor = color;
@ -131,9 +145,27 @@ namespace Ndk
m_canvas->SetKeyboardOwner(m_canvasIndex);
}
void BaseWidget::SetSize(const Nz::Vector2f& size)
void BaseWidget::SetParent(BaseWidget* widget)
{
SetContentSize({std::max(size.x - m_padding.left - m_padding.right, 0.f), std::max(size.y - m_padding.top - m_padding.bottom, 0.f)});
Canvas* oldCanvas = m_canvas;
Canvas* newCanvas = widget->GetCanvas();
// Changing a widget canvas is a problem because of the canvas entities
NazaraAssert(oldCanvas == newCanvas, "Transferring a widget between canvas is not yet supported");
Node::SetParent(widget);
m_widgetParent = widget;
Layout();
}
void BaseWidget::SetRenderingRect(const Nz::Rectf& renderingRect)
{
m_renderingRect = renderingRect;
UpdatePositionAndSize();
for (const auto& widgetPtr : m_children)
widgetPtr->UpdatePositionAndSize();
}
void BaseWidget::Show(bool show)
@ -148,22 +180,45 @@ namespace Ndk
UnregisterFromCanvas();
for (WidgetEntity& entity : m_entities)
entity.handle->Enable(show);
{
if (entity.isEnabled)
{
entity.handle->Enable(show); //< This will override isEnabled
entity.isEnabled = true;
}
}
for (const auto& widgetPtr : m_children)
widgetPtr->Show(show);
}
}
const Ndk::EntityHandle& BaseWidget::CreateEntity(bool isContentEntity)
const EntityHandle& BaseWidget::CreateEntity()
{
const EntityHandle& newEntity = m_world->CreateEntity();
newEntity->Enable(m_visible);
m_entities.emplace_back();
WidgetEntity& widgetEntity = m_entities.back();
widgetEntity.handle = newEntity;
widgetEntity.isContent = isContentEntity;
WidgetEntity& newWidgetEntity = m_entities.back();
newWidgetEntity.handle = newEntity;
newWidgetEntity.onDisabledSlot.Connect(newEntity->OnEntityDisabled, [this](Entity* entity)
{
auto it = std::find_if(m_entities.begin(), m_entities.end(), [&](const WidgetEntity& widgetEntity) { return widgetEntity.handle == entity; });
NazaraAssert(it != m_entities.end(), "Entity does not belong to this widget");
it->isEnabled = false;
});
newWidgetEntity.onEnabledSlot.Connect(newEntity->OnEntityEnabled, [this](Entity* entity)
{
auto it = std::find_if(m_entities.begin(), m_entities.end(), [&](const WidgetEntity& widgetEntity) { return widgetEntity.handle == entity; });
NazaraAssert(it != m_entities.end(), "Entity does not belong to this widget");
if (!IsVisible())
entity->Disable(); // Next line will override isEnabled status
it->isEnabled = true;
});
return newEntity;
}
@ -178,8 +233,8 @@ namespace Ndk
void BaseWidget::Layout()
{
if (m_backgroundEntity)
m_backgroundSprite->SetSize(m_contentSize.x + m_padding.left + m_padding.right, m_contentSize.y + m_padding.top + m_padding.bottom);
if (m_backgroundSprite)
m_backgroundSprite->SetSize(m_size.x, m_size.y);
UpdatePositionAndSize();
}
@ -191,6 +246,19 @@ namespace Ndk
UpdatePositionAndSize();
}
Nz::Rectf BaseWidget::GetScissorRect() const
{
Nz::Vector2f widgetPos = Nz::Vector2f(GetPosition(Nz::CoordSys_Global));
Nz::Vector2f widgetSize = GetSize();
Nz::Rectf widgetRect(widgetPos.x, widgetPos.y, widgetSize.x, widgetSize.y);
Nz::Rectf widgetRenderingRect(widgetPos.x + m_renderingRect.x, widgetPos.y + m_renderingRect.y, m_renderingRect.width, m_renderingRect.height);
widgetRect.Intersect(widgetRenderingRect, &widgetRect);
return widgetRect;
}
bool BaseWidget::IsFocusable() const
{
return false;
@ -229,6 +297,10 @@ namespace Ndk
{
}
void BaseWidget::OnMouseWheelMoved(int /*x*/, int /*y*/, float /*delta*/)
{
}
void BaseWidget::OnMouseExit()
{
}
@ -279,19 +351,22 @@ namespace Ndk
if (IsRegisteredToCanvas())
m_canvas->NotifyWidgetBoxUpdate(m_canvasIndex);
Nz::Vector2f widgetPos = Nz::Vector2f(GetPosition());
Nz::Vector2f widgetSize = GetSize();
Nz::Rectf scissorRect = GetScissorRect();
Nz::Vector2f contentPos = widgetPos + GetContentOrigin();
Nz::Vector2f contentSize = GetContentSize();
if (m_widgetParent)
{
Nz::Rectf parentScissorRect = m_widgetParent->GetScissorRect();
Nz::Recti fullBounds(Nz::Rectf(widgetPos.x, widgetPos.y, widgetSize.x, widgetSize.y));
Nz::Recti contentBounds(Nz::Rectf(contentPos.x, contentPos.y, contentSize.x, contentSize.y));
if (!scissorRect.Intersect(parentScissorRect, &scissorRect))
scissorRect = parentScissorRect;
}
Nz::Recti fullBounds(scissorRect);
for (WidgetEntity& widgetEntity : m_entities)
{
const Ndk::EntityHandle& entity = widgetEntity.handle;
if (entity->HasComponent<GraphicsComponent>())
entity->GetComponent<GraphicsComponent>().SetScissorRect((widgetEntity.isContent) ? contentBounds : fullBounds);
entity->GetComponent<GraphicsComponent>().SetScissorRect(fullBounds);
}
}
}

View File

@ -7,10 +7,6 @@
namespace Ndk
{
void Canvas::ResizeToContent()
{
}
std::size_t Canvas::RegisterWidget(BaseWidget* widget)
{
WidgetEntry box;
@ -65,7 +61,7 @@ namespace Ndk
}
}
void Canvas::OnEventMouseButtonRelease(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::MouseButtonEvent & event)
void Canvas::OnEventMouseButtonRelease(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::MouseButtonEvent& event)
{
if (m_hoveredWidget != InvalidCanvasIndex)
{
@ -132,6 +128,19 @@ namespace Ndk
}
}
void Canvas::OnEventMouseWheelMoved(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::MouseWheelEvent& event)
{
if (m_hoveredWidget != InvalidCanvasIndex)
{
WidgetEntry& hoveredWidget = m_widgetEntries[m_hoveredWidget];
int x = static_cast<int>(std::round(event.x - hoveredWidget.box.x));
int y = static_cast<int>(std::round(event.y - hoveredWidget.box.y));
hoveredWidget.widget->OnMouseWheelMoved(x, y, event.delta);
}
}
void Canvas::OnEventMouseLeft(const Nz::EventHandler* /*eventHandler*/)
{
if (m_hoveredWidget != InvalidCanvasIndex)
@ -141,7 +150,7 @@ namespace Ndk
}
}
void Canvas::OnEventKeyPressed(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::KeyEvent& event)
void Canvas::OnEventKeyPressed(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::KeyEvent& event)
{
if (m_keyboardOwner != InvalidCanvasIndex)
{
@ -195,12 +204,16 @@ namespace Ndk
}
}
}
OnUnhandledKeyPressed(eventHandler, event);
}
void Canvas::OnEventKeyReleased(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::KeyEvent& event)
void Canvas::OnEventKeyReleased(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::KeyEvent& event)
{
if (m_keyboardOwner != InvalidCanvasIndex)
m_widgetEntries[m_keyboardOwner].widget->OnKeyReleased(event);
OnUnhandledKeyReleased(eventHandler, event);
}
void Canvas::OnEventTextEntered(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::TextEvent& event)

View File

@ -154,11 +154,10 @@ namespace Ndk
}
/*!
* \brief Sets the layer of the camera in case of multiples fields
* \brief Sets the layer of the camera in case of multiples layers
*
* \param layer Layer of the camera
*/
void CameraComponent::SetLayer(unsigned int layer)
{
m_layer = layer;
@ -169,7 +168,6 @@ namespace Ndk
/*!
* \brief Operation to perform when component is attached to an entity
*/
void CameraComponent::OnAttached()
{
if (m_entity->HasComponent<NodeComponent>())
@ -304,6 +302,8 @@ namespace Ndk
break;
}
m_projectionMatrix *= Nz::Matrix4f::Scale(m_projectionScale);
m_projectionMatrixUpdated = true;
}

View File

@ -17,29 +17,57 @@ namespace Ndk
* \brief NDK class that represents a two-dimensional collision geometry
*/
/*!
* \brief Gets the collision box representing the entity
* \return The physics collision box
*/
Nz::Rectf CollisionComponent2D::GetAABB() const
{
return GetRigidBody()->GetAABB();
}
/*!
* \brief Gets the position offset between the actual rigid body center of mass position and the origin of the geometry
* \return Position offset
*/
const Nz::Vector2f& CollisionComponent2D::GetGeomOffset() const
{
return GetRigidBody()->GetPositionOffset();
}
/*!
* \brief Convenience function to align center of geometry to a specific point
*
* \param geomOffset Position offset
*
* \remark This does not change the center of mass
*/
void CollisionComponent2D::Recenter(const Nz::Vector2f& origin)
{
const Nz::RigidBody2D* rigidBody = GetRigidBody();
SetGeomOffset(origin - rigidBody->GetAABB().GetCenter() + rigidBody->GetPositionOffset());
}
/*!
* \brief Sets geometry for the entity
*
* \param geom Geometry used for collisions
*
* \remark Produces a NazaraAssert if the entity has no physics component and has no static body
*/
void CollisionComponent2D::SetGeom(Nz::Collider2DRef geom)
{
m_geom = std::move(geom);
if (m_entity->HasComponent<PhysicsComponent2D>())
{
// We update the geometry of the PhysiscsObject linked to the PhysicsComponent2D
PhysicsComponent2D& physComponent = m_entity->GetComponent<PhysicsComponent2D>();
physComponent.GetRigidBody()->SetGeom(m_geom);
}
else
{
NazaraAssert(m_staticBody, "An entity without physics component should have a static body");
m_staticBody->SetGeom(m_geom);
}
GetRigidBody()->SetGeom(m_geom);
}
/*!
* \brief Sets the position offset between the actual rigid body center of mass position and the origin of the geometry
*
* \param geomOffset Position offset
*/
void CollisionComponent2D::SetGeomOffset(const Nz::Vector2f& geomOffset)
{
GetRigidBody()->SetPositionOffset(geomOffset);
}
/*!
@ -48,7 +76,6 @@ namespace Ndk
* \remark Produces a NazaraAssert if entity is invalid
* \remark Produces a NazaraAssert if entity is not linked to a world, or the world has no physics system
*/
void CollisionComponent2D::InitializeStaticBody()
{
NazaraAssert(m_entity, "Invalid entity");
@ -56,7 +83,7 @@ namespace Ndk
NazaraAssert(entityWorld, "Entity must have world");
NazaraAssert(entityWorld->HasSystem<PhysicsSystem2D>(), "World must have a physics system");
Nz::PhysWorld2D& physWorld = entityWorld->GetSystem<PhysicsSystem2D>().GetWorld();
Nz::PhysWorld2D& physWorld = entityWorld->GetSystem<PhysicsSystem2D>().GetPhysWorld();
m_staticBody = std::make_unique<Nz::RigidBody2D>(&physWorld, 0.f, m_geom);
m_staticBody->SetUserdata(reinterpret_cast<void*>(static_cast<std::ptrdiff_t>(m_entity->GetId())));
@ -68,7 +95,34 @@ namespace Ndk
matrix.MakeIdentity();
m_staticBody->SetPosition(Nz::Vector2f(matrix.GetTranslation()));
}
Nz::RigidBody2D* CollisionComponent2D::GetRigidBody()
{
if (m_entity->HasComponent<PhysicsComponent2D>())
{
PhysicsComponent2D& physComponent = m_entity->GetComponent<PhysicsComponent2D>();
return physComponent.GetRigidBody();
}
else
{
NazaraAssert(m_staticBody, "An entity without physics component should have a static body");
return m_staticBody.get();
}
}
const Nz::RigidBody2D* CollisionComponent2D::GetRigidBody() const
{
if (m_entity->HasComponent<PhysicsComponent2D>())
{
PhysicsComponent2D& physComponent = m_entity->GetComponent<PhysicsComponent2D>();
return physComponent.GetRigidBody();
}
else
{
NazaraAssert(m_staticBody, "An entity without physics component should have a static body");
return m_staticBody.get();
}
}
/*!

View File

@ -1,6 +1,23 @@
// Copyright (C) 2019 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
#include <NDK/Components/ConstraintComponent2D.hpp>
namespace Ndk
{
ConstraintComponent2D::ConstraintComponent2D(const ConstraintComponent2D& /*joint*/)
{
}
bool ConstraintComponent2D::RemoveConstraint(Nz::Constraint2D* constraintPtr)
{
auto it = std::find_if(m_constraints.begin(), m_constraints.end(), [constraintPtr](const ConstraintData& constraintData) { return constraintData.constraint.get() == constraintPtr; });
if (it != m_constraints.end())
m_constraints.erase(it);
return !m_constraints.empty();
}
ComponentIndex ConstraintComponent2D::componentIndex;
}

View File

@ -3,8 +3,33 @@
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
#include <NDK/Components/DebugComponent.hpp>
#include <NDK/Components/GraphicsComponent.hpp>
namespace Ndk
{
void DebugComponent::DetachDebugRenderables(GraphicsComponent& gfxComponent)
{
for (auto& renderable : m_debugRenderables)
{
if (renderable)
{
gfxComponent.Detach(renderable);
renderable.Reset();
}
}
}
void DebugComponent::OnComponentDetached(BaseComponent& component)
{
if (IsComponent<GraphicsComponent>(component))
DetachDebugRenderables(static_cast<GraphicsComponent&>(component));
}
void DebugComponent::OnDetached()
{
if (m_entity->HasComponent<GraphicsComponent>())
DetachDebugRenderables(m_entity->GetComponent<GraphicsComponent>());
}
ComponentIndex DebugComponent::componentIndex;
}

View File

@ -22,6 +22,7 @@ namespace Ndk
*/
void GraphicsComponent::AddToRenderQueue(Nz::AbstractRenderQueue* renderQueue) const
{
EnsureBoundingVolumesUpdate();
EnsureTransformMatrixUpdate();
RenderSystem& renderSystem = m_entity->GetWorld()->GetSystem<RenderSystem>();
@ -30,7 +31,6 @@ namespace Ndk
{
if (!object.dataUpdated)
{
object.data.transformMatrix = Nz::Matrix4f::ConcatenateAffine(renderSystem.GetCoordinateSystemMatrix(), Nz::Matrix4f::ConcatenateAffine(object.data.localMatrix, m_transformMatrix));
object.renderable->UpdateData(&object.data);
object.dataUpdated = true;
}
@ -39,6 +39,34 @@ namespace Ndk
}
}
/*!
* \brief Adds the renderable elements to the render queue if their bounding volume intersects with the frustum
*
* \param frustum Queue to be added
* \param renderQueue Queue to be added
*/
void GraphicsComponent::AddToRenderQueueByCulling(const Nz::Frustumf& frustum, Nz::AbstractRenderQueue* renderQueue) const
{
EnsureBoundingVolumesUpdate();
EnsureTransformMatrixUpdate();
RenderSystem& renderSystem = m_entity->GetWorld()->GetSystem<RenderSystem>();
for (const Renderable& object : m_renderables)
{
if (frustum.Contains(object.boundingVolume))
{
if (!object.dataUpdated)
{
object.renderable->UpdateData(&object.data);
object.dataUpdated = true;
}
object.renderable->AddToRenderQueue(renderQueue, object.data, m_scissorRect);
}
}
}
/*!
* \brief Attaches a renderable to the entity with a specific matrix
*
@ -60,12 +88,13 @@ namespace Ndk
for (std::size_t i = 0; i < materialCount; ++i)
RegisterMaterial(entry.renderable->GetMaterial(i));
InvalidateBoundingVolume();
InvalidateAABB();
ForceCullingInvalidation();
}
void GraphicsComponent::ConnectInstancedRenderableSignals(Renderable& entry)
{
entry.renderableBoundingVolumeInvalidationSlot.Connect(entry.renderable->OnInstancedRenderableInvalidateBoundingVolume, [this](const Nz::InstancedRenderable*) { InvalidateBoundingVolume(); });
entry.renderableBoundingVolumeInvalidationSlot.Connect(entry.renderable->OnInstancedRenderableInvalidateBoundingVolume, [this](const Nz::InstancedRenderable*) { InvalidateAABB(); });
entry.renderableDataInvalidationSlot.Connect(entry.renderable->OnInstancedRenderableInvalidateData, std::bind(&GraphicsComponent::InvalidateRenderableData, this, std::placeholders::_1, std::placeholders::_2, m_renderables.size() - 1));
entry.renderableMaterialInvalidationSlot.Connect(entry.renderable->OnInstancedRenderableInvalidateMaterial, this, &GraphicsComponent::InvalidateRenderableMaterial);
entry.renderableReleaseSlot.Connect(entry.renderable->OnInstancedRenderableRelease, this, &GraphicsComponent::Detach);
@ -82,8 +111,7 @@ namespace Ndk
r.dataUpdated = false;
r.renderable->InvalidateData(&r.data, flags);
for (VolumeCullingEntry& entry : m_volumeCullingEntries)
entry.listEntry.ForceInvalidation();
ForceCullingInvalidation();
}
void GraphicsComponent::InvalidateRenderableMaterial(const Nz::InstancedRenderable* renderable, std::size_t skinIndex, std::size_t matIndex, const Nz::MaterialRef& newMat)
@ -96,9 +124,11 @@ namespace Ndk
const Nz::MaterialRef& oldMat = renderable->GetMaterial(skinIndex, matIndex);
UnregisterMaterial(oldMat);
ForceCullingInvalidation();
}
void Ndk::GraphicsComponent::InvalidateReflectionMap()
void GraphicsComponent::InvalidateReflectionMap()
{
m_entity->Invalidate();
@ -202,6 +232,8 @@ namespace Ndk
std::size_t materialCount = renderable->GetMaterialCount();
for (std::size_t i = 0; i < materialCount; ++i)
UnregisterMaterial(renderable->GetMaterial(i));
ForceCullingInvalidation();
}
void GraphicsComponent::OnInstancedRenderableSkinChange(const Nz::InstancedRenderable* renderable, std::size_t newSkinIndex)
@ -212,6 +244,8 @@ namespace Ndk
for (std::size_t i = 0; i < materialCount; ++i)
UnregisterMaterial(renderable->GetMaterial(i));
ForceCullingInvalidation();
}
void GraphicsComponent::OnMaterialReflectionChange(const Nz::Material* material, Nz::ReflectionMode reflectionMode)
@ -234,11 +268,10 @@ namespace Ndk
NazaraUnused(node);
// Our view matrix depends on NodeComponent position/rotation
InvalidateBoundingVolume();
InvalidateAABB();
InvalidateTransformMatrix();
for (VolumeCullingEntry& entry : m_volumeCullingEntries)
entry.listEntry.ForceInvalidation(); //< Force invalidation on movement
ForceCullingInvalidation(); //< Force invalidation on movement for now (FIXME)
}
void GraphicsComponent::UnregisterMaterial(Nz::Material* material)
@ -263,36 +296,38 @@ namespace Ndk
* \brief Updates the bounding volume
*/
void GraphicsComponent::UpdateBoundingVolume() const
void GraphicsComponent::UpdateBoundingVolumes() const
{
EnsureTransformMatrixUpdate();
m_boundingVolume.MakeNull();
for (const Renderable& r : m_renderables)
{
Nz::BoundingVolumef boundingVolume = r.renderable->GetBoundingVolume();
// Adjust renderable bounding volume by local matrix
if (boundingVolume.IsFinite())
{
Nz::Boxf localBox = boundingVolume.obb.localBox;
Nz::Vector3f newPos = r.data.localMatrix * localBox.GetPosition();
Nz::Vector3f newCorner = r.data.localMatrix * (localBox.GetPosition() + localBox.GetLengths());
Nz::Vector3f newLengths = newCorner - newPos;
boundingVolume.Set(Nz::Boxf(newPos.x, newPos.y, newPos.z, newLengths.x, newLengths.y, newLengths.z));
}
m_boundingVolume.ExtendTo(boundingVolume);
}
RenderSystem& renderSystem = m_entity->GetWorld()->GetSystem<RenderSystem>();
m_boundingVolume.Update(Nz::Matrix4f::ConcatenateAffine(renderSystem.GetCoordinateSystemMatrix(), m_transformMatrix));
m_boundingVolumeUpdated = true;
m_aabb.Set(-1.f, -1.f, -1.f);
for (VolumeCullingEntry& entry : m_volumeCullingEntries)
entry.listEntry.UpdateVolume(m_boundingVolume);
bool isAabbSet = false;
for (const Renderable& r : m_renderables)
{
r.boundingVolume = r.renderable->GetBoundingVolume();
r.data.transformMatrix = Nz::Matrix4f::ConcatenateAffine(renderSystem.GetCoordinateSystemMatrix(), Nz::Matrix4f::ConcatenateAffine(r.data.localMatrix, m_transformMatrix));
if (r.boundingVolume.IsFinite())
{
r.boundingVolume.Update(r.data.transformMatrix);
if (isAabbSet)
m_aabb.ExtendTo(r.boundingVolume.aabb);
else
{
m_aabb.Set(r.boundingVolume.aabb);
isAabbSet = true;
}
}
}
m_boundingVolumesUpdated = true;
for (CullingBoxEntry& entry : m_cullingBoxEntries)
entry.listEntry.UpdateBox(m_aabb);
}
/*!

View File

@ -0,0 +1,10 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
#include <NDK/Components/LifetimeComponent.hpp>
namespace Ndk
{
ComponentIndex LifetimeComponent::componentIndex;
}

View File

@ -29,11 +29,19 @@ namespace Ndk
World* entityWorld = m_entity->GetWorld();
NazaraAssert(entityWorld->HasSystem<PhysicsSystem2D>(), "World must have a 2D physics system");
Nz::PhysWorld2D& world = entityWorld->GetSystem<PhysicsSystem2D>().GetWorld();
Nz::PhysWorld2D& world = entityWorld->GetSystem<PhysicsSystem2D>().GetPhysWorld();
Nz::Vector2f positionOffset;
Nz::Collider2DRef geom;
if (m_entity->HasComponent<CollisionComponent2D>())
geom = m_entity->GetComponent<CollisionComponent2D>().GetGeom();
{
const CollisionComponent2D& entityCollision = m_entity->GetComponent<CollisionComponent2D>();
geom = entityCollision.GetGeom();
positionOffset = entityCollision.GetStaticBody()->GetPositionOffset(); //< Calling GetGeomOffset would retrieve current component which is not yet initialized
}
else
positionOffset = Nz::Vector2f::Zero();
Nz::Matrix4f matrix;
if (m_entity->HasComponent<NodeComponent>())
@ -42,8 +50,12 @@ namespace Ndk
matrix.MakeIdentity();
m_object = std::make_unique<Nz::RigidBody2D>(&world, 1.f, geom);
m_object->SetPositionOffset(positionOffset);
m_object->SetPosition(Nz::Vector2f(matrix.GetTranslation()));
m_object->SetUserdata(reinterpret_cast<void*>(static_cast<std::ptrdiff_t>(m_entity->GetId())));
if (m_pendingStates.valid)
ApplyPhysicsState(*m_object);
}
/*!
@ -86,7 +98,11 @@ namespace Ndk
void PhysicsComponent2D::OnDetached()
{
m_object.reset();
if (m_object)
{
CopyPhysicsState(*m_object);
m_object.reset();
}
}
void PhysicsComponent2D::OnEntityDestruction()

View File

@ -4,14 +4,12 @@
#include <NDK/Console.hpp>
#include <Nazara/Core/Unicode.hpp>
#include <Nazara/Lua/LuaState.hpp>
#include <Nazara/Platform/Event.hpp>
#include <NDK/Components/GraphicsComponent.hpp>
#include <NDK/Components/NodeComponent.hpp>
#include <NDK/Widgets.hpp>
#include <NDK/World.hpp>
///TODO: For now is unable to display different color in the history, it needs a RichTextDrawer to do so
namespace Ndk
{
namespace
@ -34,71 +32,76 @@ namespace Ndk
* \param instance Lua instance that will interact with the world
*/
Console::Console(World& world, const Nz::Vector2f& size, Nz::LuaState& state) :
Console::Console(BaseWidget* parent) :
BaseWidget(parent),
m_historyPosition(0),
m_defaultFont(Nz::Font::GetDefault()),
m_state(state),
m_size(size),
m_opened(false),
m_characterSize(24)
m_characterSize(24),
m_maxHistoryLines(200)
{
Nz::MaterialRef backgroundMaterial = Nz::Material::New();
backgroundMaterial->EnableBlending(true);
backgroundMaterial->EnableDepthBuffer(false);
backgroundMaterial->SetDstBlend(Nz::BlendFunc_InvSrcAlpha);
backgroundMaterial->SetSrcBlend(Nz::BlendFunc_SrcAlpha);
// History bakckground
m_historyBackgroundSprite = Nz::Sprite::New();
m_historyBackgroundSprite->SetColor(Nz::Color(80, 80, 160, 128));
m_historyBackgroundSprite->SetMaterial(backgroundMaterial);
m_historyBackground = world.CreateEntity();
m_historyBackground->Enable(m_opened);
m_historyBackground->AddComponent<Ndk::GraphicsComponent>().Attach(m_historyBackgroundSprite, -1);
m_historyBackground->AddComponent<Ndk::NodeComponent>().SetParent(this);
// History
m_historyDrawer.SetCharacterSize(m_characterSize);
m_historyDrawer.SetColor(Nz::Color(200, 200, 200));
m_historyDrawer.SetFont(m_defaultFont);
m_history = Add<RichTextAreaWidget>();
m_history->EnableBackground(true);
m_history->EnableLineWrap(true);
m_history->SetReadOnly(true);
m_history->SetBackgroundColor(Nz::Color(80, 80, 160, 128));
m_historyTextSprite = Nz::TextSprite::New();
m_history = world.CreateEntity();
m_history->Enable(m_opened);
m_history->AddComponent<Ndk::GraphicsComponent>().Attach(m_historyTextSprite);
Ndk::NodeComponent& historyNode = m_history->AddComponent<Ndk::NodeComponent>();
historyNode.SetParent(this);
// Input background
m_inputBackgroundSprite = Nz::Sprite::New();
m_inputBackgroundSprite->SetColor(Nz::Color(255, 255, 255, 200));
m_inputBackgroundSprite->SetMaterial(backgroundMaterial);
m_inputBackground = world.CreateEntity();
m_inputBackground->Enable(m_opened);
m_inputBackground->AddComponent<Ndk::GraphicsComponent>().Attach(m_inputBackgroundSprite, -1);
m_inputBackground->AddComponent<Ndk::NodeComponent>().SetParent(this);
m_historyArea = Add<ScrollAreaWidget>(m_history);
// Input
m_inputDrawer.SetColor(Nz::Color::Black);
m_inputDrawer.SetCharacterSize(m_characterSize);
m_inputDrawer.SetFont(m_defaultFont);
m_inputDrawer.SetText(s_inputPrefix);
m_input = Add<TextAreaWidget>();
m_input->EnableBackground(true);
m_input->SetText(s_inputPrefix);
m_input->SetTextColor(Nz::Color::Black);
m_inputTextSprite = Nz::TextSprite::New();
m_inputTextSprite->Update(m_inputDrawer);
m_input->OnTextAreaKeyReturn.Connect(this, &Console::ExecuteInput);
m_input = world.CreateEntity();
m_input->Enable(m_opened);
m_input->AddComponent<Ndk::GraphicsComponent>().Attach(m_inputTextSprite);
// Protect input prefix from erasure/selection
m_input->SetCursorPosition(s_inputPrefixSize);
Ndk::NodeComponent& inputNode = m_input->AddComponent<Ndk::NodeComponent>();
inputNode.SetParent(this);
m_input->OnTextAreaCursorMove.Connect([](const AbstractTextAreaWidget* textArea, Nz::Vector2ui* newCursorPos)
{
newCursorPos->x = std::max(newCursorPos->x, static_cast<unsigned int>(s_inputPrefixSize));
});
Layout();
m_input->OnTextAreaSelection.Connect([](const AbstractTextAreaWidget* textArea, Nz::Vector2ui* start, Nz::Vector2ui* end)
{
start->x = std::max(start->x, static_cast<unsigned int>(s_inputPrefixSize));
end->x = std::max(end->x, static_cast<unsigned int>(s_inputPrefixSize));
});
m_input->OnTextAreaKeyBackspace.Connect([](const AbstractTextAreaWidget* textArea, bool* ignoreDefaultAction)
{
if (textArea->GetGlyphIndex() < s_inputPrefixSize)
*ignoreDefaultAction = true;
});
// Handle history
m_input->OnTextAreaKeyUp.Connect([&] (const AbstractTextAreaWidget* textArea, bool* ignoreDefaultAction)
{
*ignoreDefaultAction = true;
if (m_commandHistory.empty())
return;
if (m_historyPosition > 0)
m_historyPosition--;
m_input->SetText(s_inputPrefix + m_commandHistory[m_historyPosition]);
});
m_input->OnTextAreaKeyDown.Connect([&] (const AbstractTextAreaWidget* textArea, bool* ignoreDefaultAction)
{
*ignoreDefaultAction = true;
if (m_commandHistory.empty())
return;
if (++m_historyPosition >= m_commandHistory.size())
m_historyPosition = 0;
m_input->SetText(s_inputPrefix + m_commandHistory[m_historyPosition]);
});
}
/*!
@ -107,110 +110,41 @@ namespace Ndk
* \param text New line of text
* \param color Color for the text
*/
void Console::AddLine(const Nz::String& text, const Nz::Color& color)
{
AddLineInternal(text, color);
RefreshHistory();
if (m_historyLines.size() >= m_maxHistoryLines)
m_historyLines.erase(m_historyLines.begin());
m_historyLines.emplace_back(Line{ color, text });
m_history->SetTextColor(color);
m_history->AppendText(text + '\n');
m_history->Resize(m_history->GetPreferredSize());
m_historyArea->Resize(m_historyArea->GetSize());
m_historyArea->ScrollToRatio(1.f);
}
/*!
* \brief Clears the console
*
* Clears the console history and input
*/
void Console::Clear()
{
m_historyLines.clear();
RefreshHistory();
m_history->Clear();
m_history->Resize(m_history->GetPreferredSize());
m_historyArea->Resize(m_historyArea->GetSize());
m_input->SetText(s_inputPrefix);
}
/*!
* \brief Sends a character to the console
* \brief Clears the console focus
*
* \param character Character that will be added to the console
* Clear console input widget focus (if owned)
*/
void Console::SendCharacter(char32_t character)
void Console::ClearFocus()
{
switch (character)
{
case '\b':
{
Nz::String input = m_inputDrawer.GetText();
if (input.GetLength() <= s_inputPrefixSize) // Prevent removal of the input prefix
return; // Ignore if no user character is there
input.Resize(-1, Nz::String::HandleUtf8);
m_inputDrawer.SetText(input);
break;
}
case '\r':
case '\n':
ExecuteInput();
break;
default:
{
if (Nz::Unicode::GetCategory(character) == Nz::Unicode::Category_Other_Control)
return;
m_inputDrawer.AppendText(Nz::String::Unicode(character));
break;
}
}
m_inputTextSprite->Update(m_inputDrawer);
}
/*!
* \brief Sends an event to the console
*
* \param event Event to be takin into consideration by the console
*/
void Console::SendEvent(const Nz::WindowEvent& event)
{
switch (event.type)
{
case Nz::WindowEventType_TextEntered:
SendCharacter(event.text.character);
break;
case Nz::WindowEventType_KeyPressed:
{
switch (event.key.code)
{
case Nz::Keyboard::Down:
case Nz::Keyboard::Up:
{
if (event.key.code == Nz::Keyboard::Up)
m_historyPosition = std::min<std::size_t>(m_commandHistory.size(), m_historyPosition + 1);
else
{
if (m_historyPosition > 1)
m_historyPosition--;
else if (m_historyPosition == 0)
m_historyPosition = 1;
}
if (!m_commandHistory.empty())
{
Nz::String text = m_commandHistory[m_commandHistory.size() - m_historyPosition];
m_inputDrawer.SetText(s_inputPrefix + text);
m_inputTextSprite->Update(m_inputDrawer);
}
break;
}
default:
break;
}
break;
}
default:
break;
}
m_input->ClearFocus();
}
/*!
@ -218,30 +152,23 @@ namespace Ndk
*
* \param size Size of the font
*/
void Console::SetCharacterSize(unsigned int size)
{
m_characterSize = size;
m_historyDrawer.SetCharacterSize(m_characterSize);
m_historyTextSprite->Update(m_historyDrawer);
m_inputDrawer.SetCharacterSize(m_characterSize);
m_inputTextSprite->Update(m_inputDrawer);
m_history->SetCharacterSize(size);
m_input->SetCharacterSize(size);
Layout();
}
/*!
* \brief Sets the console size
* \brief Give the console input focus
*
* \param size (Width, Height) of the console
*/
void Console::SetSize(const Nz::Vector2f& size)
void Console::SetFocus()
{
m_size = size;
m_historyBackgroundSprite->SetSize(m_size);
Layout();
m_input->SetFocus();
}
/*!
@ -251,121 +178,55 @@ namespace Ndk
*
* \remark Produces a NazaraAssert if font is invalid or null
*/
void Console::SetTextFont(Nz::FontRef font)
{
NazaraAssert(font && font->IsValid(), "Invalid font");
m_defaultFont = std::move(font);
m_historyDrawer.SetFont(m_defaultFont);
m_inputDrawer.SetFont(m_defaultFont);
m_history->SetTextFont(m_defaultFont);
m_input->SetTextFont(m_defaultFont);
Layout();
}
/*!
* \brief Shows the console
*
* \param show Should the console be showed
*/
void Console::Show(bool show)
{
if (m_opened != show)
{
m_historyBackground->Enable(show);
m_history->Enable(show);
m_input->Enable(show);
m_inputBackground->Enable(show);
m_opened = show;
}
}
/*!
* \brief Adds a line to the history of the console
*
* \param text New line of text
* \param color Color for the text
*/
void Console::AddLineInternal(const Nz::String& text, const Nz::Color& color)
{
m_historyLines.emplace_back(Line{color, text});
}
/*!
* \brief Performs this action when an input is added to the console
*/
void Console::ExecuteInput()
void Console::ExecuteInput(const AbstractTextAreaWidget* textArea, bool* ignoreDefaultAction)
{
Nz::String input = m_inputDrawer.GetText();
NazaraAssert(textArea == m_input, "Unexpected signal from an other text area");
*ignoreDefaultAction = true;
Nz::String input = m_input->GetText();
Nz::String inputCmd = input.SubString(s_inputPrefixSize);
m_inputDrawer.SetText(s_inputPrefix);
m_input->SetText(s_inputPrefix);
if (m_commandHistory.empty() || m_commandHistory.back() != inputCmd)
m_commandHistory.push_back(inputCmd);
m_historyPosition = 0;
m_historyPosition = m_commandHistory.size();
AddLineInternal(input); //< With the input prefix
AddLine(input); //< With the input prefix
if (!m_state.Execute(inputCmd))
AddLineInternal(m_state.GetLastError(), Nz::Color::Red);
RefreshHistory();
OnCommand(this, inputCmd);
}
/*!
* \brief Places the console according to its layout
*/
void Console::Layout()
{
Nz::Vector2f origin = Nz::Vector2f(GetPosition());
const Nz::Vector2f& size = GetSize();
unsigned int lineHeight = m_defaultFont->GetSizeInfo(m_characterSize).lineHeight;
float historyHeight = size.y - lineHeight;
Ndk::NodeComponent& inputNode = m_input->GetComponent<Ndk::NodeComponent>();
inputNode.SetPosition(0.f, m_size.y - lineHeight - 5.f);
m_historyArea->SetPosition(origin.x, origin.y);
m_historyArea->Resize({ size.x, historyHeight - 4.f });
float historyHeight = m_size.y - lineHeight - 5.f - 2.f;
m_historyBackgroundSprite->SetSize(m_size.x, historyHeight);
m_maxHistoryLines = static_cast<unsigned int>(std::ceil(historyHeight / lineHeight));
Ndk::NodeComponent& historyNode = m_history->GetComponent<Ndk::NodeComponent>();
historyNode.SetPosition(0.f, historyHeight - m_maxHistoryLines * lineHeight);
Ndk::NodeComponent& inputBackgroundNode = m_inputBackground->GetComponent<Ndk::NodeComponent>();
inputBackgroundNode.SetPosition(0.f, historyHeight + 2.f);
m_inputBackgroundSprite->SetSize(m_size.x, m_size.y - historyHeight);
}
/*!
* \brief Refreshes the history of the console
*/
void Console::RefreshHistory()
{
m_historyDrawer.Clear();
auto it = m_historyLines.end();
if (m_historyLines.size() > m_maxHistoryLines)
it -= m_maxHistoryLines;
else
it = m_historyLines.begin();
for (unsigned int i = 0; i < m_maxHistoryLines; ++i)
{
if (m_maxHistoryLines - i <= m_historyLines.size() && it != m_historyLines.end())
{
m_historyDrawer.AppendText(it->text);
++it;
}
m_historyDrawer.AppendText(Nz::String('\n'));
}
m_historyTextSprite->Update(m_historyDrawer);
m_input->Resize({size.x, size.y - historyHeight});
m_input->SetPosition(origin.x, origin.y + historyHeight);
}
}

View File

@ -97,6 +97,36 @@ namespace Ndk
return m_world->CloneEntity(m_id);
}
/*!
* \brief Detaches a component from the entity
* \return An owning pointer to the component
*
* Instantly detaches a component from the entity and returns it, allowing to attach it to another entity
*
* \remark Unlike RemoveComponent, this function instantly removes the component
*/
std::unique_ptr<BaseComponent> Entity::DropComponent(ComponentIndex index)
{
if (!HasComponent(index))
return nullptr;
// We get the component and we alert existing components of the deleted one
std::unique_ptr<BaseComponent> component = std::move(m_components[index]);
m_components[index].reset();
for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i))
{
if (i != index)
m_components[i]->OnComponentDetached(*component);
}
m_componentBits.Reset(index);
m_removedComponentBits.UnboundedReset(index);
component->SetEntity(nullptr);
return component;
}
/*!
* \brief Enables the entity
*
@ -111,11 +141,15 @@ namespace Ndk
{
for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i))
m_components[i]->OnEntityEnabled();
OnEntityEnabled(this);
}
else
{
for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i))
m_components[i]->OnEntityDisabled();
OnEntityDisabled(this);
}
Invalidate();
@ -133,13 +167,22 @@ namespace Ndk
/*!
* \brief Invalidates the entity
*/
void Entity::Invalidate()
{
// We alert everyone that we have been updated
m_world->Invalidate(m_id);
}
/*!
* \brief Checks if the entity has been killed this update
* \return True if the entity is currently dying and will be dead at next world refresh
*/
bool Entity::IsDying() const
{
return m_world->IsEntityDying(m_id);
}
/*!
* \brief Creates the entity
*/
@ -195,32 +238,4 @@ namespace Ndk
m_valid = false;
}
/*!
* \brief Destroys a component by index
*
* \param index Index of the component
*
* \remark If component is not available, no action is performed
*/
void Entity::DestroyComponent(ComponentIndex index)
{
if (HasComponent(index))
{
// We get the component and we alert existing components of the deleted one
BaseComponent& component = *m_components[index].get();
for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i))
{
if (i != index)
m_components[i]->OnComponentDetached(component);
}
component.SetEntity(nullptr);
m_components[index].reset();
m_componentBits.Reset(index);
}
}
}

View File

@ -67,7 +67,7 @@ namespace Ndk
music.BindMethod("IsLooping", &Nz::Music::IsLooping);
music.BindMethod("OpenFromFile", &Nz::Music::OpenFromFile, Nz::MusicParams());
music.BindMethod("OpenFromFile", &Nz::Music::OpenFromFile, Nz::SoundStreamParams());
music.BindMethod("Pause", &Nz::Music::Pause);
music.BindMethod("Play", &Nz::Music::Play);
@ -138,7 +138,7 @@ namespace Ndk
soundBuffer.BindMethod("IsValid", &Nz::SoundBuffer::IsValid);
soundBuffer.BindMethod("LoadFromFile", &Nz::SoundBuffer::LoadFromFile, Nz::SoundBufferParams());
soundBuffer.BindStaticMethod("LoadFromFile", &Nz::SoundBuffer::LoadFromFile, Nz::SoundBufferParams());
soundBuffer.BindStaticMethod("IsFormatSupported", &Nz::SoundBuffer::IsFormatSupported);

View File

@ -181,8 +181,6 @@ namespace Ndk
material.BindMethod("IsShadowCastingEnabled", &Nz::Material::IsShadowCastingEnabled);
material.BindMethod("IsShadowReceiveEnabled", &Nz::Material::IsShadowReceiveEnabled);
material.BindMethod("LoadFromFile", &Nz::Material::LoadFromFile, Nz::MaterialParams());
material.BindMethod("Reset", &Nz::Material::Reset);
material.BindMethod("SetAlphaThreshold", &Nz::Material::SetAlphaThreshold);
@ -205,6 +203,7 @@ namespace Ndk
material.BindMethod("SetSrcBlend", &Nz::Material::SetSrcBlend);
material.BindStaticMethod("GetDefault", &Nz::Material::GetDefault);
material.BindStaticMethod("LoadFromFile", &Nz::Material::LoadFromFile, Nz::MaterialParams());
material.BindMethod("SetAlphaMap", [] (Nz::LuaState& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int
{
@ -308,8 +307,6 @@ namespace Ndk
//modelClass.SetMethod("GetMesh", &Nz::Model::GetMesh);
model.BindMethod("IsAnimated", &Nz::Model::IsAnimated);
model.BindMethod("LoadFromFile", &Nz::Model::LoadFromFile, Nz::ModelParameters());
model.BindMethod("SetMaterial", [] (Nz::LuaState& lua, Nz::Model* instance, std::size_t argumentCount) -> int
{
@ -371,6 +368,8 @@ namespace Ndk
//modelClass.SetMethod("SetMesh", &Nz::Model::SetMesh);
//modelClass.SetMethod("SetSequence", &Nz::Model::SetSequence);
model.BindStaticMethod("LoadFromFile", &Nz::Model::LoadFromFile, Nz::ModelParameters());
}
/*********************************** Nz::Sprite ***********************************/

View File

@ -282,7 +282,7 @@ namespace Ndk
{
case 1:
if (lua.IsOfType(argIndex, "Matrix4"))
instance.Set(*static_cast<Nz::Matrix4d*>(lua.ToUserdata(argIndex)));
instance = *static_cast<Nz::Matrix4d*>(lua.ToUserdata(argIndex));
break;
case 16:
@ -291,7 +291,7 @@ namespace Ndk
for (std::size_t i = 0; i < 16; ++i)
values[i] = lua.CheckNumber(argIndex++);
instance.Set(values);
instance = Nz::Matrix4d(values);
return 0;
}

View File

@ -44,21 +44,6 @@ namespace Ndk
texture.BindMethod("InvalidateMipmaps", &Nz::Texture::InvalidateMipmaps);
texture.BindMethod("IsValid", &Nz::Texture::IsValid);
texture.BindMethod("LoadFromFile", &Nz::Texture::LoadFromFile, true, Nz::ImageParams());
//bool LoadFromImage(const Image& image, bool generateMipmaps = true);
//bool LoadFromMemory(const void* data, std::size_t size, const ImageParams& params = ImageParams(), bool generateMipmaps = true);
//bool LoadFromStream(Stream& stream, const ImageParams& params = ImageParams(), bool generateMipmaps = true);
texture.BindMethod("LoadArrayFromFile", &Nz::Texture::LoadArrayFromFile, Nz::Vector2ui(2, 2), true, Nz::ImageParams());
//bool LoadArrayFromImage(const Image& image, bool generateMipmaps = true, const Vector2ui& atlasSize = Vector2ui(2, 2));
//bool LoadArrayFromMemory(const void* data, std::size_t size, const ImageParams& imageParams = ImageParams(), bool generateMipmaps = true, const Vector2ui& atlasSize = Vector2ui(2, 2));
//bool LoadArrayFromStream(Stream& stream, const ImageParams& imageParams = ImageParams(), bool generateMipmaps = true, const Vector2ui& atlasSize = Vector2ui(2, 2));
//bool LoadCubemapFromFile(const String& filePath, const ImageParams& imageParams = ImageParams(), bool generateMipmaps = true, const CubemapParams& cubemapParams = CubemapParams());
//bool LoadCubemapFromImage(const Image& image, bool generateMipmaps = true, const CubemapParams& params = CubemapParams());
//bool LoadCubemapFromMemory(const void* data, std::size_t size, const ImageParams& imageParams = ImageParams(), bool generateMipmaps = true, const CubemapParams& cubemapParams = CubemapParams());
//bool LoadCubemapFromStream(Stream& stream, const ImageParams& imageParams = ImageParams(), bool generateMipmaps = true, const CubemapParams& cubemapParams = CubemapParams());
texture.BindMethod("LoadFaceFromFile", &Nz::Texture::LoadFaceFromFile, Nz::ImageParams());
//bool LoadFaceFromMemory(CubemapFace face, const void* data, std::size_t size, const ImageParams& params = ImageParams());
//bool LoadFaceFromStream(CubemapFace face, Stream& stream, const ImageParams& params = ImageParams());
@ -71,6 +56,21 @@ namespace Ndk
texture.BindStaticMethod("IsFormatSupported", &Nz::Texture::IsFormatSupported);
texture.BindStaticMethod("IsMipmappingSupported", &Nz::Texture::IsMipmappingSupported);
texture.BindStaticMethod("IsTypeSupported", &Nz::Texture::IsTypeSupported);
texture.BindStaticMethod("LoadFromFile", &Nz::Texture::LoadFromFile, true, Nz::ImageParams());
//TextureRef LoadFromImage(const Image& image, bool generateMipmaps = true);
//TextureRef LoadFromMemory(const void* data, std::size_t size, const ImageParams& params = ImageParams(), bool generateMipmaps = true);
//TextureRef LoadFromStream(Stream& stream, const ImageParams& params = ImageParams(), bool generateMipmaps = true);
texture.BindStaticMethod("LoadArrayFromFile", &Nz::Texture::LoadArrayFromFile, Nz::Vector2ui(2, 2), true, Nz::ImageParams());
//TextureRef LoadArrayFromImage(const Image& image, bool generateMipmaps = true, const Vector2ui& atlasSize = Vector2ui(2, 2));
//TextureRef LoadArrayFromMemory(const void* data, std::size_t size, const ImageParams& imageParams = ImageParams(), bool generateMipmaps = true, const Vector2ui& atlasSize = Vector2ui(2, 2));
//TextureRef LoadArrayFromStream(Stream& stream, const ImageParams& imageParams = ImageParams(), bool generateMipmaps = true, const Vector2ui& atlasSize = Vector2ui(2, 2));
//TextureRef LoadCubemapFromFile(const String& filePath, const ImageParams& imageParams = ImageParams(), bool generateMipmaps = true, const CubemapParams& cubemapParams = CubemapParams());
//TextureRef LoadCubemapFromImage(const Image& image, bool generateMipmaps = true, const CubemapParams& params = CubemapParams());
//TextureRef LoadCubemapFromMemory(const void* data, std::size_t size, const ImageParams& imageParams = ImageParams(), bool generateMipmaps = true, const CubemapParams& cubemapParams = CubemapParams());
//TextureRef LoadCubemapFromStream(Stream& stream, const ImageParams& imageParams = ImageParams(), bool generateMipmaps = true, const CubemapParams& cubemapParams = CubemapParams());
}
/*********************************** Nz::TextureLibrary ***********************************/

View File

@ -62,24 +62,14 @@ namespace Ndk
console.BindMethod("AddLine", &Console::AddLine, Nz::Color::White);
console.BindMethod("Clear", &Console::Clear);
console.BindMethod("GetCharacterSize", &Console::GetCharacterSize);
console.BindMethod("GetHistory", &Console::GetHistory);
console.BindMethod("GetHistoryBackground", &Console::GetHistoryBackground);
console.BindMethod("GetInput", &Console::GetInput);
console.BindMethod("GetInputBackground", &Console::GetInputBackground);
console.BindMethod("GetSize", &Console::GetSize);
//console.BindMethod("GetHistory", &Console::GetHistory);
//console.BindMethod("GetInput", &Console::GetInput);
console.BindMethod("GetTextFont", &Console::GetTextFont);
console.BindMethod("IsValidHandle", &ConsoleHandle::IsValid);
console.BindMethod("IsVisible", &Console::IsVisible);
console.BindMethod("SendCharacter", &Console::SendCharacter);
//consoleClass.SetMethod("SendEvent", &Console::SendEvent);
console.BindMethod("SetCharacterSize", &Console::SetCharacterSize);
console.BindMethod("SetSize", &Console::SetSize);
console.BindMethod("SetTextFont", &Console::SetTextFont);
console.BindMethod("Show", &Console::Show, true);
}
#endif

View File

@ -123,12 +123,13 @@ namespace Ndk
lua.Push(instance->GetCachedGlyphCount());
return 1;
case 2:
case 3:
{
unsigned int characterSize = lua.Check<unsigned int>(&argIndex);
Nz::UInt32 style = lua.Check<Nz::UInt32>(&argIndex);
Nz::TextStyleFlags style = lua.Check<Nz::TextStyleFlags>(&argIndex);
float outlineThickness = lua.Check<float>(&argIndex);
lua.Push(instance->GetCachedGlyphCount(characterSize, style));
lua.Push(instance->GetCachedGlyphCount(characterSize, style, outlineThickness));
return 1;
}
}
@ -146,9 +147,7 @@ namespace Ndk
font.BindMethod("IsValid", &Nz::Font::IsValid);
font.BindMethod("Precache", (bool(Nz::Font::*)(unsigned int, Nz::UInt32, const Nz::String&) const) &Nz::Font::Precache);
font.BindMethod("OpenFromFile", &Nz::Font::OpenFromFile, Nz::FontParams());
font.BindMethod("Precache", (bool(Nz::Font::*)(unsigned int, Nz::TextStyleFlags, float, const Nz::String&) const) &Nz::Font::Precache);
font.BindMethod("SetGlyphBorder", &Nz::Font::SetGlyphBorder);
font.BindMethod("SetMinimumStepSize", &Nz::Font::SetMinimumStepSize);
@ -157,6 +156,8 @@ namespace Ndk
font.BindStaticMethod("GetDefaultGlyphBorder", &Nz::Font::GetDefaultGlyphBorder);
font.BindStaticMethod("GetDefaultMinimumStepSize", &Nz::Font::GetDefaultMinimumStepSize);
font.BindStaticMethod("OpenFromFile", &Nz::Font::OpenFromFile, Nz::FontParams());
font.BindStaticMethod("SetDefaultGlyphBorder", &Nz::Font::SetDefaultGlyphBorder);
font.BindStaticMethod("SetDefaultMinimumStepSize", &Nz::Font::SetDefaultMinimumStepSize);
}

View File

@ -17,11 +17,13 @@
#include <NDK/BaseSystem.hpp>
#include <NDK/Components/CollisionComponent2D.hpp>
#include <NDK/Components/CollisionComponent3D.hpp>
#include <NDK/Components/LifetimeComponent.hpp>
#include <NDK/Components/NodeComponent.hpp>
#include <NDK/Components/PhysicsComponent2D.hpp>
#include <NDK/Components/PhysicsComponent3D.hpp>
#include <NDK/Components/VelocityComponent.hpp>
#include <NDK/Components/ConstraintComponent2D.hpp>
#include <NDK/Systems/LifetimeSystem.hpp>
#include <NDK/Systems/PhysicsSystem2D.hpp>
#include <NDK/Systems/PhysicsSystem3D.hpp>
#include <NDK/Systems/VelocitySystem.hpp>
@ -88,6 +90,7 @@ namespace Ndk
// Shared components
InitializeComponent<CollisionComponent2D>("NdkColl2");
InitializeComponent<CollisionComponent3D>("NdkColl3");
InitializeComponent<LifetimeComponent>("NdkLiftm");
InitializeComponent<NodeComponent>("NdkNode");
InitializeComponent<PhysicsComponent2D>("NdkPhys2");
InitializeComponent<PhysicsComponent3D>("NdkPhys3");
@ -110,6 +113,7 @@ namespace Ndk
BaseSystem::Initialize();
// Shared systems
InitializeSystem<LifetimeSystem>();
InitializeSystem<PhysicsSystem2D>();
InitializeSystem<PhysicsSystem3D>();
InitializeSystem<VelocitySystem>();

View File

@ -8,10 +8,12 @@
#include <Nazara/Utility/IndexIterator.hpp>
#include <Nazara/Utility/Mesh.hpp>
#include <Nazara/Utility/StaticMesh.hpp>
#include <NDK/Components/CollisionComponent2D.hpp>
#include <NDK/Components/CollisionComponent3D.hpp>
#include <NDK/Components/DebugComponent.hpp>
#include <NDK/Components/GraphicsComponent.hpp>
#include <NDK/Components/NodeComponent.hpp>
#include <NDK/Components/PhysicsComponent2D.hpp>
namespace Ndk
{
@ -20,9 +22,8 @@ namespace Ndk
class DebugRenderable : public Nz::InstancedRenderable
{
public:
DebugRenderable(Ndk::Entity* owner, Nz::MaterialRef mat, Nz::IndexBufferRef indexBuffer, Nz::VertexBufferRef vertexBuffer) :
DebugRenderable(Ndk::Entity* owner, Nz::IndexBufferRef indexBuffer, Nz::VertexBufferRef vertexBuffer) :
m_entityOwner(owner),
m_material(std::move(mat)),
m_indexBuffer(std::move(indexBuffer)),
m_vertexBuffer(std::move(vertexBuffer))
{
@ -33,19 +34,20 @@ namespace Ndk
m_meshData.vertexBuffer = m_vertexBuffer;
}
void UpdateBoundingVolume(InstanceData* instanceData) const override
void UpdateBoundingVolume(InstanceData* /*instanceData*/) const override
{
}
void MakeBoundingVolume() const override
{
m_boundingVolume.MakeNull();
// We generate an infinite bounding volume so that we're always considered for rendering when culling does occurs
// (bounding volume culling happens only if GraphicsComponent AABB partially fail)
m_boundingVolume.MakeInfinite();
}
protected:
Ndk::EntityHandle m_entityOwner;
Nz::IndexBufferRef m_indexBuffer;
Nz::MaterialRef m_material;
Nz::MeshData m_meshData;
Nz::VertexBufferRef m_vertexBuffer;
};
@ -53,7 +55,12 @@ namespace Ndk
class AABBDebugRenderable : public DebugRenderable
{
public:
using DebugRenderable::DebugRenderable;
AABBDebugRenderable(Ndk::Entity* owner, Nz::MaterialRef globalMaterial, Nz::MaterialRef localMaterial, Nz::IndexBufferRef indexBuffer, Nz::VertexBufferRef vertexBuffer) :
DebugRenderable(owner, std::move(indexBuffer), std::move(vertexBuffer)),
m_globalMaterial(std::move(globalMaterial)),
m_localMaterial(std::move(localMaterial))
{
}
void AddToRenderQueue(Nz::AbstractRenderQueue* renderQueue, const InstanceData& instanceData, const Nz::Recti& scissorRect) const override
{
@ -62,25 +69,43 @@ namespace Ndk
const DebugComponent& entityDebug = m_entityOwner->GetComponent<DebugComponent>();
const GraphicsComponent& entityGfx = m_entityOwner->GetComponent<GraphicsComponent>();
Nz::Boxf aabb = entityGfx.GetBoundingVolume().aabb;
auto DrawBox = [&](const Nz::Boxf& box, const Nz::MaterialRef& mat)
{
Nz::Matrix4f transformMatrix = Nz::Matrix4f::Identity();
transformMatrix.SetScale(box.GetLengths());
transformMatrix.SetTranslation(box.GetCenter());
Nz::Matrix4f transformMatrix = Nz::Matrix4f::Identity();
transformMatrix.SetScale(aabb.GetLengths());
transformMatrix.SetTranslation(aabb.GetCenter());
renderQueue->AddMesh(0, mat, m_meshData, Nz::Boxf::Zero(), transformMatrix, scissorRect);
};
renderQueue->AddMesh(0, m_material, m_meshData, Nz::Boxf::Zero(), transformMatrix, scissorRect);
DrawBox(entityGfx.GetAABB(), m_globalMaterial);
for (std::size_t i = 0; i < entityGfx.GetAttachedRenderableCount(); ++i)
{
const Nz::BoundingVolumef& boundingVolume = entityGfx.GetBoundingVolume(i);
if (boundingVolume.IsFinite())
DrawBox(boundingVolume.aabb, m_localMaterial);
}
}
std::unique_ptr<InstancedRenderable> Clone() const override
{
return nullptr;
}
private:
Nz::MaterialRef m_globalMaterial;
Nz::MaterialRef m_localMaterial;
};
class OBBDebugRenderable : public DebugRenderable
{
public:
using DebugRenderable::DebugRenderable;
OBBDebugRenderable(Ndk::Entity* owner, Nz::MaterialRef material, Nz::IndexBufferRef indexBuffer, Nz::VertexBufferRef vertexBuffer) :
DebugRenderable(owner, std::move(indexBuffer), std::move(vertexBuffer)),
m_material(std::move(material))
{
}
void AddToRenderQueue(Nz::AbstractRenderQueue* renderQueue, const InstanceData& instanceData, const Nz::Recti& scissorRect) const override
{
@ -89,21 +114,31 @@ namespace Ndk
const DebugComponent& entityDebug = m_entityOwner->GetComponent<DebugComponent>();
const GraphicsComponent& entityGfx = m_entityOwner->GetComponent<GraphicsComponent>();
Nz::Boxf obb = entityGfx.GetBoundingVolume().obb.localBox;
auto DrawBox = [&](const Nz::Boxf& box, const Nz::Matrix4f& transformMatrix)
{
Nz::Matrix4f boxMatrix = Nz::Matrix4f::Identity();
boxMatrix.SetScale(box.GetLengths());
boxMatrix.SetTranslation(box.GetCenter());
boxMatrix.ConcatenateAffine(transformMatrix);
Nz::Matrix4f transformMatrix = instanceData.transformMatrix;
Nz::Vector3f obbCenter = transformMatrix.Transform(obb.GetCenter(), 0.f); //< Apply rotation/scale to obb center, to display it at a correct position
renderQueue->AddMesh(0, m_material, m_meshData, Nz::Boxf::Zero(), boxMatrix, scissorRect);
};
transformMatrix.ApplyScale(obb.GetLengths());
transformMatrix.ApplyTranslation(obbCenter);
renderQueue->AddMesh(0, m_material, m_meshData, Nz::Boxf::Zero(), transformMatrix, scissorRect);
for (std::size_t i = 0; i < entityGfx.GetAttachedRenderableCount(); ++i)
{
const Nz::BoundingVolumef& boundingVolume = entityGfx.GetBoundingVolume(i);
if (boundingVolume.IsFinite())
DrawBox(boundingVolume.obb.localBox, entityGfx.GetTransformMatrix(i));
}
}
std::unique_ptr<InstancedRenderable> Clone() const override
{
return nullptr;
}
private:
Nz::MaterialRef m_material;
};
}
@ -118,12 +153,174 @@ namespace Ndk
/*!
* \brief Constructs an DebugSystem object by default
*/
DebugSystem::DebugSystem()
DebugSystem::DebugSystem() :
m_isDepthBufferEnabled(true)
{
Requires<DebugComponent, GraphicsComponent>();
Requires<DebugComponent, GraphicsComponent, NodeComponent>();
SetUpdateOrder(1000); //< Update last
}
void DebugSystem::EnableDepthBuffer(bool enable)
{
m_isDepthBufferEnabled = enable;
if (m_collisionMaterial)
m_collisionMaterial->EnableDepthBuffer(enable);
if (m_globalAabbMaterial)
m_globalAabbMaterial->EnableDepthBuffer(enable);
if (m_localAabbMaterial)
m_localAabbMaterial->EnableDepthBuffer(enable);
if (m_obbMaterial)
m_obbMaterial->EnableDepthBuffer(enable);
}
Nz::InstancedRenderableRef DebugSystem::GenerateBox(Nz::Boxf box)
{
Nz::MeshRef mesh = Nz::Mesh::New();
mesh->CreateStatic();
mesh->BuildSubMesh(Nz::Primitive::Box(box.GetLengths()));
mesh->SetMaterialCount(1);
Nz::ModelRef model = Nz::Model::New();
model->SetMesh(mesh);
model->SetMaterial(0, GetOBBMaterial());
return model;
}
Nz::InstancedRenderableRef DebugSystem::GenerateCollision2DMesh(Entity* entity, Nz::Vector3f* offset)
{
if (entity->HasComponent<CollisionComponent2D>())
{
CollisionComponent2D& entityCollision = entity->GetComponent<CollisionComponent2D>();
const Nz::Collider2DRef& geom = entityCollision.GetGeom();
std::vector<Nz::Vector3f> vertices;
std::vector<std::size_t> indices;
geom->ForEachPolygon([&](const Nz::Vector2f* polygonVertices, std::size_t vertexCount)
{
std::size_t firstIndex = vertices.size();
// Don't reserve and let the vector handle its own capacity
for (std::size_t i = 0; i < vertexCount; ++i)
vertices.emplace_back(*polygonVertices++);
for (std::size_t i = 0; i < vertexCount - 1; ++i)
{
indices.push_back(firstIndex + i);
indices.push_back(firstIndex + i + 1);
}
indices.push_back(firstIndex + vertexCount - 1);
indices.push_back(firstIndex);
});
Nz::IndexBufferRef indexBuffer = Nz::IndexBuffer::New(vertices.size() > 0xFFFF, Nz::UInt32(indices.size()), Nz::DataStorage_Hardware, 0);
Nz::IndexMapper indexMapper(indexBuffer, Nz::BufferAccess_WriteOnly);
Nz::IndexIterator indexPtr = indexMapper.begin();
for (std::size_t index : indices)
*indexPtr++ = static_cast<Nz::UInt32>(index);
indexMapper.Unmap();
Nz::VertexBufferRef vertexBuffer = Nz::VertexBuffer::New(Nz::VertexDeclaration::Get(Nz::VertexLayout_XYZ), Nz::UInt32(vertices.size()), Nz::DataStorage_Hardware, 0);
vertexBuffer->Fill(vertices.data(), 0, Nz::UInt32(vertices.size()));
Nz::MeshRef mesh = Nz::Mesh::New();
mesh->CreateStatic();
Nz::StaticMeshRef subMesh = Nz::StaticMesh::New(vertexBuffer, indexBuffer);
subMesh->SetPrimitiveMode(Nz::PrimitiveMode_LineList);
subMesh->SetMaterialIndex(0);
subMesh->GenerateAABB();
mesh->SetMaterialCount(1);
mesh->AddSubMesh(subMesh);
Nz::ModelRef model = Nz::Model::New();
model->SetMesh(mesh);
model->SetMaterial(0, GetCollisionMaterial());
// Find center of mass
if (entity->HasComponent<PhysicsComponent2D>())
{
const PhysicsComponent2D& entityPhys = entity->GetComponent<PhysicsComponent2D>();
*offset = entityPhys.GetMassCenter(Nz::CoordSys_Local) + entityCollision.GetGeomOffset();
}
else
*offset = entityCollision.GetGeomOffset();
return model;
}
else
return nullptr;
}
Nz::InstancedRenderableRef DebugSystem::GenerateCollision3DMesh(Entity* entity)
{
if (entity->HasComponent<CollisionComponent3D>())
{
CollisionComponent3D& entityCollision = entity->GetComponent<CollisionComponent3D>();
const Nz::Collider3DRef& geom = entityCollision.GetGeom();
std::vector<Nz::Vector3f> vertices;
std::vector<std::size_t> indices;
geom->ForEachPolygon([&](const Nz::Vector3f* polygonVertices, std::size_t vertexCount)
{
std::size_t firstIndex = vertices.size();
vertices.resize(firstIndex + vertexCount);
std::copy(polygonVertices, polygonVertices + vertexCount, &vertices[firstIndex]);
for (std::size_t i = 0; i < vertexCount - 1; ++i)
{
indices.push_back(firstIndex + i);
indices.push_back(firstIndex + i + 1);
}
indices.push_back(firstIndex + vertexCount - 1);
indices.push_back(firstIndex);
});
Nz::IndexBufferRef indexBuffer = Nz::IndexBuffer::New(vertices.size() > 0xFFFF, Nz::UInt32(indices.size()), Nz::DataStorage_Hardware, 0);
Nz::IndexMapper indexMapper(indexBuffer, Nz::BufferAccess_WriteOnly);
Nz::IndexIterator indexPtr = indexMapper.begin();
for (std::size_t index : indices)
*indexPtr++ = static_cast<Nz::UInt32>(index);
indexMapper.Unmap();
Nz::VertexBufferRef vertexBuffer = Nz::VertexBuffer::New(Nz::VertexDeclaration::Get(Nz::VertexLayout_XYZ), Nz::UInt32(vertices.size()), Nz::DataStorage_Hardware, 0);
vertexBuffer->Fill(vertices.data(), 0, Nz::UInt32(vertices.size()));
Nz::MeshRef mesh = Nz::Mesh::New();
mesh->CreateStatic();
Nz::StaticMeshRef subMesh = Nz::StaticMesh::New(vertexBuffer, indexBuffer);
subMesh->SetPrimitiveMode(Nz::PrimitiveMode_LineList);
subMesh->SetMaterialIndex(0);
subMesh->GenerateAABB();
mesh->SetMaterialCount(1);
mesh->AddSubMesh(subMesh);
Nz::ModelRef model = Nz::Model::New();
model->SetMesh(mesh);
model->SetMaterial(0, GetCollisionMaterial());
return model;
}
else
return nullptr;
}
std::pair<Nz::IndexBufferRef, Nz::VertexBufferRef> DebugSystem::GetBoxMesh()
{
if (!m_boxMeshIndexBuffer)
@ -175,12 +372,73 @@ namespace Ndk
return { m_boxMeshIndexBuffer, m_boxMeshVertexBuffer };
}
Nz::MaterialRef DebugSystem::GetGlobalAABBMaterial()
{
if (!m_globalAabbMaterial)
{
m_globalAabbMaterial = Nz::Material::New();
m_globalAabbMaterial->EnableFaceCulling(false);
m_globalAabbMaterial->EnableDepthBuffer(true);
m_globalAabbMaterial->SetDiffuseColor(Nz::Color::Orange);
m_globalAabbMaterial->SetFaceFilling(Nz::FaceFilling_Line);
//m_globalAabbMaterial->SetLineWidth(2.f);
}
return m_globalAabbMaterial;
}
Nz::MaterialRef DebugSystem::GetLocalAABBMaterial()
{
if (!m_localAabbMaterial)
{
m_localAabbMaterial = Nz::Material::New();
m_localAabbMaterial->EnableFaceCulling(false);
m_localAabbMaterial->EnableDepthBuffer(true);
m_localAabbMaterial->SetDiffuseColor(Nz::Color::Red);
m_localAabbMaterial->SetFaceFilling(Nz::FaceFilling_Line);
//m_localAabbMaterial->SetLineWidth(2.f);
}
return m_localAabbMaterial;
}
Nz::MaterialRef DebugSystem::GetCollisionMaterial()
{
if (!m_collisionMaterial)
{
m_collisionMaterial = Nz::Material::New();
m_collisionMaterial->EnableFaceCulling(false);
m_collisionMaterial->EnableDepthBuffer(true);
m_collisionMaterial->SetDiffuseColor(Nz::Color::Blue);
m_collisionMaterial->SetFaceFilling(Nz::FaceFilling_Line);
//m_collisionMaterial->SetLineWidth(2.f);
}
return m_collisionMaterial;
}
Nz::MaterialRef DebugSystem::GetOBBMaterial()
{
if (!m_obbMaterial)
{
m_obbMaterial = Nz::Material::New();
m_obbMaterial->EnableFaceCulling(false);
m_obbMaterial->EnableDepthBuffer(true);
m_obbMaterial->SetDiffuseColor(Nz::Color::Green);
m_obbMaterial->SetFaceFilling(Nz::FaceFilling_Line);
//m_obbMaterial->SetLineWidth(2.f);
}
return m_obbMaterial;
}
void DebugSystem::OnEntityValidation(Entity* entity, bool /*justAdded*/)
{
static constexpr int DebugDrawOrder = 1'000;
DebugComponent& entityDebug = entity->GetComponent<DebugComponent>();
GraphicsComponent& entityGfx = entity->GetComponent<GraphicsComponent>();
NodeComponent& entityNode = entity->GetComponent<NodeComponent>();
DebugDrawFlags enabledFlags = entityDebug.GetEnabledFlags();
DebugDrawFlags flags = entityDebug.GetFlags();
@ -193,17 +451,24 @@ namespace Ndk
{
switch (option)
{
case DebugDraw::Collider2D:
{
Nz::Vector3f offset;
Nz::InstancedRenderableRef renderable = GenerateCollision2DMesh(entity, &offset);
if (renderable)
entityGfx.Attach(renderable, Nz::Matrix4f::Translate(offset), DebugDrawOrder);
entityDebug.UpdateDebugRenderable(option, std::move(renderable));
break;
}
case DebugDraw::Collider3D:
{
const Nz::Boxf& obb = entityGfx.GetBoundingVolume().obb.localBox;
const Nz::Boxf& obb = entityGfx.GetAABB();
Nz::InstancedRenderableRef renderable = GenerateCollision3DMesh(entity);
if (renderable)
{
renderable->SetPersistent(false);
entityGfx.Attach(renderable, Nz::Matrix4f::Translate(obb.GetCenter()), DebugDrawOrder);
}
entityGfx.Attach(renderable, Nz::Matrix4f::Translate(obb.GetCenter() - entityNode.GetPosition()), DebugDrawOrder);
entityDebug.UpdateDebugRenderable(option, std::move(renderable));
break;
@ -213,7 +478,7 @@ namespace Ndk
{
auto indexVertexBuffers = GetBoxMesh();
Nz::InstancedRenderableRef renderable = new AABBDebugRenderable(entity, GetAABBMaterial(), indexVertexBuffers.first, indexVertexBuffers.second);
Nz::InstancedRenderableRef renderable = new AABBDebugRenderable(entity, GetGlobalAABBMaterial(), GetLocalAABBMaterial(), indexVertexBuffers.first, indexVertexBuffers.second);
renderable->SetPersistent(false);
entityGfx.Attach(renderable, Nz::Matrix4f::Identity(), DebugDrawOrder);
@ -257,125 +522,5 @@ namespace Ndk
// Nothing to do
}
Nz::InstancedRenderableRef DebugSystem::GenerateBox(Nz::Boxf box)
{
Nz::MeshRef mesh = Nz::Mesh::New();
mesh->CreateStatic();
mesh->BuildSubMesh(Nz::Primitive::Box(box.GetLengths()));
mesh->SetMaterialCount(1);
Nz::ModelRef model = Nz::Model::New();
model->SetMesh(mesh);
model->SetMaterial(0, GetOBBMaterial());
return model;
}
Nz::InstancedRenderableRef DebugSystem::GenerateCollision3DMesh(Entity* entity)
{
if (entity->HasComponent<CollisionComponent3D>())
{
CollisionComponent3D& entityCollision = entity->GetComponent<CollisionComponent3D>();
const Nz::Collider3DRef& geom = entityCollision.GetGeom();
std::vector<Nz::Vector3f> vertices;
std::vector<std::size_t> indices;
geom->ForEachPolygon([&](const float* polygonVertices, std::size_t vertexCount)
{
std::size_t firstIndex = vertices.size();
for (std::size_t i = 0; i < vertexCount; ++i)
{
const float* vertexData = &polygonVertices[i * 3];
vertices.emplace_back(vertexData[0], vertexData[1], vertexData[2]);
}
for (std::size_t i = 0; i < vertexCount - 1; ++i)
{
indices.push_back(firstIndex + i);
indices.push_back(firstIndex + i + 1);
}
indices.push_back(firstIndex + vertexCount - 1);
indices.push_back(firstIndex);
});
Nz::IndexBufferRef indexBuffer = Nz::IndexBuffer::New(vertices.size() > 0xFFFF, Nz::UInt32(indices.size()), Nz::DataStorage_Hardware, 0);
Nz::IndexMapper indexMapper(indexBuffer, Nz::BufferAccess_WriteOnly);
Nz::IndexIterator indexPtr = indexMapper.begin();
for (std::size_t index : indices)
*indexPtr++ = static_cast<Nz::UInt32>(index);
indexMapper.Unmap();
Nz::VertexBufferRef vertexBuffer = Nz::VertexBuffer::New(Nz::VertexDeclaration::Get(Nz::VertexLayout_XYZ), Nz::UInt32(vertices.size()), Nz::DataStorage_Hardware, 0);
vertexBuffer->Fill(vertices.data(), 0, Nz::UInt32(vertices.size()));
Nz::MeshRef mesh = Nz::Mesh::New();
mesh->CreateStatic();
Nz::StaticMeshRef subMesh = Nz::StaticMesh::New(vertexBuffer, indexBuffer);
subMesh->SetPrimitiveMode(Nz::PrimitiveMode_LineList);
subMesh->SetMaterialIndex(0);
subMesh->GenerateAABB();
mesh->SetMaterialCount(1);
mesh->AddSubMesh(subMesh);
Nz::ModelRef model = Nz::Model::New();
model->SetMesh(mesh);
model->SetMaterial(0, GetCollisionMaterial());
return model;
}
else
return nullptr;
}
Nz::MaterialRef DebugSystem::GetAABBMaterial()
{
if (!m_aabbMaterial)
{
m_aabbMaterial = Nz::Material::New();
m_aabbMaterial->EnableFaceCulling(false);
m_aabbMaterial->EnableDepthBuffer(true);
m_aabbMaterial->SetDiffuseColor(Nz::Color::Red);
m_aabbMaterial->SetFaceFilling(Nz::FaceFilling_Line);
}
return m_aabbMaterial;
}
Nz::MaterialRef DebugSystem::GetCollisionMaterial()
{
if (!m_collisionMaterial)
{
m_collisionMaterial = Nz::Material::New();
m_collisionMaterial->EnableFaceCulling(false);
m_collisionMaterial->EnableDepthBuffer(true);
m_collisionMaterial->SetDiffuseColor(Nz::Color::Blue);
m_collisionMaterial->SetFaceFilling(Nz::FaceFilling_Line);
}
return m_collisionMaterial;
}
Nz::MaterialRef DebugSystem::GetOBBMaterial()
{
if (!m_obbMaterial)
{
m_obbMaterial = Nz::Material::New();
m_obbMaterial->EnableFaceCulling(false);
m_obbMaterial->EnableDepthBuffer(true);
m_obbMaterial->SetDiffuseColor(Nz::Color::Green);
m_obbMaterial->SetFaceFilling(Nz::FaceFilling_Line);
}
return m_obbMaterial;
}
SystemIndex DebugSystem::systemIndex;
}

View File

@ -0,0 +1,27 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
#include <NDK/Systems/LifetimeSystem.hpp>
#include <NDK/Components/LifetimeComponent.hpp>
namespace Ndk
{
LifetimeSystem::LifetimeSystem()
{
Requires<LifetimeComponent>();
}
void LifetimeSystem::OnUpdate(float elapsedTime)
{
for (const Ndk::EntityHandle& entity : GetEntities())
{
auto& lifetime = entity->GetComponent<LifetimeComponent>();
if (lifetime.UpdateLifetime(elapsedTime))
entity->Kill();
}
}
SystemIndex LifetimeSystem::systemIndex;
}

View File

@ -4,6 +4,7 @@
#include <NDK/Systems/PhysicsSystem2D.hpp>
#include <Nazara/Physics2D/RigidBody2D.hpp>
#include <NDK/World.hpp>
#include <NDK/Components/CollisionComponent2D.hpp>
#include <NDK/Components/NodeComponent.hpp>
#include <NDK/Components/PhysicsComponent2D.hpp>
@ -33,9 +34,135 @@ namespace Ndk
void PhysicsSystem2D::CreatePhysWorld() const
{
NazaraAssert(!m_world, "Physics world should not be created twice");
NazaraAssert(!m_physWorld, "Physics world should not be created twice");
m_world = std::make_unique<Nz::PhysWorld2D>();
m_physWorld = std::make_unique<Nz::PhysWorld2D>();
}
void PhysicsSystem2D::DebugDraw(const DebugDrawOptions& options, bool drawShapes, bool drawConstraints, bool drawCollisions)
{
Nz::PhysWorld2D::DebugDrawOptions worldOptions{ options.constraintColor, options.collisionPointColor, options.shapeOutlineColor };
if (options.colorCallback)
{
worldOptions.colorCallback = [&options, this](Nz::RigidBody2D& body, std::size_t shapeIndex, void* userdata)
{
return options.colorCallback(GetEntityFromBody(body), shapeIndex, userdata);
};
}
worldOptions.circleCallback = options.circleCallback;
worldOptions.dotCallback = options.dotCallback;
worldOptions.polygonCallback = options.polygonCallback;
worldOptions.segmentCallback = options.segmentCallback;
worldOptions.thickSegmentCallback = options.thickSegmentCallback;
worldOptions.userdata = options.userdata;
GetPhysWorld().DebugDraw(worldOptions, drawShapes, drawConstraints, drawCollisions);
}
const EntityHandle& PhysicsSystem2D::GetEntityFromBody(const Nz::RigidBody2D& body) const
{
auto entityId = static_cast<EntityId>(reinterpret_cast<std::uintptr_t>(body.GetUserdata()));
auto& world = GetWorld();
NazaraAssert(world.IsEntityIdValid(entityId), "All Bodies of this world must be part of the physics world by using PhysicsComponent");
return world.GetEntity(entityId);
}
bool PhysicsSystem2D::NearestBodyQuery(const Nz::Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, EntityHandle* nearestBody)
{
Nz::RigidBody2D* body;
bool res = GetPhysWorld().NearestBodyQuery(from, maxDistance, collisionGroup, categoryMask, collisionMask, &body);
(*nearestBody) = GetEntityFromBody(*body);
return res;
}
bool PhysicsSystem2D::NearestBodyQuery(const Nz::Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, NearestQueryResult* result)
{
Nz::PhysWorld2D::NearestQueryResult queryResult;
if (GetPhysWorld().NearestBodyQuery(from, maxDistance, collisionGroup, categoryMask, collisionMask, &queryResult))
{
result->nearestBody = GetEntityFromBody(*queryResult.nearestBody);
result->closestPoint = std::move(queryResult.closestPoint);
result->fraction = std::move(queryResult.fraction);
result->distance = queryResult.distance;
return true;
}
else
return false;
}
void PhysicsSystem2D::RaycastQuery(const Nz::Vector2f & from, const Nz::Vector2f & to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, const std::function<void(const RaycastHit&)>& callback)
{
return GetPhysWorld().RaycastQuery(from, to, radius, collisionGroup, categoryMask, collisionMask, [this, &callback](const Nz::PhysWorld2D::RaycastHit& hitInfo)
{
callback({
GetEntityFromBody(*hitInfo.nearestBody),
hitInfo.hitPos,
hitInfo.hitNormal,
hitInfo.fraction
});
});
}
bool PhysicsSystem2D::RaycastQuery(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector<RaycastHit>* hitInfos)
{
std::vector<Nz::PhysWorld2D::RaycastHit> queryResult;
bool res = GetPhysWorld().RaycastQuery(from, to, radius, collisionGroup, categoryMask, collisionMask, &queryResult);
for (auto& hitResult : queryResult)
{
hitInfos->push_back({
GetEntityFromBody(*hitResult.nearestBody),
std::move(hitResult.hitPos),
std::move(hitResult.hitNormal),
hitResult.fraction
});
}
return res;
}
bool PhysicsSystem2D::RaycastQueryFirst(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, RaycastHit* hitInfo)
{
Nz::PhysWorld2D::RaycastHit queryResult;
if (GetPhysWorld().RaycastQueryFirst(from, to, radius, collisionGroup, categoryMask, collisionMask, &queryResult))
{
hitInfo->body = GetEntityFromBody(*queryResult.nearestBody);
hitInfo->hitPos = std::move(queryResult.hitPos);
hitInfo->hitNormal = std::move(queryResult.hitNormal);
hitInfo->fraction = queryResult.fraction;
return true;
}
else
return false;
}
void PhysicsSystem2D::RegionQuery(const Nz::Rectf& boundingBox, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, const std::function<void(const EntityHandle&)>& callback)
{
return GetPhysWorld().RegionQuery(boundingBox, collisionGroup, categoryMask, collisionMask, [this, &callback](Nz::RigidBody2D* body)
{
callback(GetEntityFromBody(*body));
});
}
void PhysicsSystem2D::RegionQuery(const Nz::Rectf& boundingBox, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector<EntityHandle>* bodies)
{
std::vector<Nz::RigidBody2D*> queryResult;
GetPhysWorld().RegionQuery(boundingBox, collisionGroup, categoryMask, collisionMask, &queryResult);
for (auto& body : queryResult)
{
bodies->emplace_back(GetEntityFromBody(*body));
}
}
/*!
@ -47,18 +174,34 @@ namespace Ndk
void PhysicsSystem2D::OnEntityValidation(Entity* entity, bool justAdded)
{
// It's possible our entity got revalidated because of the addition/removal of a PhysicsComponent3D
if (!justAdded)
if (entity->HasComponent<PhysicsComponent2D>())
{
// We take the opposite array from which the entity should belong to
auto& entities = (entity->HasComponent<PhysicsComponent2D>()) ? m_staticObjects : m_dynamicObjects;
entities.Remove(entity);
if (entity->GetComponent<PhysicsComponent2D>().IsNodeSynchronizationEnabled())
m_dynamicObjects.Insert(entity);
else
m_dynamicObjects.Remove(entity);
m_staticObjects.Remove(entity);
}
else
{
m_dynamicObjects.Remove(entity);
m_staticObjects.Insert(entity);
// If entities just got added to the system, teleport them to their NodeComponent position/rotation
// This will prevent the physics engine to mess with the scene while correcting position/rotation
if (justAdded)
{
auto& collision = entity->GetComponent<CollisionComponent2D>();
auto& node = entity->GetComponent<NodeComponent>();
Nz::RigidBody2D* physObj = collision.GetStaticBody();
physObj->SetPosition(Nz::Vector2f(node.GetPosition(Nz::CoordSys_Global)));
//physObj->SetRotation(node.GetRotation());
}
}
auto& entities = (entity->HasComponent<PhysicsComponent2D>()) ? m_dynamicObjects : m_staticObjects;
entities.Insert(entity);
if (!m_world)
if (!m_physWorld)
CreatePhysWorld();
}
@ -70,10 +213,10 @@ namespace Ndk
void PhysicsSystem2D::OnUpdate(float elapsedTime)
{
if (!m_world)
if (!m_physWorld)
return;
m_world->Step(elapsedTime);
m_physWorld->Step(elapsedTime);
for (const Ndk::EntityHandle& entity : m_dynamicObjects)
{
@ -81,7 +224,7 @@ namespace Ndk
PhysicsComponent2D& phys = entity->GetComponent<PhysicsComponent2D>();
Nz::RigidBody2D* body = phys.GetRigidBody();
node.SetRotation(Nz::EulerAnglesf(0.f, 0.f, body->GetRotation()), Nz::CoordSys_Global);
node.SetRotation(body->GetRotation(), Nz::CoordSys_Global);
node.SetPosition(Nz::Vector3f(body->GetPosition(), node.GetPosition(Nz::CoordSys_Global).z), Nz::CoordSys_Global);
}
@ -97,7 +240,7 @@ namespace Ndk
Nz::Vector2f newPosition = Nz::Vector2f(node.GetPosition(Nz::CoordSys_Global));
// To move static objects and ensure their collisions, we have to specify them a velocity
// (/!\: the physical motor does not apply the speed on static objects)
// (/!\: the physical engine does not apply the speed on static objects)
if (newPosition != oldPosition)
{
body->SetPosition(newPosition);
@ -106,8 +249,7 @@ namespace Ndk
else
body->SetVelocity(Nz::Vector2f::Zero());
/*
if (newRotation != oldRotation)
/*if (newRotation != oldRotation)
{
Nz::Quaternionf transition = newRotation * oldRotation.GetConjugate();
Nz::EulerAnglesf angles = transition.ToEulerAngles();
@ -119,10 +261,91 @@ namespace Ndk
physObj->SetAngularVelocity(angularVelocity);
}
else
physObj->SetAngularVelocity(Nz::Vector3f::Zero());
*/
physObj->SetAngularVelocity(Nz::Vector3f::Zero());*/
}
}
void PhysicsSystem2D::RegisterCallbacks(unsigned int collisionId, Callback callbacks)
{
Nz::PhysWorld2D::Callback worldCallbacks;
if (callbacks.endCallback)
{
worldCallbacks.endCallback = [this, cb = std::move(callbacks.endCallback)](Nz::PhysWorld2D& world, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
{
cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
};
}
if (callbacks.preSolveCallback)
{
worldCallbacks.preSolveCallback = [this, cb = std::move(callbacks.preSolveCallback)](Nz::PhysWorld2D& world, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
{
return cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
};
}
if (callbacks.postSolveCallback)
{
worldCallbacks.postSolveCallback = [this, cb = std::move(callbacks.postSolveCallback)](Nz::PhysWorld2D& world, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
{
cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
};
}
if (callbacks.startCallback)
{
worldCallbacks.startCallback = [this, cb = std::move(callbacks.startCallback)](Nz::PhysWorld2D& world, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
{
return cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
};
}
worldCallbacks.userdata = callbacks.userdata;
m_physWorld->RegisterCallbacks(collisionId, worldCallbacks);
}
void PhysicsSystem2D::RegisterCallbacks(unsigned int collisionIdA, unsigned int collisionIdB, Callback callbacks)
{
Nz::PhysWorld2D::Callback worldCallbacks;
if (callbacks.endCallback)
{
worldCallbacks.endCallback = [this, cb = std::move(callbacks.endCallback)](Nz::PhysWorld2D& world, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
{
cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
};
}
if (callbacks.preSolveCallback)
{
worldCallbacks.preSolveCallback = [this, cb = std::move(callbacks.preSolveCallback)](Nz::PhysWorld2D& world, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
{
return cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
};
}
if (callbacks.postSolveCallback)
{
worldCallbacks.postSolveCallback = [this, cb = std::move(callbacks.postSolveCallback)](Nz::PhysWorld2D& world, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
{
cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
};
}
if (callbacks.startCallback)
{
worldCallbacks.startCallback = [this, cb = std::move(callbacks.startCallback)](Nz::PhysWorld2D& world, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
{
return cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
};
}
worldCallbacks.userdata = callbacks.userdata;
m_physWorld->RegisterCallbacks(collisionIdA, collisionIdB, worldCallbacks);
}
SystemIndex PhysicsSystem2D::systemIndex;
}

View File

@ -69,8 +69,8 @@ namespace Ndk
auto& node = entity->GetComponent<NodeComponent>();
Nz::RigidBody3D* physObj = collision.GetStaticBody();
physObj->SetPosition(node.GetPosition());
physObj->SetRotation(node.GetRotation());
physObj->SetPosition(node.GetPosition(Nz::CoordSys_Global));
physObj->SetRotation(node.GetRotation(Nz::CoordSys_Global));
}
}

Some files were not shown because too many files have changed in this diff Show More