first commit
This commit is contained in:
commit
9080d88f6f
|
|
@ -0,0 +1,396 @@
|
||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
##
|
||||||
|
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Mono auto generated files
|
||||||
|
mono_crash.*
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
#[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Oo]ut/
|
||||||
|
[Ll]og/
|
||||||
|
[Ll]ogs/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUnit
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
nunit-*.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Coverlet is a free, cross platform Code Coverage Tool
|
||||||
|
coverage*.json
|
||||||
|
coverage*.xml
|
||||||
|
coverage*.info
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# NuGet Symbol Packages
|
||||||
|
*.snupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
*.appxbundle
|
||||||
|
*.appxupload
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!?*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Including strong name files can present a security risk
|
||||||
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
*- [Bb]ackup.rdl
|
||||||
|
*- [Bb]ackup ([0-9]).rdl
|
||||||
|
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# OpenCover UI analysis results
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# Azure Stream Analytics local run output
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# NVidia Nsight GPU debugger configuration file
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# Local History for Visual Studio
|
||||||
|
.localhistory/
|
||||||
|
|
||||||
|
# BeatPulse healthcheck temp database
|
||||||
|
healthchecksdb
|
||||||
|
|
||||||
|
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||||
|
MigrationBackup/
|
||||||
|
|
||||||
|
# Ionide (cross platform F# VS Code tools) working folder
|
||||||
|
.ionide/
|
||||||
|
|
||||||
|
# Fody - auto-generated XML schema
|
||||||
|
FodyWeavers.xsd
|
||||||
|
|
||||||
|
intermediate-files/
|
||||||
|
|
||||||
|
.cache/
|
||||||
|
.vscode/
|
||||||
|
*.json
|
||||||
|
*.make
|
||||||
|
Makefile
|
||||||
|
*.sublime-*
|
||||||
|
|
||||||
|
*.vcxproj
|
||||||
|
|
||||||
|
*.sln
|
||||||
|
|
||||||
|
*.vcxproj.filters
|
||||||
|
|
||||||
|
*.code-workspace
|
||||||
|
|
||||||
|
*.o
|
||||||
|
|
||||||
|
*.d
|
||||||
|
|
||||||
|
*.ninja*
|
||||||
|
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
Engine-Core/lib
|
||||||
|
Engine-Core/intermediate-files
|
||||||
|
Editor/bin
|
||||||
|
Editor/intermediate-files
|
||||||
|
Game/bin
|
||||||
|
|
||||||
|
imgui.ini
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
.\vendor\premake5\premake5.exe vs2022
|
||||||
|
PAUSE
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025 Joseph Aquino
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,93 @@
|
||||||
|
Copyright 2018 The Chakra Petch Project Authors (https://github.com/m4rc1e/Chakra-Petch.git)
|
||||||
|
|
||||||
|
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:
|
||||||
|
https://openfontlicense.org
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
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.
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
#! /bin/bash
|
||||||
|
|
||||||
|
./vendor/premake5/premake5 ninja
|
||||||
|
ninja $1
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
#! /bin/bash
|
||||||
|
|
||||||
|
./vendor/premake5/premake5 gmake
|
||||||
|
make config=$1
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
#! /bin/bash
|
||||||
|
if [ -z "$1" ] || [ $# -eq 0 ]
|
||||||
|
then
|
||||||
|
ninja -t clean
|
||||||
|
else
|
||||||
|
ninja -t clean $1
|
||||||
|
fi
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
#! /bin/bash
|
||||||
|
if [ -z "$1" ] || [ $# -eq 0 ]
|
||||||
|
then
|
||||||
|
make config=Debug clean && make config=Release clean
|
||||||
|
else
|
||||||
|
make config=$1 clean
|
||||||
|
fi
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
framerate 60
|
||||||
|
|
||||||
|
playerColor 1 1 1
|
||||||
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
#! /bin/bash
|
||||||
|
if [ -z "$1" ] || [ $# -eq 0 ]
|
||||||
|
then
|
||||||
|
./vendor/premake5/premake5 --config=Debug ecc
|
||||||
|
else
|
||||||
|
./vendor/premake5/premake5 --config=$1 ecc
|
||||||
|
fi
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SFML/Graphics.hpp>
|
||||||
|
|
||||||
|
struct Color
|
||||||
|
{
|
||||||
|
Color() = default;
|
||||||
|
Color(float r_in, float g_in, float b_in, float a_in);
|
||||||
|
|
||||||
|
Color(sf::Color color_in);
|
||||||
|
|
||||||
|
sf::Color sfml();
|
||||||
|
|
||||||
|
float* imgui();
|
||||||
|
|
||||||
|
float r{};
|
||||||
|
float g{};
|
||||||
|
float b{};
|
||||||
|
float a{1.f};
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <Util.h>
|
||||||
|
|
||||||
|
#include <SFML/Graphics.hpp>
|
||||||
|
#include <SFML/Audio.hpp>
|
||||||
|
#include <imgui-SFML.h>
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
|
||||||
|
class SnakeNode
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Player
|
||||||
|
{
|
||||||
|
Player() = default;
|
||||||
|
Player(sf::Vector2i gridPos_in);
|
||||||
|
|
||||||
|
sf::Vector2i gridPos{};
|
||||||
|
sf::Vector2i previousGridPos{};
|
||||||
|
sf::Vector2f windowPos{};
|
||||||
|
int score{};
|
||||||
|
int lives{3};
|
||||||
|
bool left{false};
|
||||||
|
bool right{false};
|
||||||
|
bool up{false};
|
||||||
|
bool down{false};
|
||||||
|
};
|
||||||
|
|
||||||
|
class Game
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Game(bool useImgui_in);
|
||||||
|
|
||||||
|
void run();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void imgui();
|
||||||
|
|
||||||
|
void render();
|
||||||
|
|
||||||
|
void input();
|
||||||
|
|
||||||
|
void collision();
|
||||||
|
|
||||||
|
void movement();
|
||||||
|
|
||||||
|
void resetGame();
|
||||||
|
|
||||||
|
bool parseConfigFile();
|
||||||
|
|
||||||
|
void soundSystem();
|
||||||
|
|
||||||
|
void scoreSystem();
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
sf::Clock clock;
|
||||||
|
sf::RenderWindow window;
|
||||||
|
sf::Font font;
|
||||||
|
sf::Text lives;
|
||||||
|
sf::Text score;
|
||||||
|
|
||||||
|
Player player;
|
||||||
|
|
||||||
|
// mostly used for imgui
|
||||||
|
int framerate{};
|
||||||
|
float volume{};
|
||||||
|
bool useImgui;
|
||||||
|
static constexpr unsigned int numPhysicsUpdates{4};
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
namespace Math
|
||||||
|
{
|
||||||
|
template<typename T, typename U, typename V>
|
||||||
|
inline T max(U first, V second)
|
||||||
|
{
|
||||||
|
return static_cast<T>(static_cast<T>(first) >= static_cast<T>(second) ? first : second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef RANDOM_MT_H
|
||||||
|
#define RANDOM_MT_H
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
// This header-only Random namespace implements a self-seeding Mersenne Twister.
|
||||||
|
// Requires C++17 or newer.
|
||||||
|
// It can be #included into as many code files as needed (The inline keyword avoids ODR violations)
|
||||||
|
// Freely redistributable, courtesy of learncpp.com (https://www.learncpp.com/cpp-tutorial/global-random-numbers-random-h/)
|
||||||
|
namespace Random
|
||||||
|
{
|
||||||
|
// Returns a seeded Mersenne Twister
|
||||||
|
// Note: we'd prefer to return a std::seed_seq (to initialize a std::mt19937), but std::seed can't be copied, so it can't be returned by value.
|
||||||
|
// Instead, we'll create a std::mt19937, seed it, and then return the std::mt19937 (which can be copied).
|
||||||
|
inline std::mt19937 generate()
|
||||||
|
{
|
||||||
|
std::random_device rd{};
|
||||||
|
|
||||||
|
// Create seed_seq with clock and 7 random numbers from std::random_device
|
||||||
|
std::seed_seq ss{
|
||||||
|
static_cast<std::seed_seq::result_type>(std::chrono::steady_clock::now().time_since_epoch().count()),
|
||||||
|
rd(), rd(), rd(), rd(), rd(), rd(), rd() };
|
||||||
|
|
||||||
|
return std::mt19937{ ss };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Here's our global std::mt19937 object.
|
||||||
|
// The inline keyword means we only have one global instance for our whole program.
|
||||||
|
inline std::mt19937 mt{ generate() }; // generates a seeded std::mt19937 and copies it into our global object
|
||||||
|
|
||||||
|
// Generate a random int between [min, max] (inclusive)
|
||||||
|
// * also handles cases where the two arguments have different types but can be converted to int
|
||||||
|
inline int get(int min, int max)
|
||||||
|
{
|
||||||
|
return std::uniform_int_distribution{min, max}(mt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following function templates can be used to generate random numbers in other cases
|
||||||
|
|
||||||
|
// See https://www.learncpp.com/cpp-tutorial/function-template-instantiation/
|
||||||
|
// You can ignore these if you don't understand them
|
||||||
|
|
||||||
|
// Generate a random value between [min, max] (inclusive)
|
||||||
|
// * min and max must have the same type
|
||||||
|
// * return value has same type as min and max
|
||||||
|
// * Supported types:
|
||||||
|
// * short, int, long, long long
|
||||||
|
// * unsigned short, unsigned int, unsigned long, or unsigned long long
|
||||||
|
// Sample call: Random::get(1L, 6L); // returns long
|
||||||
|
// Sample call: Random::get(1u, 6u); // returns unsigned int
|
||||||
|
template <typename T>
|
||||||
|
T get(T min, T max)
|
||||||
|
{
|
||||||
|
return std::uniform_int_distribution<T>{min, max}(mt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a random value between [min, max] (inclusive)
|
||||||
|
// * min and max can have different types
|
||||||
|
// * return type must be explicitly specified as a template argument
|
||||||
|
// * min and max will be converted to the return type
|
||||||
|
// Sample call: Random::get<std::size_t>(0, 6); // returns std::size_t
|
||||||
|
// Sample call: Random::get<std::size_t>(0, 6u); // returns std::size_t
|
||||||
|
// Sample call: Random::get<std::int>(0, 6u); // returns int
|
||||||
|
template <typename R, typename S, typename T>
|
||||||
|
R get(S min, T max)
|
||||||
|
{
|
||||||
|
return get<R>(static_cast<R>(min), static_cast<R>(max));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Random.h>
|
||||||
|
#include <Color.h>
|
||||||
|
#include <Math-util.h>
|
||||||
|
|
@ -0,0 +1,154 @@
|
||||||
|
require "ecc/ecc"
|
||||||
|
require "ninja/ninja"
|
||||||
|
|
||||||
|
workspace "snake"
|
||||||
|
architecture "x64"
|
||||||
|
|
||||||
|
output_dir = "%{cfg.buildcfg}-%{cfg.system}-%{cfg.architecture}"
|
||||||
|
vs_intdir = "!$(SolutionDir)intermediate-files/" .. output_dir
|
||||||
|
intdir = "%{wks.location}/intermediate-files/" .. output_dir
|
||||||
|
vs_bindir = "$(SolutionDir)bin/" .. output_dir
|
||||||
|
bindir = "%{wks.location}/bin/" .. output_dir
|
||||||
|
vs_coreinclude_dir = "$(SolutionDir)include"
|
||||||
|
vs_sfmldir = "$(SolutionDir)vendor/SFML"
|
||||||
|
sfmldir = "%{wks.location}/vendor/SFML"
|
||||||
|
vs_imguidir = "$(SolutionDir)vendor/imgui"
|
||||||
|
imguidir = "%{wks.location}/vendor/imgui"
|
||||||
|
vs_include_dir = "$(SolutionDir)include"
|
||||||
|
include_dir = "%{wks.location}/include"
|
||||||
|
|
||||||
|
configurations
|
||||||
|
{
|
||||||
|
"Debug",
|
||||||
|
"Release"
|
||||||
|
}
|
||||||
|
|
||||||
|
project "snake"
|
||||||
|
language "C++"
|
||||||
|
cppdialect "C++20"
|
||||||
|
systemversion "latest"
|
||||||
|
kind "WindowedApp"
|
||||||
|
targetname "snake"
|
||||||
|
|
||||||
|
files
|
||||||
|
{
|
||||||
|
"src/**.cpp",
|
||||||
|
"include/**.h",
|
||||||
|
"include/**.hpp",
|
||||||
|
"vendor/imgui/imgui.cpp",
|
||||||
|
"vendor/imgui/imgui_draw.cpp",
|
||||||
|
"vendor/imgui/imgui_tables.cpp",
|
||||||
|
"vendor/imgui/imgui_widgets.cpp",
|
||||||
|
"vendor/imgui/imgui-SFML.cpp"
|
||||||
|
}
|
||||||
|
|
||||||
|
--visual studio--
|
||||||
|
filter {"action:vs*", "system:windows"}
|
||||||
|
targetdir (vs_bindir)
|
||||||
|
objdir (vs_intdir)
|
||||||
|
debugdir "$(SolutionDir)"
|
||||||
|
includedirs
|
||||||
|
{
|
||||||
|
"src",
|
||||||
|
vs_include_dir,
|
||||||
|
vs_sfmldir .. "/include",
|
||||||
|
vs_imguidir
|
||||||
|
}
|
||||||
|
|
||||||
|
libdirs {vs_sfmldir .."/lib"}
|
||||||
|
|
||||||
|
--not visual studio --
|
||||||
|
filter {"not action:vs*", "system:windows"}
|
||||||
|
targetdir (bindir)
|
||||||
|
objdir (intdir)
|
||||||
|
debugdir "%{wks.location}"
|
||||||
|
includedirs
|
||||||
|
{
|
||||||
|
"src",
|
||||||
|
include_dir,
|
||||||
|
sfmldir .. "/include",
|
||||||
|
imguidir
|
||||||
|
}
|
||||||
|
|
||||||
|
libdirs {sfmldir .."/lib"}
|
||||||
|
|
||||||
|
--windows specific settings--
|
||||||
|
filter{"system:windows"}
|
||||||
|
defines {"PLATFORM_WINDOWS", "SFML_STATIC"}
|
||||||
|
staticruntime "on"
|
||||||
|
|
||||||
|
filter {"system:windows", "configurations:debug"}
|
||||||
|
defines{"_DEBUG", "_CONSOLE"}
|
||||||
|
links
|
||||||
|
{
|
||||||
|
"sfml-main-d",
|
||||||
|
"sfml-graphics-s-d",
|
||||||
|
"sfml-window-s-d",
|
||||||
|
"opengl32",
|
||||||
|
"gdi32",
|
||||||
|
"freetyped",
|
||||||
|
"sfml-audio-s-d",
|
||||||
|
"flacd",
|
||||||
|
"vorbisfiled",
|
||||||
|
"vorbisd",
|
||||||
|
"oggd",
|
||||||
|
"sfml-system-s-d",
|
||||||
|
"winmm"
|
||||||
|
}
|
||||||
|
|
||||||
|
filter {"system:windows", "configurations:release"}
|
||||||
|
defines{"NDEBUG"}
|
||||||
|
links
|
||||||
|
{
|
||||||
|
"sfml-main",
|
||||||
|
"sfml-graphics-s",
|
||||||
|
"sfml-window-s",
|
||||||
|
"opengl32",
|
||||||
|
"gdi32",
|
||||||
|
"freetype",
|
||||||
|
"sfml-audio-s",
|
||||||
|
"flac",
|
||||||
|
"vorbisfile",
|
||||||
|
"vorbis",
|
||||||
|
"ogg",
|
||||||
|
"sfml-system-s",
|
||||||
|
"winmm"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
--linux specific settings--
|
||||||
|
filter {"system:linux"}
|
||||||
|
defines {"PLATFORM_LINUX"}
|
||||||
|
targetdir (bindir)
|
||||||
|
objdir (intdir)
|
||||||
|
debugdir "%{wks.location}"
|
||||||
|
includedirs
|
||||||
|
{
|
||||||
|
"src",
|
||||||
|
include_dir,
|
||||||
|
imguidir
|
||||||
|
}
|
||||||
|
|
||||||
|
links
|
||||||
|
{
|
||||||
|
"sfml-graphics",
|
||||||
|
"sfml-window",
|
||||||
|
"sfml-audio",
|
||||||
|
"sfml-system",
|
||||||
|
"OpenGL",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
--config settings--
|
||||||
|
filter "configurations:debug"
|
||||||
|
defines {"LOG_ENABLE", "GAME_DEBUG"}
|
||||||
|
symbols "on"
|
||||||
|
runtime "Debug"
|
||||||
|
warnings "Extra"
|
||||||
|
|
||||||
|
filter "configurations:release"
|
||||||
|
defines {"GAME_RELEASE"}
|
||||||
|
optimize "Speed"
|
||||||
|
inlining "Auto"
|
||||||
|
symbols "off"
|
||||||
|
runtime "Release"
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
#include <Color.h>
|
||||||
|
|
||||||
|
#include <SFML/Graphics.hpp>
|
||||||
|
|
||||||
|
Color::Color(float r_in, float g_in, float b_in, float a_in = 1.0f)
|
||||||
|
: r(r_in)
|
||||||
|
, g(g_in)
|
||||||
|
, b(b_in)
|
||||||
|
, a(a_in)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
Color::Color(sf::Color color_in)
|
||||||
|
: r(color_in.r / 255.f)
|
||||||
|
, g(color_in.g / 255.f)
|
||||||
|
, b(color_in.b / 255.f)
|
||||||
|
, a(color_in.a / 255.f)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
sf::Color Color::sfml()
|
||||||
|
{
|
||||||
|
return sf::Color{uint8_t(r * 255), uint8_t(g * 255), uint8_t(b * 255), uint8_t(a * 255)};
|
||||||
|
}
|
||||||
|
|
||||||
|
float* Color::imgui()
|
||||||
|
{
|
||||||
|
return &r;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,221 @@
|
||||||
|
#include <Game.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <Util.h>
|
||||||
|
|
||||||
|
#include <SFML/Graphics.hpp>
|
||||||
|
#include <imgui-SFML.h>
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
|
Game::Game(bool useImgui_in)
|
||||||
|
: window({sf::VideoMode({ 1920u, 1080u }), "project-breakout"})
|
||||||
|
, font("assets/fonts/ChakraPetch-Regular.ttf")
|
||||||
|
, lives(font)
|
||||||
|
, score(font)
|
||||||
|
, volume(10)
|
||||||
|
, useImgui(useImgui_in)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!ImGui::SFML::Init(window)) return;
|
||||||
|
|
||||||
|
if (!parseConfigFile()) return;
|
||||||
|
|
||||||
|
lives.setPosition({10, static_cast<float>(window.getSize().y - 40)});
|
||||||
|
score.setPosition({10, static_cast<float>(window.getSize().y - 80)});
|
||||||
|
|
||||||
|
window.setFramerateLimit(framerate);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Game::parseConfigFile()
|
||||||
|
{
|
||||||
|
std::ifstream configFile{"config/game-config.txt"};
|
||||||
|
|
||||||
|
if(!configFile)
|
||||||
|
{
|
||||||
|
std::cerr << "ERROR: CANNOT OPEN 'game-config.txt'\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string inputBuff;
|
||||||
|
while(configFile >> inputBuff)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::input()
|
||||||
|
{
|
||||||
|
while (const std::optional event = window.pollEvent())
|
||||||
|
{
|
||||||
|
ImGui::SFML::ProcessEvent(window, *event);
|
||||||
|
|
||||||
|
if (event->is<sf::Event::Closed>())
|
||||||
|
{
|
||||||
|
window.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const auto* keyPressed = event->getIf<sf::Event::KeyPressed>())
|
||||||
|
{
|
||||||
|
switch (keyPressed->scancode)
|
||||||
|
{
|
||||||
|
case sf::Keyboard::Scan::Escape:
|
||||||
|
window.close();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sf::Keyboard::Scan::Left:
|
||||||
|
case sf::Keyboard::Scan::A:
|
||||||
|
player.left = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sf::Keyboard::Scan::Right:
|
||||||
|
case sf::Keyboard::Scan::D:
|
||||||
|
player.right = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sf::Keyboard::Scan::Up:
|
||||||
|
case sf::Keyboard::Scan::W:
|
||||||
|
player.up = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sf::Keyboard::Scan::Down:
|
||||||
|
case sf::Keyboard::Scan::S:
|
||||||
|
player.down = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sf::Keyboard::Scan::R:
|
||||||
|
resetGame();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const auto* keyReleased = event->getIf<sf::Event::KeyReleased>())
|
||||||
|
{
|
||||||
|
switch (keyReleased->scancode)
|
||||||
|
{
|
||||||
|
case sf::Keyboard::Scan::Left:
|
||||||
|
case sf::Keyboard::Scan::A:
|
||||||
|
player.left = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sf::Keyboard::Scan::Right:
|
||||||
|
case sf::Keyboard::Scan::D:
|
||||||
|
player.right = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sf::Keyboard::Scan::Up:
|
||||||
|
case sf::Keyboard::Scan::W:
|
||||||
|
player.up = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sf::Keyboard::Scan::Down:
|
||||||
|
case sf::Keyboard::Scan::S:
|
||||||
|
player.down = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::collision()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::movement()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::imgui()
|
||||||
|
{
|
||||||
|
ImGui::SetNextWindowCollapsed(false, ImGuiCond_Once);
|
||||||
|
ImGui::SetNextWindowSize({490,375}, ImGuiCond_Once);
|
||||||
|
ImGui::SetNextWindowPos({26,29}, ImGuiCond_Once);
|
||||||
|
if(!ImGui::Begin("menu"))
|
||||||
|
{
|
||||||
|
ImGui::End();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ImGui::Text("Controls:");
|
||||||
|
ImGui::Indent();
|
||||||
|
ImGui::Text("A/D or arrow keys: move left and right");
|
||||||
|
ImGui::Text("R: reset game");
|
||||||
|
ImGui::Unindent();
|
||||||
|
|
||||||
|
if (ImGui::SliderFloat("Game Volume", &volume, 0, 100, "%.1f"))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::render()
|
||||||
|
{
|
||||||
|
window.clear();
|
||||||
|
|
||||||
|
lives.setString("Lives: " + std::to_string(player.lives));
|
||||||
|
score.setString("Score: " + std::to_string(player.score));
|
||||||
|
|
||||||
|
window.draw(lives);
|
||||||
|
window.draw(score);
|
||||||
|
|
||||||
|
ImGui::SFML::Render(window);
|
||||||
|
|
||||||
|
window.display();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::soundSystem()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::scoreSystem()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::resetGame()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::run()
|
||||||
|
{
|
||||||
|
while(window.isOpen())
|
||||||
|
{
|
||||||
|
ImGui::SFML::Update(window, clock.restart());
|
||||||
|
|
||||||
|
input();
|
||||||
|
|
||||||
|
movement();
|
||||||
|
|
||||||
|
collision();
|
||||||
|
|
||||||
|
soundSystem();
|
||||||
|
|
||||||
|
scoreSystem();
|
||||||
|
|
||||||
|
imgui();
|
||||||
|
|
||||||
|
render();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SFML::Shutdown();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
#include <Game.h>
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
// parse command-line arguments
|
||||||
|
bool useImgui{true};
|
||||||
|
for (int i = 0; i < argc; i++)
|
||||||
|
{
|
||||||
|
if (!strcmp(argv[i], "--noImgui"))
|
||||||
|
{
|
||||||
|
useImgui = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Game game(useImgui);
|
||||||
|
|
||||||
|
game.run();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <SFML/Audio/InputSoundFile.hpp>
|
||||||
|
#include <SFML/Audio/Listener.hpp>
|
||||||
|
#include <SFML/Audio/Music.hpp>
|
||||||
|
#include <SFML/Audio/OutputSoundFile.hpp>
|
||||||
|
#include <SFML/Audio/PlaybackDevice.hpp>
|
||||||
|
#include <SFML/Audio/Sound.hpp>
|
||||||
|
#include <SFML/Audio/SoundBuffer.hpp>
|
||||||
|
#include <SFML/Audio/SoundBufferRecorder.hpp>
|
||||||
|
#include <SFML/Audio/SoundFileFactory.hpp>
|
||||||
|
#include <SFML/Audio/SoundFileReader.hpp>
|
||||||
|
#include <SFML/Audio/SoundFileWriter.hpp>
|
||||||
|
#include <SFML/Audio/SoundRecorder.hpp>
|
||||||
|
#include <SFML/Audio/SoundSource.hpp>
|
||||||
|
#include <SFML/Audio/SoundStream.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \defgroup audio Audio module
|
||||||
|
///
|
||||||
|
/// Sounds, streaming (musics or custom sources), recording,
|
||||||
|
/// spatialization.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Audio/Export.hpp>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Base class for classes that require an audio device
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_AUDIO_API AudioResource
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Copy constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
AudioResource(const AudioResource&) = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Copy assignment
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
AudioResource& operator=(const AudioResource&) = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
AudioResource(AudioResource&&) noexcept = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move assignment
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
AudioResource& operator=(AudioResource&&) noexcept = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
AudioResource();
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::shared_ptr<void> m_device; //!< Sound device
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::AudioResource
|
||||||
|
/// \ingroup audio
|
||||||
|
///
|
||||||
|
/// This class is for internal use only, it must be the base
|
||||||
|
/// of every class that requires a valid audio device in
|
||||||
|
/// order to work.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Config.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Portable import / export macros
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#if defined(SFML_AUDIO_EXPORTS)
|
||||||
|
|
||||||
|
#define SFML_AUDIO_API SFML_API_EXPORT
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define SFML_AUDIO_API SFML_API_IMPORT
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,336 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Audio/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Audio/SoundFileReader.hpp>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class Time;
|
||||||
|
class InputStream;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Provide read access to sound files
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_AUDIO_API InputSoundFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// Construct an input sound file that is not associated
|
||||||
|
/// with a file to read.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
InputSoundFile() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct a sound file from the disk for reading
|
||||||
|
///
|
||||||
|
/// The supported audio formats are: WAV (PCM only), OGG/Vorbis, FLAC, MP3.
|
||||||
|
/// The supported sample sizes for FLAC and WAV are 8, 16, 24 and 32 bit.
|
||||||
|
///
|
||||||
|
/// Because of minimp3_ex limitation, for MP3 files with big (>16kb) APEv2 tag,
|
||||||
|
/// it may not be properly removed, tag data will be treated as MP3 data
|
||||||
|
/// and there is a low chance of garbage decoded at the end of file.
|
||||||
|
/// See also: https://github.com/lieff/minimp3
|
||||||
|
///
|
||||||
|
/// \param filename Path of the sound file to load
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if opening the file was unsuccessful
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit InputSoundFile(const std::filesystem::path& filename);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct a sound file in memory for reading
|
||||||
|
///
|
||||||
|
/// The supported audio formats are: WAV (PCM only), OGG/Vorbis, FLAC.
|
||||||
|
/// The supported sample sizes for FLAC and WAV are 8, 16, 24 and 32 bit.
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the file data in memory
|
||||||
|
/// \param sizeInBytes Size of the data to load, in bytes
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if opening the file was unsuccessful
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
InputSoundFile(const void* data, std::size_t sizeInBytes);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct a sound file from a custom stream for reading
|
||||||
|
///
|
||||||
|
/// The supported audio formats are: WAV (PCM only), OGG/Vorbis, FLAC.
|
||||||
|
/// The supported sample sizes for FLAC and WAV are 8, 16, 24 and 32 bit.
|
||||||
|
///
|
||||||
|
/// \param stream Source stream to read from
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if opening the file was unsuccessful
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit InputSoundFile(InputStream& stream);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Open a sound file from the disk for reading
|
||||||
|
///
|
||||||
|
/// The supported audio formats are: WAV (PCM only), OGG/Vorbis, FLAC, MP3.
|
||||||
|
/// The supported sample sizes for FLAC and WAV are 8, 16, 24 and 32 bit.
|
||||||
|
///
|
||||||
|
/// Because of minimp3_ex limitation, for MP3 files with big (>16kb) APEv2 tag,
|
||||||
|
/// it may not be properly removed, tag data will be treated as MP3 data
|
||||||
|
/// and there is a low chance of garbage decoded at the end of file.
|
||||||
|
/// See also: https://github.com/lieff/minimp3
|
||||||
|
///
|
||||||
|
/// \param filename Path of the sound file to load
|
||||||
|
///
|
||||||
|
/// \return `true` if the file was successfully opened
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool openFromFile(const std::filesystem::path& filename);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Open a sound file in memory for reading
|
||||||
|
///
|
||||||
|
/// The supported audio formats are: WAV (PCM only), OGG/Vorbis, FLAC.
|
||||||
|
/// The supported sample sizes for FLAC and WAV are 8, 16, 24 and 32 bit.
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the file data in memory
|
||||||
|
/// \param sizeInBytes Size of the data to load, in bytes
|
||||||
|
///
|
||||||
|
/// \return `true` if the file was successfully opened
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool openFromMemory(const void* data, std::size_t sizeInBytes);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Open a sound file from a custom stream for reading
|
||||||
|
///
|
||||||
|
/// The supported audio formats are: WAV (PCM only), OGG/Vorbis, FLAC.
|
||||||
|
/// The supported sample sizes for FLAC and WAV are 8, 16, 24 and 32 bit.
|
||||||
|
///
|
||||||
|
/// \param stream Source stream to read from
|
||||||
|
///
|
||||||
|
/// \return `true` if the file was successfully opened
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool openFromStream(InputStream& stream);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the total number of audio samples in the file
|
||||||
|
///
|
||||||
|
/// \return Number of samples
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] std::uint64_t getSampleCount() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the number of channels used by the sound
|
||||||
|
///
|
||||||
|
/// \return Number of channels (1 = mono, 2 = stereo)
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] unsigned int getChannelCount() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the sample rate of the sound
|
||||||
|
///
|
||||||
|
/// \return Sample rate, in samples per second
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] unsigned int getSampleRate() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the map of position in sample frame to sound channel
|
||||||
|
///
|
||||||
|
/// This is used to map a sample in the sample stream to a
|
||||||
|
/// position during spatialization.
|
||||||
|
///
|
||||||
|
/// \return Map of position in sample frame to sound channel
|
||||||
|
///
|
||||||
|
/// \see `getSampleRate`, `getChannelCount`, `getDuration`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const std::vector<SoundChannel>& getChannelMap() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the total duration of the sound file
|
||||||
|
///
|
||||||
|
/// This function is provided for convenience, the duration is
|
||||||
|
/// deduced from the other sound file attributes.
|
||||||
|
///
|
||||||
|
/// \return Duration of the sound file
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Time getDuration() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the read offset of the file in time
|
||||||
|
///
|
||||||
|
/// \return Time position
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Time getTimeOffset() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the read offset of the file in samples
|
||||||
|
///
|
||||||
|
/// \return Sample position
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] std::uint64_t getSampleOffset() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Change the current read position to the given sample offset
|
||||||
|
///
|
||||||
|
/// This function takes a sample offset to provide maximum
|
||||||
|
/// precision. If you need to jump to a given time, use the
|
||||||
|
/// other overload.
|
||||||
|
///
|
||||||
|
/// The sample offset takes the channels into account.
|
||||||
|
/// If you have a time offset instead, you can easily find
|
||||||
|
/// the corresponding sample offset with the following formula:
|
||||||
|
/// `timeInSeconds * sampleRate * channelCount`
|
||||||
|
/// If the given offset exceeds to total number of samples,
|
||||||
|
/// this function jumps to the end of the sound file.
|
||||||
|
///
|
||||||
|
/// \param sampleOffset Index of the sample to jump to, relative to the beginning
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void seek(std::uint64_t sampleOffset);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Change the current read position to the given time offset
|
||||||
|
///
|
||||||
|
/// Using a time offset is handy but imprecise. If you need an accurate
|
||||||
|
/// result, consider using the overload which takes a sample offset.
|
||||||
|
///
|
||||||
|
/// If the given time exceeds to total duration, this function jumps
|
||||||
|
/// to the end of the sound file.
|
||||||
|
///
|
||||||
|
/// \param timeOffset Time to jump to, relative to the beginning
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void seek(Time timeOffset);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Read audio samples from the open file
|
||||||
|
///
|
||||||
|
/// \param samples Pointer to the sample array to fill
|
||||||
|
/// \param maxCount Maximum number of samples to read
|
||||||
|
///
|
||||||
|
/// \return Number of samples actually read (may be less than \a maxCount)
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] std::uint64_t read(std::int16_t* samples, std::uint64_t maxCount);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Close the current file
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void close();
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Deleter for input streams that only conditionally deletes
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
struct SFML_AUDIO_API StreamDeleter
|
||||||
|
{
|
||||||
|
StreamDeleter(bool theOwned);
|
||||||
|
|
||||||
|
// To accept ownership transfer from usual std::unique_ptr<T>
|
||||||
|
template <typename T>
|
||||||
|
StreamDeleter(const std::default_delete<T>&);
|
||||||
|
|
||||||
|
void operator()(InputStream* ptr) const;
|
||||||
|
|
||||||
|
bool owned{true};
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::unique_ptr<SoundFileReader> m_reader; //!< Reader that handles I/O on the file's format
|
||||||
|
std::unique_ptr<InputStream, StreamDeleter> m_stream{nullptr, false}; //!< Input stream used to access the file's data
|
||||||
|
std::uint64_t m_sampleOffset{}; //!< Sample Read Position
|
||||||
|
std::uint64_t m_sampleCount{}; //!< Total number of samples in the file
|
||||||
|
unsigned int m_sampleRate{}; //!< Number of samples per second
|
||||||
|
std::vector<SoundChannel> m_channelMap; //!< The map of position in sample frame to sound channel
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::InputSoundFile
|
||||||
|
/// \ingroup audio
|
||||||
|
///
|
||||||
|
/// This class decodes audio samples from a sound file. It is
|
||||||
|
/// used internally by higher-level classes such as `sf::SoundBuffer`
|
||||||
|
/// and `sf::Music`, but can also be useful if you want to process
|
||||||
|
/// or analyze audio files without playing them, or if you want to
|
||||||
|
/// implement your own version of `sf::Music` with more specific
|
||||||
|
/// features.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// // Open a sound file
|
||||||
|
/// sf::InputSoundFile file("music.ogg");
|
||||||
|
///
|
||||||
|
/// // Print the sound attributes
|
||||||
|
/// std::cout << "duration: " << file.getDuration().asSeconds() << '\n'
|
||||||
|
/// << "channels: " << file.getChannelCount() << '\n'
|
||||||
|
/// << "sample rate: " << file.getSampleRate() << '\n'
|
||||||
|
/// << "sample count: " << file.getSampleCount() << std::endl;
|
||||||
|
///
|
||||||
|
/// // Read and process batches of samples until the end of file is reached
|
||||||
|
/// std::array<std::int16_t, 1024> samples;
|
||||||
|
/// std::uint64_t count;
|
||||||
|
/// do
|
||||||
|
/// {
|
||||||
|
/// count = file.read(samples.data(), samples.size());
|
||||||
|
///
|
||||||
|
/// // process, analyze, play, convert, or whatever
|
||||||
|
/// // you want to do with the samples...
|
||||||
|
/// }
|
||||||
|
/// while (count > 0);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::SoundFileReader`, `sf::OutputSoundFile`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,234 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Audio/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/Angle.hpp>
|
||||||
|
#include <SFML/System/Vector3.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief The audio listener is the point in the scene
|
||||||
|
/// from where all the sounds are heard
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
namespace sf::Listener
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Structure defining the properties of a directional cone
|
||||||
|
///
|
||||||
|
/// Sounds will play at gain 1 when they are positioned
|
||||||
|
/// within the inner angle of the cone. Sounds will play
|
||||||
|
/// at `outerGain` when they are positioned outside the
|
||||||
|
/// outer angle of the cone. The gain declines linearly
|
||||||
|
/// from 1 to `outerGain` as the sound moves from the inner
|
||||||
|
/// angle to the outer angle.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
struct Cone
|
||||||
|
{
|
||||||
|
Angle innerAngle; //!< Inner angle
|
||||||
|
Angle outerAngle; //!< Outer angle
|
||||||
|
float outerGain{}; //!< Outer gain
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Change the global volume of all the sounds and musics
|
||||||
|
///
|
||||||
|
/// `volume` is a number between 0 and 100; it is combined
|
||||||
|
/// with the individual volume of each sound / music.
|
||||||
|
/// The default value for the volume is 100 (maximum).
|
||||||
|
///
|
||||||
|
/// \param volume New global volume, in the range [0, 100]
|
||||||
|
///
|
||||||
|
/// \see `getGlobalVolume`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_AUDIO_API void setGlobalVolume(float volume);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the current value of the global volume
|
||||||
|
///
|
||||||
|
/// \return Current global volume, in the range [0, 100]
|
||||||
|
///
|
||||||
|
/// \see `setGlobalVolume`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] SFML_AUDIO_API float getGlobalVolume();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the position of the listener in the scene
|
||||||
|
///
|
||||||
|
/// The default listener's position is (0, 0, 0).
|
||||||
|
///
|
||||||
|
/// \param position New listener's position
|
||||||
|
///
|
||||||
|
/// \see `getPosition`, `setDirection`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_AUDIO_API void setPosition(const Vector3f& position);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the current position of the listener in the scene
|
||||||
|
///
|
||||||
|
/// \return Listener's position
|
||||||
|
///
|
||||||
|
/// \see `setPosition`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] SFML_AUDIO_API Vector3f getPosition();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the forward vector of the listener in the scene
|
||||||
|
///
|
||||||
|
/// The direction (also called "at vector") is the vector
|
||||||
|
/// pointing forward from the listener's perspective. Together
|
||||||
|
/// with the up vector, it defines the 3D orientation of the
|
||||||
|
/// listener in the scene. The direction vector doesn't
|
||||||
|
/// have to be normalized.
|
||||||
|
/// The default listener's direction is (0, 0, -1).
|
||||||
|
///
|
||||||
|
/// \param direction New listener's direction
|
||||||
|
///
|
||||||
|
/// \see `getDirection`, `setUpVector`, `setPosition`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_AUDIO_API void setDirection(const Vector3f& direction);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the current forward vector of the listener in the scene
|
||||||
|
///
|
||||||
|
/// \return Listener's forward vector (not normalized)
|
||||||
|
///
|
||||||
|
/// \see `setDirection`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] SFML_AUDIO_API Vector3f getDirection();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the velocity of the listener in the scene
|
||||||
|
///
|
||||||
|
/// The default listener's velocity is (0, 0, -1).
|
||||||
|
///
|
||||||
|
/// \param velocity New listener's velocity
|
||||||
|
///
|
||||||
|
/// \see `getVelocity`, `getDirection`, `setUpVector`, `setPosition`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_AUDIO_API void setVelocity(const Vector3f& velocity);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the current forward vector of the listener in the scene
|
||||||
|
///
|
||||||
|
/// \return Listener's velocity
|
||||||
|
///
|
||||||
|
/// \see `setVelocity`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] SFML_AUDIO_API Vector3f getVelocity();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the cone properties of the listener in the audio scene
|
||||||
|
///
|
||||||
|
/// The cone defines how directional attenuation is applied.
|
||||||
|
/// The default cone of a sound is (2 * PI, 2 * PI, 1).
|
||||||
|
///
|
||||||
|
/// \param cone Cone properties of the listener in the scene
|
||||||
|
///
|
||||||
|
/// \see `getCone`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_AUDIO_API void setCone(const Listener::Cone& cone);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the cone properties of the listener in the audio scene
|
||||||
|
///
|
||||||
|
/// \return Cone properties of the listener
|
||||||
|
///
|
||||||
|
/// \see `setCone`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] SFML_AUDIO_API Listener::Cone getCone();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the upward vector of the listener in the scene
|
||||||
|
///
|
||||||
|
/// The up vector is the vector that points upward from the
|
||||||
|
/// listener's perspective. Together with the direction, it
|
||||||
|
/// defines the 3D orientation of the listener in the scene.
|
||||||
|
/// The up vector doesn't have to be normalized.
|
||||||
|
/// The default listener's up vector is (0, 1, 0). It is usually
|
||||||
|
/// not necessary to change it, especially in 2D scenarios.
|
||||||
|
///
|
||||||
|
/// \param upVector New listener's up vector
|
||||||
|
///
|
||||||
|
/// \see `getUpVector`, `setDirection`, `setPosition`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_AUDIO_API void setUpVector(const Vector3f& upVector);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the current upward vector of the listener in the scene
|
||||||
|
///
|
||||||
|
/// \return Listener's upward vector (not normalized)
|
||||||
|
///
|
||||||
|
/// \see `setUpVector`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] SFML_AUDIO_API Vector3f getUpVector();
|
||||||
|
} // namespace sf::Listener
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \namespace sf::Listener
|
||||||
|
/// \ingroup audio
|
||||||
|
///
|
||||||
|
/// The audio listener defines the global properties of the
|
||||||
|
/// audio environment, it defines where and how sounds and musics
|
||||||
|
/// are heard. If `sf::View` is the eyes of the user, then
|
||||||
|
/// `sf::Listener` are their ears (by the way, they are often linked
|
||||||
|
/// together -- same position, orientation, etc.).
|
||||||
|
///
|
||||||
|
/// `sf::Listener` is a simple interface, which allows to setup the
|
||||||
|
/// listener in the 3D audio environment (position, direction and
|
||||||
|
/// up vector), and to adjust the global volume.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// // Move the listener to the position (1, 0, -5)
|
||||||
|
/// sf::Listener::setPosition({1, 0, -5});
|
||||||
|
///
|
||||||
|
/// // Make it face the right axis (1, 0, 0)
|
||||||
|
/// sf::Listener::setDirection({1, 0, 0});
|
||||||
|
///
|
||||||
|
/// // Reduce the global volume
|
||||||
|
/// sf::Listener::setGlobalVolume(50);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,377 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Audio/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Audio/SoundStream.hpp>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class Time;
|
||||||
|
class InputStream;
|
||||||
|
class InputSoundFile;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Streamed music played from an audio file
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_AUDIO_API Music : public SoundStream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Structure defining a time range using the template type
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
struct Span
|
||||||
|
{
|
||||||
|
T offset{}; //!< The beginning offset of the time range
|
||||||
|
T length{}; //!< The length of the time range
|
||||||
|
};
|
||||||
|
|
||||||
|
// Associated `Span` type
|
||||||
|
using TimeSpan = Span<Time>;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// Construct an empty music that does not contain any data.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Music();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct a music from an audio file
|
||||||
|
///
|
||||||
|
/// This function doesn't start playing the music (call `play()`
|
||||||
|
/// to do so).
|
||||||
|
/// See the documentation of `sf::InputSoundFile` for the list
|
||||||
|
/// of supported formats.
|
||||||
|
///
|
||||||
|
/// \warning Since the music is not loaded at once but rather
|
||||||
|
/// streamed continuously, the file must remain accessible until
|
||||||
|
/// the `sf::Music` object loads a new music or is destroyed.
|
||||||
|
///
|
||||||
|
/// \param filename Path of the music file to open
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if loading was unsuccessful
|
||||||
|
///
|
||||||
|
/// \see `openFromMemory`, `openFromStream`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit Music(const std::filesystem::path& filename);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct a music from an audio file in memory
|
||||||
|
///
|
||||||
|
/// This function doesn't start playing the music (call `play()`
|
||||||
|
/// to do so).
|
||||||
|
/// See the documentation of `sf::InputSoundFile` for the list
|
||||||
|
/// of supported formats.
|
||||||
|
///
|
||||||
|
/// \warning Since the music is not loaded at once but rather streamed
|
||||||
|
/// continuously, the \a data buffer must remain accessible until
|
||||||
|
/// the `sf::Music` object loads a new music or is destroyed. That is,
|
||||||
|
/// you can't deallocate the buffer right after calling this function.
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the file data in memory
|
||||||
|
/// \param sizeInBytes Size of the data to load, in bytes
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if loading was unsuccessful
|
||||||
|
///
|
||||||
|
/// \see `openFromFile`, `openFromStream`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Music(const void* data, std::size_t sizeInBytes);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct a music from an audio file in a custom stream
|
||||||
|
///
|
||||||
|
/// This function doesn't start playing the music (call `play()`
|
||||||
|
/// to do so).
|
||||||
|
/// See the documentation of `sf::InputSoundFile` for the list
|
||||||
|
/// of supported formats.
|
||||||
|
///
|
||||||
|
/// \warning Since the music is not loaded at once but rather
|
||||||
|
/// streamed continuously, the `stream` must remain accessible
|
||||||
|
/// until the `sf::Music` object loads a new music or is destroyed.
|
||||||
|
///
|
||||||
|
/// \param stream Source stream to read from
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if loading was unsuccessful
|
||||||
|
///
|
||||||
|
/// \see `openFromFile`, `openFromMemory`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit Music(InputStream& stream);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Destructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
~Music() override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Music(Music&&) noexcept;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move assignment
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Music& operator=(Music&&) noexcept;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Open a music from an audio file
|
||||||
|
///
|
||||||
|
/// This function doesn't start playing the music (call `play()`
|
||||||
|
/// to do so).
|
||||||
|
/// See the documentation of `sf::InputSoundFile` for the list
|
||||||
|
/// of supported formats.
|
||||||
|
///
|
||||||
|
/// \warning Since the music is not loaded at once but rather
|
||||||
|
/// streamed continuously, the file must remain accessible until
|
||||||
|
/// the `sf::Music` object loads a new music or is destroyed.
|
||||||
|
///
|
||||||
|
/// \param filename Path of the music file to open
|
||||||
|
///
|
||||||
|
/// \return `true` if loading succeeded, `false` if it failed
|
||||||
|
///
|
||||||
|
/// \see `openFromMemory`, `openFromStream`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool openFromFile(const std::filesystem::path& filename);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Open a music from an audio file in memory
|
||||||
|
///
|
||||||
|
/// This function doesn't start playing the music (call `play()`
|
||||||
|
/// to do so).
|
||||||
|
/// See the documentation of `sf::InputSoundFile` for the list
|
||||||
|
/// of supported formats.
|
||||||
|
///
|
||||||
|
/// \warning Since the music is not loaded at once but rather streamed
|
||||||
|
/// continuously, the `data` buffer must remain accessible until
|
||||||
|
/// the `sf::Music` object loads a new music or is destroyed. That is,
|
||||||
|
/// you can't deallocate the buffer right after calling this function.
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the file data in memory
|
||||||
|
/// \param sizeInBytes Size of the data to load, in bytes
|
||||||
|
///
|
||||||
|
/// \return `true` if loading succeeded, `false` if it failed
|
||||||
|
///
|
||||||
|
/// \see `openFromFile`, `openFromStream`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool openFromMemory(const void* data, std::size_t sizeInBytes);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Open a music from an audio file in a custom stream
|
||||||
|
///
|
||||||
|
/// This function doesn't start playing the music (call `play()`
|
||||||
|
/// to do so).
|
||||||
|
/// See the documentation of `sf::InputSoundFile` for the list
|
||||||
|
/// of supported formats.
|
||||||
|
///
|
||||||
|
/// \warning Since the music is not loaded at once but rather
|
||||||
|
/// streamed continuously, the `stream` must remain accessible
|
||||||
|
/// until the `sf::Music` object loads a new music or is destroyed.
|
||||||
|
///
|
||||||
|
/// \param stream Source stream to read from
|
||||||
|
///
|
||||||
|
/// \return `true` if loading succeeded, `false` if it failed
|
||||||
|
///
|
||||||
|
/// \see `openFromFile`, `openFromMemory`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool openFromStream(InputStream& stream);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the total duration of the music
|
||||||
|
///
|
||||||
|
/// \return Music duration
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Time getDuration() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the positions of the of the sound's looping sequence
|
||||||
|
///
|
||||||
|
/// \return Loop Time position class.
|
||||||
|
///
|
||||||
|
/// \warning Since `setLoopPoints()` performs some adjustments on the
|
||||||
|
/// provided values and rounds them to internal samples, a call to
|
||||||
|
/// `getLoopPoints()` is not guaranteed to return the same times passed
|
||||||
|
/// into a previous call to `setLoopPoints()`. However, it is guaranteed
|
||||||
|
/// to return times that will map to the valid internal samples of
|
||||||
|
/// this Music if they are later passed to `setLoopPoints()`.
|
||||||
|
///
|
||||||
|
/// \see `setLoopPoints`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] TimeSpan getLoopPoints() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Sets the beginning and duration of the sound's looping sequence using `sf::Time`
|
||||||
|
///
|
||||||
|
/// `setLoopPoints()` allows for specifying the beginning offset and the duration of the loop such that,
|
||||||
|
/// when the music is enabled for looping, it will seamlessly seek to the beginning whenever it
|
||||||
|
/// encounters the end of the duration. Valid ranges for `timePoints.offset` and `timePoints.length` are
|
||||||
|
/// [0, Dur) and (0, Dur-offset] respectively, where Dur is the value returned by `getDuration()`.
|
||||||
|
/// Note that the EOF "loop point" from the end to the beginning of the stream is still honored,
|
||||||
|
/// in case the caller seeks to a point after the end of the loop range. This function can be
|
||||||
|
/// safely called at any point after a stream is opened, and will be applied to a playing sound
|
||||||
|
/// without affecting the current playing offset.
|
||||||
|
///
|
||||||
|
/// \warning Setting the loop points while the stream's status is Paused
|
||||||
|
/// will set its status to Stopped. The playing offset will be unaffected.
|
||||||
|
///
|
||||||
|
/// \param timePoints The definition of the loop. Can be any time points within the sound's length
|
||||||
|
///
|
||||||
|
/// \see `getLoopPoints`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setLoopPoints(TimeSpan timePoints);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Request a new chunk of audio samples from the stream source
|
||||||
|
///
|
||||||
|
/// This function fills the chunk from the next samples
|
||||||
|
/// to read from the audio file.
|
||||||
|
///
|
||||||
|
/// \param data Chunk of data to fill
|
||||||
|
///
|
||||||
|
/// \return `true` to continue playback, `false` to stop
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool onGetData(Chunk& data) override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Change the current playing position in the stream source
|
||||||
|
///
|
||||||
|
/// \param timeOffset New playing position, from the beginning of the music
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void onSeek(Time timeOffset) override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Change the current playing position in the stream source to the loop offset
|
||||||
|
///
|
||||||
|
/// This is called by the underlying `SoundStream` whenever it needs us to reset
|
||||||
|
/// the seek position for a loop. We then determine whether we are looping on a
|
||||||
|
/// loop point or the end-of-file, perform the seek, and return the new position.
|
||||||
|
///
|
||||||
|
/// \return The seek position after looping (or `std::nullopt` if there's no loop)
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::optional<std::uint64_t> onLoop() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Helper to convert an `sf::Time` to a sample position
|
||||||
|
///
|
||||||
|
/// \param position Time to convert to samples
|
||||||
|
///
|
||||||
|
/// \return The number of samples elapsed at the given time
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] std::uint64_t timeToSamples(Time position) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Helper to convert a sample position to an `sf::Time`
|
||||||
|
///
|
||||||
|
/// \param samples Sample count to convert to Time
|
||||||
|
///
|
||||||
|
/// \return The Time position of the given sample
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Time samplesToTime(std::uint64_t samples) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
struct Impl;
|
||||||
|
std::unique_ptr<Impl> m_impl; //!< Implementation details
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::Music
|
||||||
|
/// \ingroup audio
|
||||||
|
///
|
||||||
|
/// Musics are sounds that are streamed rather than completely
|
||||||
|
/// loaded in memory. This is especially useful for compressed
|
||||||
|
/// musics that usually take hundreds of MB when they are
|
||||||
|
/// uncompressed: by streaming it instead of loading it entirely,
|
||||||
|
/// you avoid saturating the memory and have almost no loading delay.
|
||||||
|
/// This implies that the underlying resource (file, stream or
|
||||||
|
/// memory buffer) must remain valid for the lifetime of the
|
||||||
|
/// `sf::Music` object.
|
||||||
|
///
|
||||||
|
/// Apart from that, a `sf::Music` has almost the same features as
|
||||||
|
/// the `sf::SoundBuffer` / `sf::Sound` pair: you can play/pause/stop
|
||||||
|
/// it, request its parameters (channels, sample rate), change
|
||||||
|
/// the way it is played (pitch, volume, 3D position, ...), etc.
|
||||||
|
///
|
||||||
|
/// As a sound stream, a music is played in its own thread in order
|
||||||
|
/// not to block the rest of the program. This means that you can
|
||||||
|
/// leave the music alone after calling `play()`, it will manage itself
|
||||||
|
/// very well.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// // Open a music from an audio file
|
||||||
|
/// sf::Music music("music.ogg");
|
||||||
|
///
|
||||||
|
/// // Change some parameters
|
||||||
|
/// music.setPosition({0, 1, 10}); // change its 3D position
|
||||||
|
/// music.setPitch(2); // increase the pitch
|
||||||
|
/// music.setVolume(50); // reduce the volume
|
||||||
|
/// music.setLooping(true); // make it loop
|
||||||
|
///
|
||||||
|
/// // Play it
|
||||||
|
/// music.play();
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::Sound`, `sf::SoundStream`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,147 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Audio/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Audio/SoundChannel.hpp>
|
||||||
|
#include <SFML/Audio/SoundFileWriter.hpp>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Provide write access to sound files
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_AUDIO_API OutputSoundFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// Construct an output sound file that is not associated
|
||||||
|
/// with a file to write.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
OutputSoundFile() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the sound file from the disk for writing
|
||||||
|
///
|
||||||
|
/// The supported audio formats are: WAV, OGG/Vorbis, FLAC.
|
||||||
|
///
|
||||||
|
/// \param filename Path of the sound file to write
|
||||||
|
/// \param sampleRate Sample rate of the sound
|
||||||
|
/// \param channelCount Number of channels in the sound
|
||||||
|
/// \param channelMap Map of position in sample frame to sound channel
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if the file could not be opened successfully
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
OutputSoundFile(const std::filesystem::path& filename,
|
||||||
|
unsigned int sampleRate,
|
||||||
|
unsigned int channelCount,
|
||||||
|
const std::vector<SoundChannel>& channelMap);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Open the sound file from the disk for writing
|
||||||
|
///
|
||||||
|
/// The supported audio formats are: WAV, OGG/Vorbis, FLAC.
|
||||||
|
///
|
||||||
|
/// \param filename Path of the sound file to write
|
||||||
|
/// \param sampleRate Sample rate of the sound
|
||||||
|
/// \param channelCount Number of channels in the sound
|
||||||
|
/// \param channelMap Map of position in sample frame to sound channel
|
||||||
|
///
|
||||||
|
/// \return `true` if the file was successfully opened
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool openFromFile(const std::filesystem::path& filename,
|
||||||
|
unsigned int sampleRate,
|
||||||
|
unsigned int channelCount,
|
||||||
|
const std::vector<SoundChannel>& channelMap);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Write audio samples to the file
|
||||||
|
///
|
||||||
|
/// \param samples Pointer to the sample array to write
|
||||||
|
/// \param count Number of samples to write
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void write(const std::int16_t* samples, std::uint64_t count);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Close the current file
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void close();
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::unique_ptr<SoundFileWriter> m_writer; //!< Writer that handles I/O on the file's format
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::OutputSoundFile
|
||||||
|
/// \ingroup audio
|
||||||
|
///
|
||||||
|
/// This class encodes audio samples to a sound file. It is
|
||||||
|
/// used internally by higher-level classes such as `sf::SoundBuffer`,
|
||||||
|
/// but can also be useful if you want to create audio files from
|
||||||
|
/// custom data sources, like generated audio samples.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// // Create a sound file, ogg/vorbis format, 44100 Hz, stereo
|
||||||
|
/// sf::OutputSoundFile file("music.ogg", 44100, 2, {sf::SoundChannel::FrontLeft, sf::SoundChannel::FrontRight});
|
||||||
|
///
|
||||||
|
/// while (...)
|
||||||
|
/// {
|
||||||
|
/// // Read or generate audio samples from your custom source
|
||||||
|
/// std::vector<std::int16_t> samples = ...;
|
||||||
|
///
|
||||||
|
/// // Write them to the file
|
||||||
|
/// file.write(samples.data(), samples.size());
|
||||||
|
/// }
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::SoundFileWriter`, `sf::InputSoundFile`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,110 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Audio/Export.hpp>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf::PlaybackDevice
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get a list of the names of all available audio playback devices
|
||||||
|
///
|
||||||
|
/// This function returns a vector of strings containing
|
||||||
|
/// the names of all available audio playback devices.
|
||||||
|
///
|
||||||
|
/// If the operating system reports multiple devices with
|
||||||
|
/// the same name, a number will be appended to the name
|
||||||
|
/// of all subsequent devices to distinguish them from each
|
||||||
|
/// other. This guarantees that every entry returned by this
|
||||||
|
/// function will represent a unique device.
|
||||||
|
///
|
||||||
|
/// For example, if the operating system reports multiple
|
||||||
|
/// devices with the name "Sound Card", the entries returned
|
||||||
|
/// would be:
|
||||||
|
/// - Sound Card
|
||||||
|
/// - Sound Card 2
|
||||||
|
/// - Sound Card 3
|
||||||
|
/// - ...
|
||||||
|
///
|
||||||
|
/// The default device, if one is marked as such, will be
|
||||||
|
/// placed at the beginning of the vector.
|
||||||
|
///
|
||||||
|
/// If no devices are available, this function will return
|
||||||
|
/// an empty vector.
|
||||||
|
///
|
||||||
|
/// \return A vector of strings containing the device names or an empty vector if no devices are available
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] SFML_AUDIO_API std::vector<std::string> getAvailableDevices();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the name of the default audio playback device
|
||||||
|
///
|
||||||
|
/// This function returns the name of the default audio
|
||||||
|
/// playback device. If none is available, an empty string
|
||||||
|
/// is returned.
|
||||||
|
///
|
||||||
|
/// \return The name of the default audio playback device
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] SFML_AUDIO_API std::optional<std::string> getDefaultDevice();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the audio playback device
|
||||||
|
///
|
||||||
|
/// This function sets the audio playback device to the device
|
||||||
|
/// with the given `name`. It can be called on the fly (i.e:
|
||||||
|
/// while sounds are playing).
|
||||||
|
///
|
||||||
|
/// If there are sounds playing when the audio playback
|
||||||
|
/// device is switched, the sounds will continue playing
|
||||||
|
/// uninterrupted on the new audio playback device.
|
||||||
|
///
|
||||||
|
/// \param name The name of the audio playback device
|
||||||
|
///
|
||||||
|
/// \return `true`, if it was able to set the requested device
|
||||||
|
///
|
||||||
|
/// \see `getAvailableDevices`, `getDefaultDevice`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] SFML_AUDIO_API bool setDevice(const std::string& name);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the name of the current audio playback device
|
||||||
|
///
|
||||||
|
/// \return The name of the current audio playback device or `std::nullopt` if there is none
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] SFML_AUDIO_API std::optional<std::string> getDevice();
|
||||||
|
|
||||||
|
} // namespace sf::PlaybackDevice
|
||||||
|
|
@ -0,0 +1,284 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Audio/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Audio/SoundSource.hpp>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class Time;
|
||||||
|
class SoundBuffer;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Regular sound that can be played in the audio environment
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_AUDIO_API Sound : public SoundSource
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the sound with a buffer
|
||||||
|
///
|
||||||
|
/// \param buffer Sound buffer containing the audio data to play with the sound
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit Sound(const SoundBuffer& buffer);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Disallow construction from a temporary sound buffer
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Sound(const SoundBuffer&& buffer) = delete;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Copy constructor
|
||||||
|
///
|
||||||
|
/// \param copy Instance to copy
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Sound(const Sound& copy);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Destructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
~Sound() override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Start or resume playing the sound
|
||||||
|
///
|
||||||
|
/// This function starts the stream if it was stopped, resumes
|
||||||
|
/// it if it was paused, and restarts it from beginning if it
|
||||||
|
/// was it already playing.
|
||||||
|
/// This function uses its own thread so that it doesn't block
|
||||||
|
/// the rest of the program while the sound is played.
|
||||||
|
///
|
||||||
|
/// \see `pause`, `stop`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void play() override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Pause the sound
|
||||||
|
///
|
||||||
|
/// This function pauses the sound if it was playing,
|
||||||
|
/// otherwise (sound already paused or stopped) it has no effect.
|
||||||
|
///
|
||||||
|
/// \see `play`, `stop`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void pause() override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief stop playing the sound
|
||||||
|
///
|
||||||
|
/// This function stops the sound if it was playing or paused,
|
||||||
|
/// and does nothing if it was already stopped.
|
||||||
|
/// It also resets the playing position (unlike `pause()`).
|
||||||
|
///
|
||||||
|
/// \see `play`, `pause`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void stop() override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the source buffer containing the audio data to play
|
||||||
|
///
|
||||||
|
/// It is important to note that the sound buffer is not copied,
|
||||||
|
/// thus the `sf::SoundBuffer` instance must remain alive as long
|
||||||
|
/// as it is attached to the sound.
|
||||||
|
///
|
||||||
|
/// \param buffer Sound buffer to attach to the sound
|
||||||
|
///
|
||||||
|
/// \see `getBuffer`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setBuffer(const SoundBuffer& buffer);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Disallow setting from a temporary sound buffer
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setBuffer(const SoundBuffer&& buffer) = delete;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set whether or not the sound should loop after reaching the end
|
||||||
|
///
|
||||||
|
/// If set, the sound will restart from beginning after
|
||||||
|
/// reaching the end and so on, until it is stopped or
|
||||||
|
/// `setLooping(false)` is called.
|
||||||
|
/// The default looping state for sound is `false`.
|
||||||
|
///
|
||||||
|
/// \param loop `true` to play in loop, `false` to play once
|
||||||
|
///
|
||||||
|
/// \see `isLooping`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setLooping(bool loop);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Change the current playing position of the sound
|
||||||
|
///
|
||||||
|
/// The playing position can be changed when the sound is
|
||||||
|
/// either paused or playing. Changing the playing position
|
||||||
|
/// when the sound is stopped has no effect, since playing
|
||||||
|
/// the sound will reset its position.
|
||||||
|
///
|
||||||
|
/// \param timeOffset New playing position, from the beginning of the sound
|
||||||
|
///
|
||||||
|
/// \see `getPlayingOffset`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setPlayingOffset(Time timeOffset);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the effect processor to be applied to the sound
|
||||||
|
///
|
||||||
|
/// The effect processor is a callable that will be called
|
||||||
|
/// with sound data to be processed.
|
||||||
|
///
|
||||||
|
/// \param effectProcessor The effect processor to attach to this sound, attach an empty processor to disable processing
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setEffectProcessor(EffectProcessor effectProcessor) override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the audio buffer attached to the sound
|
||||||
|
///
|
||||||
|
/// \return Sound buffer attached to the sound
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const SoundBuffer& getBuffer() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Tell whether or not the sound is in loop mode
|
||||||
|
///
|
||||||
|
/// \return `true` if the sound is looping, `false` otherwise
|
||||||
|
///
|
||||||
|
/// \see `setLooping`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool isLooping() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the current playing position of the sound
|
||||||
|
///
|
||||||
|
/// \return Current playing position, from the beginning of the sound
|
||||||
|
///
|
||||||
|
/// \see `setPlayingOffset`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Time getPlayingOffset() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the current status of the sound (stopped, paused, playing)
|
||||||
|
///
|
||||||
|
/// \return Current status of the sound
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Status getStatus() const override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Overload of assignment operator
|
||||||
|
///
|
||||||
|
/// \param right Instance to assign
|
||||||
|
///
|
||||||
|
/// \return Reference to self
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Sound& operator=(const Sound& right);
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class SoundBuffer;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Detach sound from its internal buffer
|
||||||
|
///
|
||||||
|
/// This allows the sound buffer to temporarily detach the
|
||||||
|
/// sounds that use it when the sound buffer gets updated.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void detachBuffer();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the sound object
|
||||||
|
///
|
||||||
|
/// \return The sound object
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] void* getSound() const override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
struct Impl;
|
||||||
|
const std::unique_ptr<Impl> m_impl; //!< Implementation details
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::Sound
|
||||||
|
/// \ingroup audio
|
||||||
|
///
|
||||||
|
/// `sf::Sound` is the class to use to play sounds.
|
||||||
|
/// It provides:
|
||||||
|
/// \li Control (play, pause, stop)
|
||||||
|
/// \li Ability to modify output parameters in real-time (pitch, volume, ...)
|
||||||
|
/// \li 3D spatial features (position, attenuation, ...).
|
||||||
|
///
|
||||||
|
/// `sf::Sound` is perfect for playing short sounds that can
|
||||||
|
/// fit in memory and require no latency, like foot steps or
|
||||||
|
/// gun shots. For longer sounds, like background musics
|
||||||
|
/// or long speeches, rather see `sf::Music` (which is based
|
||||||
|
/// on streaming).
|
||||||
|
///
|
||||||
|
/// In order to work, a sound must be given a buffer of audio
|
||||||
|
/// data to play. Audio data (samples) is stored in `sf::SoundBuffer,`
|
||||||
|
/// and attached to a sound when it is created or with the `setBuffer()` function.
|
||||||
|
/// The buffer object attached to a sound must remain alive
|
||||||
|
/// as long as the sound uses it. Note that multiple sounds
|
||||||
|
/// can use the same sound buffer at the same time.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// const sf::SoundBuffer buffer("sound.wav");
|
||||||
|
/// sf::Sound sound(buffer);
|
||||||
|
/// sound.play();
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::SoundBuffer`, `sf::Music`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,451 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Audio/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Audio/SoundChannel.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/Time.hpp>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class Sound;
|
||||||
|
class InputSoundFile;
|
||||||
|
class InputStream;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Storage for audio samples defining a sound
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_AUDIO_API SoundBuffer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// Construct an empty sound buffer that does not contain
|
||||||
|
/// any samples.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SoundBuffer() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Copy constructor
|
||||||
|
///
|
||||||
|
/// \param copy Instance to copy
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SoundBuffer(const SoundBuffer& copy);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the sound buffer from a file
|
||||||
|
///
|
||||||
|
/// See the documentation of `sf::InputSoundFile` for the list
|
||||||
|
/// of supported formats.
|
||||||
|
///
|
||||||
|
/// \param filename Path of the sound file to load
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if loading was unsuccessful
|
||||||
|
///
|
||||||
|
/// \see `loadFromMemory`, `loadFromStream`, `loadFromSamples`, `saveToFile`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit SoundBuffer(const std::filesystem::path& filename);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the sound buffer from a file in memory
|
||||||
|
///
|
||||||
|
/// See the documentation of `sf::InputSoundFile` for the list
|
||||||
|
/// of supported formats.
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the file data in memory
|
||||||
|
/// \param sizeInBytes Size of the data to load, in bytes
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if loading was unsuccessful
|
||||||
|
///
|
||||||
|
/// \see `loadFromFile`, `loadFromStream`, `loadFromSamples`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SoundBuffer(const void* data, std::size_t sizeInBytes);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the sound buffer from a custom stream
|
||||||
|
///
|
||||||
|
/// See the documentation of `sf::InputSoundFile` for the list
|
||||||
|
/// of supported formats.
|
||||||
|
///
|
||||||
|
/// \param stream Source stream to read from
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if loading was unsuccessful
|
||||||
|
///
|
||||||
|
/// \see `loadFromFile`, `loadFromMemory`, `loadFromSamples`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit SoundBuffer(InputStream& stream);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the sound buffer from an array of audio samples
|
||||||
|
///
|
||||||
|
/// The assumed format of the audio samples is 16 bit signed integer.
|
||||||
|
///
|
||||||
|
/// \param samples Pointer to the array of samples in memory
|
||||||
|
/// \param sampleCount Number of samples in the array
|
||||||
|
/// \param channelCount Number of channels (1 = mono, 2 = stereo, ...)
|
||||||
|
/// \param sampleRate Sample rate (number of samples to play per second)
|
||||||
|
/// \param channelMap Map of position in sample frame to sound channel
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if loading was unsuccessful
|
||||||
|
///
|
||||||
|
/// \see `loadFromFile`, `loadFromMemory`, `saveToFile`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SoundBuffer(const std::int16_t* samples,
|
||||||
|
std::uint64_t sampleCount,
|
||||||
|
unsigned int channelCount,
|
||||||
|
unsigned int sampleRate,
|
||||||
|
const std::vector<SoundChannel>& channelMap);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Destructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
~SoundBuffer();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Load the sound buffer from a file
|
||||||
|
///
|
||||||
|
/// See the documentation of `sf::InputSoundFile` for the list
|
||||||
|
/// of supported formats.
|
||||||
|
///
|
||||||
|
/// \param filename Path of the sound file to load
|
||||||
|
///
|
||||||
|
/// \return `true` if loading succeeded, `false` if it failed
|
||||||
|
///
|
||||||
|
/// \see `loadFromMemory`, `loadFromStream`, `loadFromSamples`, `saveToFile`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool loadFromFile(const std::filesystem::path& filename);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Load the sound buffer from a file in memory
|
||||||
|
///
|
||||||
|
/// See the documentation of `sf::InputSoundFile` for the list
|
||||||
|
/// of supported formats.
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the file data in memory
|
||||||
|
/// \param sizeInBytes Size of the data to load, in bytes
|
||||||
|
///
|
||||||
|
/// \return `true` if loading succeeded, `false` if it failed
|
||||||
|
///
|
||||||
|
/// \see `loadFromFile`, `loadFromStream`, `loadFromSamples`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool loadFromMemory(const void* data, std::size_t sizeInBytes);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Load the sound buffer from a custom stream
|
||||||
|
///
|
||||||
|
/// See the documentation of `sf::InputSoundFile` for the list
|
||||||
|
/// of supported formats.
|
||||||
|
///
|
||||||
|
/// \param stream Source stream to read from
|
||||||
|
///
|
||||||
|
/// \return `true` if loading succeeded, `false` if it failed
|
||||||
|
///
|
||||||
|
/// \see `loadFromFile`, `loadFromMemory`, `loadFromSamples`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool loadFromStream(InputStream& stream);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Load the sound buffer from an array of audio samples
|
||||||
|
///
|
||||||
|
/// The assumed format of the audio samples is 16 bit signed integer.
|
||||||
|
///
|
||||||
|
/// \param samples Pointer to the array of samples in memory
|
||||||
|
/// \param sampleCount Number of samples in the array
|
||||||
|
/// \param channelCount Number of channels (1 = mono, 2 = stereo, ...)
|
||||||
|
/// \param sampleRate Sample rate (number of samples to play per second)
|
||||||
|
/// \param channelMap Map of position in sample frame to sound channel
|
||||||
|
///
|
||||||
|
/// \return `true` if loading succeeded, `false` if it failed
|
||||||
|
///
|
||||||
|
/// \see `loadFromFile`, `loadFromMemory`, `saveToFile`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool loadFromSamples(const std::int16_t* samples,
|
||||||
|
std::uint64_t sampleCount,
|
||||||
|
unsigned int channelCount,
|
||||||
|
unsigned int sampleRate,
|
||||||
|
const std::vector<SoundChannel>& channelMap);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Save the sound buffer to an audio file
|
||||||
|
///
|
||||||
|
/// See the documentation of `sf::OutputSoundFile` for the list
|
||||||
|
/// of supported formats.
|
||||||
|
///
|
||||||
|
/// \param filename Path of the sound file to write
|
||||||
|
///
|
||||||
|
/// \return `true` if saving succeeded, `false` if it failed
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool saveToFile(const std::filesystem::path& filename) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the array of audio samples stored in the buffer
|
||||||
|
///
|
||||||
|
/// The format of the returned samples is 16 bit signed integer.
|
||||||
|
/// The total number of samples in this array is given by the
|
||||||
|
/// `getSampleCount()` function.
|
||||||
|
///
|
||||||
|
/// \return Read-only pointer to the array of sound samples
|
||||||
|
///
|
||||||
|
/// \see `getSampleCount`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const std::int16_t* getSamples() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the number of samples stored in the buffer
|
||||||
|
///
|
||||||
|
/// The array of samples can be accessed with the `getSamples()`
|
||||||
|
/// function.
|
||||||
|
///
|
||||||
|
/// \return Number of samples
|
||||||
|
///
|
||||||
|
/// \see `getSamples`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] std::uint64_t getSampleCount() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the sample rate of the sound
|
||||||
|
///
|
||||||
|
/// The sample rate is the number of samples played per second.
|
||||||
|
/// The higher, the better the quality (for example, 44100
|
||||||
|
/// samples/s is CD quality).
|
||||||
|
///
|
||||||
|
/// \return Sample rate (number of samples per second)
|
||||||
|
///
|
||||||
|
/// \see `getChannelCount`, `getChannelMap`, `getDuration`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] unsigned int getSampleRate() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the number of channels used by the sound
|
||||||
|
///
|
||||||
|
/// If the sound is mono then the number of channels will
|
||||||
|
/// be 1, 2 for stereo, etc.
|
||||||
|
///
|
||||||
|
/// \return Number of channels
|
||||||
|
///
|
||||||
|
/// \see `getSampleRate`, `getChannelMap`, `getDuration`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] unsigned int getChannelCount() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the map of position in sample frame to sound channel
|
||||||
|
///
|
||||||
|
/// This is used to map a sample in the sample stream to a
|
||||||
|
/// position during spatialization.
|
||||||
|
///
|
||||||
|
/// \return Map of position in sample frame to sound channel
|
||||||
|
///
|
||||||
|
/// \see `getSampleRate`, `getChannelCount`, `getDuration`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] std::vector<SoundChannel> getChannelMap() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the total duration of the sound
|
||||||
|
///
|
||||||
|
/// \return Sound duration
|
||||||
|
///
|
||||||
|
/// \see `getSampleRate`, `getChannelCount`, `getChannelMap`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Time getDuration() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Overload of assignment operator
|
||||||
|
///
|
||||||
|
/// \param right Instance to assign
|
||||||
|
///
|
||||||
|
/// \return Reference to self
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SoundBuffer& operator=(const SoundBuffer& right);
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class Sound;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Initialize the internal state after loading a new sound
|
||||||
|
///
|
||||||
|
/// \param file Sound file providing access to the new loaded sound
|
||||||
|
///
|
||||||
|
/// \return `true` on successful initialization, `false` on failure
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool initialize(InputSoundFile& file);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Update the internal buffer with the cached audio samples
|
||||||
|
///
|
||||||
|
/// \param channelCount Number of channels
|
||||||
|
/// \param sampleRate Sample rate (number of samples per second)
|
||||||
|
/// \param channelMap Map of position in sample frame to sound channel
|
||||||
|
///
|
||||||
|
/// \return `true` on success, `false` if any error happened
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool update(unsigned int channelCount, unsigned int sampleRate, const std::vector<SoundChannel>& channelMap);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Add a sound to the list of sounds that use this buffer
|
||||||
|
///
|
||||||
|
/// \param sound Sound instance to attach
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void attachSound(Sound* sound) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Remove a sound from the list of sounds that use this buffer
|
||||||
|
///
|
||||||
|
/// \param sound Sound instance to detach
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void detachSound(Sound* sound) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Types
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
using SoundList = std::unordered_set<Sound*>; //!< Set of unique sound instances
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::vector<std::int16_t> m_samples; //!< Samples buffer
|
||||||
|
unsigned int m_sampleRate{44100}; //!< Number of samples per second
|
||||||
|
std::vector<SoundChannel> m_channelMap{SoundChannel::Mono}; //!< The map of position in sample frame to sound channel
|
||||||
|
Time m_duration; //!< Sound duration
|
||||||
|
mutable SoundList m_sounds; //!< List of sounds that are using this buffer
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::SoundBuffer
|
||||||
|
/// \ingroup audio
|
||||||
|
///
|
||||||
|
/// A sound buffer holds the data of a sound, which is
|
||||||
|
/// an array of audio samples. A sample is a 16 bit signed integer
|
||||||
|
/// that defines the amplitude of the sound at a given time.
|
||||||
|
/// The sound is then reconstituted by playing these samples at
|
||||||
|
/// a high rate (for example, 44100 samples per second is the
|
||||||
|
/// standard rate used for playing CDs). In short, audio samples
|
||||||
|
/// are like texture pixels, and a `sf::SoundBuffer` is similar to
|
||||||
|
/// a `sf::Texture`.
|
||||||
|
///
|
||||||
|
/// A sound buffer can be loaded from a file, from memory, from
|
||||||
|
/// a custom stream (see `sf::InputStream`) or directly from an array
|
||||||
|
/// of samples. It can also be saved back to a file.
|
||||||
|
///
|
||||||
|
/// Sound buffers alone are not very useful: they hold the audio data
|
||||||
|
/// but cannot be played. To do so, you need to use the `sf::Sound` class,
|
||||||
|
/// which provides functions to play/pause/stop the sound as well as
|
||||||
|
/// changing the way it is outputted (volume, pitch, 3D position, ...).
|
||||||
|
/// This separation allows more flexibility and better performances:
|
||||||
|
/// indeed a `sf::SoundBuffer` is a heavy resource, and any operation on it
|
||||||
|
/// is slow (often too slow for real-time applications). On the other
|
||||||
|
/// side, a `sf::Sound` is a lightweight object, which can use the audio data
|
||||||
|
/// of a sound buffer and change the way it is played without actually
|
||||||
|
/// modifying that data. Note that it is also possible to bind
|
||||||
|
/// several `sf::Sound` instances to the same `sf::SoundBuffer`.
|
||||||
|
///
|
||||||
|
/// It is important to note that the `sf::Sound` instance doesn't
|
||||||
|
/// copy the buffer that it uses, it only keeps a reference to it.
|
||||||
|
/// Thus, a `sf::SoundBuffer` must not be destructed while it is
|
||||||
|
/// used by a `sf::Sound` (i.e. never write a function that
|
||||||
|
/// uses a local `sf::SoundBuffer` instance for loading a sound).
|
||||||
|
///
|
||||||
|
/// When loading sound samples from an array, a channel map needs to be
|
||||||
|
/// provided, which specifies the mapping of the position in the sample frame
|
||||||
|
/// to the sound channel. For example when you have six samples in a frame and
|
||||||
|
/// a 5.1 sound system, the channel map defines how each of those samples map
|
||||||
|
/// to which speaker channel.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// // Load a new sound buffer from a file
|
||||||
|
/// const sf::SoundBuffer buffer("sound.wav");
|
||||||
|
///
|
||||||
|
/// // Create a sound source bound to the buffer
|
||||||
|
/// sf::Sound sound1(buffer);
|
||||||
|
///
|
||||||
|
/// // Play the sound
|
||||||
|
/// sound1.play();
|
||||||
|
///
|
||||||
|
/// // Create another sound source bound to the same buffer
|
||||||
|
/// sf::Sound sound2(buffer);
|
||||||
|
///
|
||||||
|
/// // Play it with a higher pitch -- the first sound remains unchanged
|
||||||
|
/// sound2.setPitch(2);
|
||||||
|
/// sound2.play();
|
||||||
|
///
|
||||||
|
/// // Load samples with a channel map
|
||||||
|
/// auto samples = std::vector<std::int16_t>();
|
||||||
|
/// // ...
|
||||||
|
/// auto channelMap = std::vector<sf::SoundChannel>{
|
||||||
|
/// sf::SoundChannel::FrontLeft,
|
||||||
|
/// sf::SoundChannel::FrontCenter,
|
||||||
|
/// sf::SoundChannel::FrontRight,
|
||||||
|
/// sf::SoundChannel::BackRight,
|
||||||
|
/// sf::SoundChannel::BackLeft,
|
||||||
|
/// sf::SoundChannel::LowFrequencyEffects
|
||||||
|
/// };
|
||||||
|
/// auto soundBuffer = sf::SoundBuffer(samples.data(), samples.size(), channelMap.size(), 44100, channelMap);
|
||||||
|
/// auto sound = sf::Sound(soundBuffer);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::Sound`, `sf::SoundBufferRecorder`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,149 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Audio/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Audio/SoundBuffer.hpp>
|
||||||
|
#include <SFML/Audio/SoundRecorder.hpp>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Specialized SoundRecorder which stores the captured
|
||||||
|
/// audio data into a sound buffer
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_AUDIO_API SoundBufferRecorder : public SoundRecorder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief destructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
~SoundBufferRecorder() override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the sound buffer containing the captured audio data
|
||||||
|
///
|
||||||
|
/// The sound buffer is valid only after the capture has ended.
|
||||||
|
/// This function provides a read-only access to the internal
|
||||||
|
/// sound buffer, but it can be copied if you need to
|
||||||
|
/// make any modification to it.
|
||||||
|
///
|
||||||
|
/// \return Read-only access to the sound buffer
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const SoundBuffer& getBuffer() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Start capturing audio data
|
||||||
|
///
|
||||||
|
/// \return `true` to start the capture, or `false` to abort it
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool onStart() override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Process a new chunk of recorded samples
|
||||||
|
///
|
||||||
|
/// \param samples Pointer to the new chunk of recorded samples
|
||||||
|
/// \param sampleCount Number of samples pointed by \a samples
|
||||||
|
///
|
||||||
|
/// \return `true` to continue the capture, or `false` to stop it
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool onProcessSamples(const std::int16_t* samples, std::size_t sampleCount) override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Stop capturing audio data
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void onStop() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::vector<std::int16_t> m_samples; //!< Temporary sample buffer to hold the recorded data
|
||||||
|
SoundBuffer m_buffer; //!< Sound buffer that will contain the recorded data
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::SoundBufferRecorder
|
||||||
|
/// \ingroup audio
|
||||||
|
///
|
||||||
|
/// `sf::SoundBufferRecorder` allows to access a recorded sound
|
||||||
|
/// through a `sf::SoundBuffer`, so that it can be played, saved
|
||||||
|
/// to a file, etc.
|
||||||
|
///
|
||||||
|
/// It has the same simple interface as its base class (`start()`, `stop()`)
|
||||||
|
/// and adds a function to retrieve the recorded sound buffer
|
||||||
|
/// (`getBuffer()`).
|
||||||
|
///
|
||||||
|
/// As usual, don't forget to call the `isAvailable()` function
|
||||||
|
/// before using this class (see `sf::SoundRecorder` for more details
|
||||||
|
/// about this).
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// if (sf::SoundBufferRecorder::isAvailable())
|
||||||
|
/// {
|
||||||
|
/// // Record some audio data
|
||||||
|
/// sf::SoundBufferRecorder recorder;
|
||||||
|
/// if (!recorder.start())
|
||||||
|
/// {
|
||||||
|
/// // Handle error...
|
||||||
|
/// }
|
||||||
|
/// ...
|
||||||
|
/// recorder.stop();
|
||||||
|
///
|
||||||
|
/// // Get the buffer containing the captured audio data
|
||||||
|
/// const sf::SoundBuffer& buffer = recorder.getBuffer();
|
||||||
|
///
|
||||||
|
/// // Save it to a file (for example...)
|
||||||
|
/// if (!buffer.saveToFile("my_record.ogg"))
|
||||||
|
/// {
|
||||||
|
/// // Handle error...
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::SoundRecorder`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \ingroup audio
|
||||||
|
/// \brief Types of sound channels that can be read/written from sound buffers/files
|
||||||
|
///
|
||||||
|
/// In multi-channel audio, each sound channel can be
|
||||||
|
/// assigned a position. The position of the channel is
|
||||||
|
/// used to determine where to place a sound when it
|
||||||
|
/// is spatialized. Assigning an incorrect sound channel
|
||||||
|
/// will result in multi-channel audio being positioned
|
||||||
|
/// incorrectly when using spatialization.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
enum class SoundChannel
|
||||||
|
{
|
||||||
|
Unspecified,
|
||||||
|
Mono,
|
||||||
|
FrontLeft,
|
||||||
|
FrontRight,
|
||||||
|
FrontCenter,
|
||||||
|
FrontLeftOfCenter,
|
||||||
|
FrontRightOfCenter,
|
||||||
|
LowFrequencyEffects,
|
||||||
|
BackLeft,
|
||||||
|
BackRight,
|
||||||
|
BackCenter,
|
||||||
|
SideLeft,
|
||||||
|
SideRight,
|
||||||
|
TopCenter,
|
||||||
|
TopFrontLeft,
|
||||||
|
TopFrontRight,
|
||||||
|
TopFrontCenter,
|
||||||
|
TopBackLeft,
|
||||||
|
TopBackRight,
|
||||||
|
TopBackCenter
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
@ -0,0 +1,200 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Audio/Export.hpp>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class InputStream;
|
||||||
|
class SoundFileReader;
|
||||||
|
class SoundFileWriter;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Manages and instantiates sound file readers and writers
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_AUDIO_API SoundFileFactory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Register a new reader
|
||||||
|
///
|
||||||
|
/// \see `unregisterReader`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
static void registerReader();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Unregister a reader
|
||||||
|
///
|
||||||
|
/// \see `registerReader`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
static void unregisterReader();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Check if a reader is registered
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
[[nodiscard]] static bool isReaderRegistered();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Register a new writer
|
||||||
|
///
|
||||||
|
/// \see `unregisterWriter`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
static void registerWriter();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Unregister a writer
|
||||||
|
///
|
||||||
|
/// \see `registerWriter`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
static void unregisterWriter();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Check if a writer is registered
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
[[nodiscard]] static bool isWriterRegistered();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Instantiate the right reader for the given file on disk
|
||||||
|
///
|
||||||
|
/// \param filename Path of the sound file
|
||||||
|
///
|
||||||
|
/// \return A new sound file reader that can read the given file, or null if no reader can handle it
|
||||||
|
///
|
||||||
|
/// \see `createReaderFromMemory`, `createReaderFromStream`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] static std::unique_ptr<SoundFileReader> createReaderFromFilename(const std::filesystem::path& filename);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Instantiate the right codec for the given file in memory
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the file data in memory
|
||||||
|
/// \param sizeInBytes Total size of the file data, in bytes
|
||||||
|
///
|
||||||
|
/// \return A new sound file codec that can read the given file, or null if no codec can handle it
|
||||||
|
///
|
||||||
|
/// \see `createReaderFromFilename`, `createReaderFromStream`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] static std::unique_ptr<SoundFileReader> createReaderFromMemory(const void* data, std::size_t sizeInBytes);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Instantiate the right codec for the given file in stream
|
||||||
|
///
|
||||||
|
/// \param stream Source stream to read from
|
||||||
|
///
|
||||||
|
/// \return A new sound file codec that can read the given file, or null if no codec can handle it
|
||||||
|
///
|
||||||
|
/// \see `createReaderFromFilename`, `createReaderFromMemory`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] static std::unique_ptr<SoundFileReader> createReaderFromStream(InputStream& stream);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Instantiate the right writer for the given file on disk
|
||||||
|
///
|
||||||
|
/// \param filename Path of the sound file
|
||||||
|
///
|
||||||
|
/// \return A new sound file writer that can write given file, or null if no writer can handle it
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] static std::unique_ptr<SoundFileWriter> createWriterFromFilename(const std::filesystem::path& filename);
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Types
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
using CreateFnPtr = std::unique_ptr<T> (*)();
|
||||||
|
|
||||||
|
using ReaderCheckFnPtr = bool (*)(InputStream&);
|
||||||
|
using WriterCheckFnPtr = bool (*)(const std::filesystem::path&);
|
||||||
|
|
||||||
|
using ReaderFactoryMap = std::unordered_map<CreateFnPtr<SoundFileReader>, ReaderCheckFnPtr>;
|
||||||
|
using WriterFactoryMap = std::unordered_map<CreateFnPtr<SoundFileWriter>, WriterCheckFnPtr>;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Static member functions
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] static ReaderFactoryMap& getReaderFactoryMap();
|
||||||
|
[[nodiscard]] static WriterFactoryMap& getWriterFactoryMap();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
#include <SFML/Audio/SoundFileFactory.inl>
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::SoundFileFactory
|
||||||
|
/// \ingroup audio
|
||||||
|
///
|
||||||
|
/// This class is where all the sound file readers and writers are
|
||||||
|
/// registered. You should normally only need to use its registration
|
||||||
|
/// and unregistration functions; readers/writers creation and manipulation
|
||||||
|
/// are wrapped into the higher-level classes `sf::InputSoundFile` and
|
||||||
|
/// `sf::OutputSoundFile`.
|
||||||
|
///
|
||||||
|
/// To register a new reader (writer) use the `sf::SoundFileFactory::registerReader`
|
||||||
|
/// (`registerWriter`) static function. You don't have to call the `unregisterReader`
|
||||||
|
/// (`unregisterWriter`) function, unless you want to unregister a format before your
|
||||||
|
/// application ends (typically, when a plugin is unloaded).
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// sf::SoundFileFactory::registerReader<MySoundFileReader>();
|
||||||
|
/// assert(sf::SoundFileFactory::isReaderRegistered<MySoundFileReader>());
|
||||||
|
///
|
||||||
|
/// sf::SoundFileFactory::registerWriter<MySoundFileWriter>();
|
||||||
|
/// assert(sf::SoundFileFactory::isWriterRegistered<MySoundFileWriter>());
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::InputSoundFile`, `sf::OutputSoundFile`, `sf::SoundFileReader`, `sf::SoundFileWriter`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Audio/SoundFileFactory.hpp> // NOLINT(misc-header-include-cycle)
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
namespace priv
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
std::unique_ptr<SoundFileReader> createReader()
|
||||||
|
{
|
||||||
|
return std::make_unique<T>();
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
std::unique_ptr<SoundFileWriter> createWriter()
|
||||||
|
{
|
||||||
|
return std::make_unique<T>();
|
||||||
|
}
|
||||||
|
} // namespace priv
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
void SoundFileFactory::registerReader()
|
||||||
|
{
|
||||||
|
getReaderFactoryMap()[&priv::createReader<T>] = &T::check;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
void SoundFileFactory::unregisterReader()
|
||||||
|
{
|
||||||
|
getReaderFactoryMap().erase(&priv::createReader<T>);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
bool SoundFileFactory::isReaderRegistered()
|
||||||
|
{
|
||||||
|
return getReaderFactoryMap().count(&priv::createReader<T>) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
void SoundFileFactory::registerWriter()
|
||||||
|
{
|
||||||
|
getWriterFactoryMap()[&priv::createWriter<T>] = &T::check;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
void SoundFileFactory::unregisterWriter()
|
||||||
|
{
|
||||||
|
getWriterFactoryMap().erase(&priv::createWriter<T>);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
bool SoundFileFactory::isWriterRegistered()
|
||||||
|
{
|
||||||
|
return getWriterFactoryMap().count(&priv::createWriter<T>) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
@ -0,0 +1,167 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Audio/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Audio/SoundChannel.hpp>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class InputStream;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Abstract base class for sound file decoding
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_AUDIO_API SoundFileReader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Structure holding the audio properties of a sound file
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
struct Info
|
||||||
|
{
|
||||||
|
std::uint64_t sampleCount{}; //!< Total number of samples in the file
|
||||||
|
unsigned int channelCount{}; //!< Number of channels of the sound
|
||||||
|
unsigned int sampleRate{}; //!< Samples rate of the sound, in samples per second
|
||||||
|
std::vector<SoundChannel> channelMap; //!< Map of position in sample frame to sound channel
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Virtual destructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
virtual ~SoundFileReader() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Open a sound file for reading
|
||||||
|
///
|
||||||
|
/// The provided stream reference is valid as long as the
|
||||||
|
/// `SoundFileReader` is alive, so it is safe to use/store it
|
||||||
|
/// during the whole lifetime of the reader.
|
||||||
|
///
|
||||||
|
/// \param stream Source stream to read from
|
||||||
|
///
|
||||||
|
/// \return Properties of the loaded sound if the file was successfully opened
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] virtual std::optional<Info> open(InputStream& stream) = 0;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Change the current read position to the given sample offset
|
||||||
|
///
|
||||||
|
/// The sample offset takes the channels into account.
|
||||||
|
/// If you have a time offset instead, you can easily find
|
||||||
|
/// the corresponding sample offset with the following formula:
|
||||||
|
/// `timeInSeconds * sampleRate * channelCount`
|
||||||
|
/// If the given offset exceeds to total number of samples,
|
||||||
|
/// this function must jump to the end of the file.
|
||||||
|
///
|
||||||
|
/// \param sampleOffset Index of the sample to jump to, relative to the beginning
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
virtual void seek(std::uint64_t sampleOffset) = 0;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Read audio samples from the open file
|
||||||
|
///
|
||||||
|
/// \param samples Pointer to the sample array to fill
|
||||||
|
/// \param maxCount Maximum number of samples to read
|
||||||
|
///
|
||||||
|
/// \return Number of samples actually read (may be less than \a maxCount)
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] virtual std::uint64_t read(std::int16_t* samples, std::uint64_t maxCount) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::SoundFileReader
|
||||||
|
/// \ingroup audio
|
||||||
|
///
|
||||||
|
/// This class allows users to read audio file formats not natively
|
||||||
|
/// supported by SFML, and thus extend the set of supported readable
|
||||||
|
/// audio formats.
|
||||||
|
///
|
||||||
|
/// A valid sound file reader must override the open, seek and write functions,
|
||||||
|
/// as well as providing a static check function; the latter is used by
|
||||||
|
/// SFML to find a suitable writer for a given input file.
|
||||||
|
///
|
||||||
|
/// To register a new reader, use the `sf::SoundFileFactory::registerReader`
|
||||||
|
/// template function.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// class MySoundFileReader : public sf::SoundFileReader
|
||||||
|
/// {
|
||||||
|
/// public:
|
||||||
|
///
|
||||||
|
/// [[nodiscard]] static bool check(sf::InputStream& stream)
|
||||||
|
/// {
|
||||||
|
/// // typically, read the first few header bytes and check fields that identify the format
|
||||||
|
/// // return true if the reader can handle the format
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// [[nodiscard]] std::optional<sf::SoundFileReader::Info> open(sf::InputStream& stream) override
|
||||||
|
/// {
|
||||||
|
/// // read the sound file header and fill the sound attributes
|
||||||
|
/// // (channel count, sample count and sample rate)
|
||||||
|
/// // return true on success
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// void seek(std::uint64_t sampleOffset) override
|
||||||
|
/// {
|
||||||
|
/// // advance to the sampleOffset-th sample from the beginning of the
|
||||||
|
/// sound
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// std::uint64_t read(std::int16_t* samples, std::uint64_t maxCount) override
|
||||||
|
/// {
|
||||||
|
/// // read up to 'maxCount' samples into the 'samples' array,
|
||||||
|
/// // convert them (for example from normalized float) if they are not stored
|
||||||
|
/// // as 16-bits signed integers in the file
|
||||||
|
/// // return the actual number of samples read
|
||||||
|
/// }
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// sf::SoundFileFactory::registerReader<MySoundFileReader>();
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::InputSoundFile`, `sf::SoundFileFactory`, `sf::SoundFileWriter`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,130 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Audio/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Audio/SoundChannel.hpp>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Abstract base class for sound file encoding
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_AUDIO_API SoundFileWriter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Virtual destructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
virtual ~SoundFileWriter() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Open a sound file for writing
|
||||||
|
///
|
||||||
|
/// \param filename Path of the file to open
|
||||||
|
/// \param sampleRate Sample rate of the sound
|
||||||
|
/// \param channelCount Number of channels of the sound
|
||||||
|
/// \param channelMap Map of position in sample frame to sound channel
|
||||||
|
///
|
||||||
|
/// \return `true` if the file was successfully opened
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] virtual bool open(const std::filesystem::path& filename,
|
||||||
|
unsigned int sampleRate,
|
||||||
|
unsigned int channelCount,
|
||||||
|
const std::vector<SoundChannel>& channelMap) = 0;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Write audio samples to the open file
|
||||||
|
///
|
||||||
|
/// \param samples Pointer to the sample array to write
|
||||||
|
/// \param count Number of samples to write
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
virtual void write(const std::int16_t* samples, std::uint64_t count) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::SoundFileWriter
|
||||||
|
/// \ingroup audio
|
||||||
|
///
|
||||||
|
/// This class allows users to write audio file formats not natively
|
||||||
|
/// supported by SFML, and thus extend the set of supported writable
|
||||||
|
/// audio formats.
|
||||||
|
///
|
||||||
|
/// A valid sound file writer must override the open and write functions,
|
||||||
|
/// as well as providing a static check function; the latter is used by
|
||||||
|
/// SFML to find a suitable writer for a given filename.
|
||||||
|
///
|
||||||
|
/// To register a new writer, use the `sf::SoundFileFactory::registerWriter`
|
||||||
|
/// template function.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// class MySoundFileWriter : public sf::SoundFileWriter
|
||||||
|
/// {
|
||||||
|
/// public:
|
||||||
|
///
|
||||||
|
/// [[nodiscard]] static bool check(const std::filesystem::path& filename)
|
||||||
|
/// {
|
||||||
|
/// // typically, check the extension
|
||||||
|
/// // return true if the writer can handle the format
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// [[nodiscard]] bool open(const std::filesystem::path& filename, unsigned int sampleRate, unsigned int channelCount, const std::vector<SoundChannel>& channelMap) override
|
||||||
|
/// {
|
||||||
|
/// // open the file 'filename' for writing,
|
||||||
|
/// // write the given sample rate and channel count to the file header
|
||||||
|
/// // return true on success
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// void write(const std::int16_t* samples, std::uint64_t count) override
|
||||||
|
/// {
|
||||||
|
/// // write 'count' samples stored at address 'samples',
|
||||||
|
/// // convert them (for example to normalized float) if the format requires it
|
||||||
|
/// }
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// sf::SoundFileFactory::registerWriter<MySoundFileWriter>();
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::OutputSoundFile`, `sf::SoundFileFactory`, `sf::SoundFileReader`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,362 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Audio/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Audio/SoundChannel.hpp>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Abstract base class for capturing sound data
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_AUDIO_API SoundRecorder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief destructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
virtual ~SoundRecorder();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Start the capture
|
||||||
|
///
|
||||||
|
/// The `sampleRate` parameter defines the number of audio samples
|
||||||
|
/// captured per second. The higher, the better the quality
|
||||||
|
/// (for example, 44100 samples/sec is CD quality).
|
||||||
|
/// This function uses its own thread so that it doesn't block
|
||||||
|
/// the rest of the program while the capture runs.
|
||||||
|
/// Please note that only one capture can happen at the same time.
|
||||||
|
/// You can select which capture device will be used by passing
|
||||||
|
/// the name to the `setDevice()` method. If none was selected
|
||||||
|
/// before, the default capture device will be used. You can get a
|
||||||
|
/// list of the names of all available capture devices by calling
|
||||||
|
/// `getAvailableDevices()`.
|
||||||
|
///
|
||||||
|
/// \param sampleRate Desired capture rate, in number of samples per second
|
||||||
|
///
|
||||||
|
/// \return `true`, if start of capture was successful
|
||||||
|
///
|
||||||
|
/// \see `stop`, `getAvailableDevices`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool start(unsigned int sampleRate = 44100);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Stop the capture
|
||||||
|
///
|
||||||
|
/// \see `start`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the sample rate
|
||||||
|
///
|
||||||
|
/// The sample rate defines the number of audio samples
|
||||||
|
/// captured per second. The higher, the better the quality
|
||||||
|
/// (for example, 44100 samples/sec is CD quality).
|
||||||
|
///
|
||||||
|
/// \return Sample rate, in samples per second
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] unsigned int getSampleRate() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get a list of the names of all available audio capture devices
|
||||||
|
///
|
||||||
|
/// This function returns a vector of strings, containing
|
||||||
|
/// the names of all available audio capture devices.
|
||||||
|
///
|
||||||
|
/// \return A vector of strings containing the names
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] static std::vector<std::string> getAvailableDevices();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the name of the default audio capture device
|
||||||
|
///
|
||||||
|
/// This function returns the name of the default audio
|
||||||
|
/// capture device. If none is available, an empty string
|
||||||
|
/// is returned.
|
||||||
|
///
|
||||||
|
/// \return The name of the default audio capture device
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] static std::string getDefaultDevice();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the audio capture device
|
||||||
|
///
|
||||||
|
/// This function sets the audio capture device to the device
|
||||||
|
/// with the given `name`. It can be called on the fly (i.e:
|
||||||
|
/// while recording). If you do so while recording and
|
||||||
|
/// opening the device fails, it stops the recording.
|
||||||
|
///
|
||||||
|
/// \param name The name of the audio capture device
|
||||||
|
///
|
||||||
|
/// \return `true`, if it was able to set the requested device
|
||||||
|
///
|
||||||
|
/// \see `getAvailableDevices`, `getDefaultDevice`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool setDevice(const std::string& name);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the name of the current audio capture device
|
||||||
|
///
|
||||||
|
/// \return The name of the current audio capture device
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const std::string& getDevice() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the channel count of the audio capture device
|
||||||
|
///
|
||||||
|
/// This method allows you to specify the number of channels
|
||||||
|
/// used for recording. Currently only 16-bit mono and
|
||||||
|
/// 16-bit stereo are supported.
|
||||||
|
///
|
||||||
|
/// \param channelCount Number of channels. Currently only
|
||||||
|
/// mono (1) and stereo (2) are supported.
|
||||||
|
///
|
||||||
|
/// \see `getChannelCount`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setChannelCount(unsigned int channelCount);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the number of channels used by this recorder
|
||||||
|
///
|
||||||
|
/// Currently only mono and stereo are supported, so the
|
||||||
|
/// value is either 1 (for mono) or 2 (for stereo).
|
||||||
|
///
|
||||||
|
/// \return Number of channels
|
||||||
|
///
|
||||||
|
/// \see `setChannelCount`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] unsigned int getChannelCount() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the map of position in sample frame to sound channel
|
||||||
|
///
|
||||||
|
/// This is used to map a sample in the sample stream to a
|
||||||
|
/// position during spatialization.
|
||||||
|
///
|
||||||
|
/// \return Map of position in sample frame to sound channel
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const std::vector<SoundChannel>& getChannelMap() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Check if the system supports audio capture
|
||||||
|
///
|
||||||
|
/// This function should always be called before using
|
||||||
|
/// the audio capture features. If it returns `false`, then
|
||||||
|
/// any attempt to use `sf::SoundRecorder` or one of its derived
|
||||||
|
/// classes will fail.
|
||||||
|
///
|
||||||
|
/// \return `true` if audio capture is supported, `false` otherwise
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] static bool isAvailable();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// This constructor is only meant to be called by derived classes.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SoundRecorder();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Start capturing audio data
|
||||||
|
///
|
||||||
|
/// This virtual function may be overridden by a derived class
|
||||||
|
/// if something has to be done every time a new capture
|
||||||
|
/// starts. If not, this function can be ignored; the default
|
||||||
|
/// implementation does nothing.
|
||||||
|
///
|
||||||
|
/// \return `true` to start the capture, or `false` to abort it
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
virtual bool onStart();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Process a new chunk of recorded samples
|
||||||
|
///
|
||||||
|
/// This virtual function is called every time a new chunk of
|
||||||
|
/// recorded data is available. The derived class can then do
|
||||||
|
/// whatever it wants with it (storing it, playing it, sending
|
||||||
|
/// it over the network, etc.).
|
||||||
|
///
|
||||||
|
/// \param samples Pointer to the new chunk of recorded samples
|
||||||
|
/// \param sampleCount Number of samples pointed by `samples`
|
||||||
|
///
|
||||||
|
/// \return `true` to continue the capture, or `false` to stop it
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] virtual bool onProcessSamples(const std::int16_t* samples, std::size_t sampleCount) = 0;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Stop capturing audio data
|
||||||
|
///
|
||||||
|
/// This virtual function may be overridden by a derived class
|
||||||
|
/// if something has to be done every time the capture
|
||||||
|
/// ends. If not, this function can be ignored; the default
|
||||||
|
/// implementation does nothing.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
virtual void onStop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
struct Impl;
|
||||||
|
const std::unique_ptr<Impl> m_impl; //!< Implementation details
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::SoundRecorder
|
||||||
|
/// \ingroup audio
|
||||||
|
///
|
||||||
|
/// `sf::SoundBuffer` provides a simple interface to access
|
||||||
|
/// the audio recording capabilities of the computer
|
||||||
|
/// (the microphone). As an abstract base class, it only cares
|
||||||
|
/// about capturing sound samples, the task of making something
|
||||||
|
/// useful with them is left to the derived class. Note that
|
||||||
|
/// SFML provides a built-in specialization for saving the
|
||||||
|
/// captured data to a sound buffer (see `sf::SoundBufferRecorder`).
|
||||||
|
///
|
||||||
|
/// A derived class has only one virtual function to override:
|
||||||
|
/// \li `onProcessSamples` provides the new chunks of audio samples while the capture happens
|
||||||
|
///
|
||||||
|
/// Moreover, two additional virtual functions can be overridden
|
||||||
|
/// as well if necessary:
|
||||||
|
/// \li `onStart` is called before the capture happens, to perform custom initializations
|
||||||
|
/// \li `onStop` is called after the capture ends, to perform custom cleanup
|
||||||
|
///
|
||||||
|
/// The audio capture feature may not be supported or activated
|
||||||
|
/// on every platform, thus it is recommended to check its
|
||||||
|
/// availability with the isAvailable() function. If it returns
|
||||||
|
/// `false`, then any attempt to use an audio recorder will fail.
|
||||||
|
///
|
||||||
|
/// If you have multiple sound input devices connected to your
|
||||||
|
/// computer (for example: microphone, external sound card, webcam mic, ...)
|
||||||
|
/// you can get a list of all available devices through the
|
||||||
|
/// `getAvailableDevices()` function. You can then select a device
|
||||||
|
/// by calling `setDevice()` with the appropriate device. Otherwise
|
||||||
|
/// the default capturing device will be used.
|
||||||
|
///
|
||||||
|
/// By default the recording is in 16-bit mono. Using the
|
||||||
|
/// setChannelCount method you can change the number of channels
|
||||||
|
/// used by the audio capture device to record. Note that you
|
||||||
|
/// have to decide whether you want to record in mono or stereo
|
||||||
|
/// before starting the recording.
|
||||||
|
///
|
||||||
|
/// It is important to note that the audio capture happens in a
|
||||||
|
/// separate thread, so that it doesn't block the rest of the
|
||||||
|
/// program. In particular, the `onProcessSamples` virtual function
|
||||||
|
/// (but not `onStart` and not `onStop`) will be called
|
||||||
|
/// from this separate thread. It is important to keep this in
|
||||||
|
/// mind, because you may have to take care of synchronization
|
||||||
|
/// issues if you share data between threads.
|
||||||
|
/// Another thing to bear in mind is that you must call `stop()`
|
||||||
|
/// in the destructor of your derived class, so that the recording
|
||||||
|
/// thread finishes before your object is destroyed.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// class CustomRecorder : public sf::SoundRecorder
|
||||||
|
/// {
|
||||||
|
/// public:
|
||||||
|
/// ~CustomRecorder()
|
||||||
|
/// {
|
||||||
|
/// // Make sure to stop the recording thread
|
||||||
|
/// stop();
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// private:
|
||||||
|
/// bool onStart() override // optional
|
||||||
|
/// {
|
||||||
|
/// // Initialize whatever has to be done before the capture starts
|
||||||
|
/// ...
|
||||||
|
///
|
||||||
|
/// // Return true to start playing
|
||||||
|
/// return true;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// [[nodiscard]] bool onProcessSamples(const std::int16_t* samples, std::size_t sampleCount) override
|
||||||
|
/// {
|
||||||
|
/// // Do something with the new chunk of samples (store them, send them, ...)
|
||||||
|
/// ...
|
||||||
|
///
|
||||||
|
/// // Return true to continue playing
|
||||||
|
/// return true;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// void onStop() override // optional
|
||||||
|
/// {
|
||||||
|
/// // Clean up whatever has to be done after the capture ends
|
||||||
|
/// ...
|
||||||
|
/// }
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// // Usage
|
||||||
|
/// if (CustomRecorder::isAvailable())
|
||||||
|
/// {
|
||||||
|
/// CustomRecorder recorder;
|
||||||
|
///
|
||||||
|
/// if (!recorder.start())
|
||||||
|
/// return -1;
|
||||||
|
///
|
||||||
|
/// ...
|
||||||
|
/// recorder.stop();
|
||||||
|
/// }
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::SoundBufferRecorder`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,686 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Audio/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Audio/AudioResource.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/Angle.hpp>
|
||||||
|
#include <SFML/System/Vector3.hpp>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
// NOLINTBEGIN(readability-make-member-function-const)
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Base class defining a sound's properties
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_AUDIO_API SoundSource : protected AudioResource
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Enumeration of the sound source states
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
enum class Status
|
||||||
|
{
|
||||||
|
Stopped, //!< Sound is not playing
|
||||||
|
Paused, //!< Sound is paused
|
||||||
|
Playing //!< Sound is playing
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Structure defining the properties of a directional cone
|
||||||
|
///
|
||||||
|
/// Sounds will play at gain 1 when the listener
|
||||||
|
/// is positioned within the inner angle of the cone.
|
||||||
|
/// Sounds will play at `outerGain` when the listener is
|
||||||
|
/// positioned outside the outer angle of the cone.
|
||||||
|
/// The gain declines linearly from 1 to `outerGain` as the
|
||||||
|
/// listener moves from the inner angle to the outer angle.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
struct Cone
|
||||||
|
{
|
||||||
|
Angle innerAngle; //!< Inner angle
|
||||||
|
Angle outerAngle; //!< Outer angle
|
||||||
|
float outerGain{}; //!< Outer gain
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Callable that is provided with sound data for processing
|
||||||
|
///
|
||||||
|
/// When the audio engine sources sound data from sound
|
||||||
|
/// sources it will pass the data through an effects
|
||||||
|
/// processor if one is set. The sound data will already be
|
||||||
|
/// converted to the internal floating point format.
|
||||||
|
///
|
||||||
|
/// Sound data that is processed this way is provided in
|
||||||
|
/// frames. Each frame contains 1 floating point sample per
|
||||||
|
/// channel. If e.g. the data source provides stereo data,
|
||||||
|
/// each frame will contain 2 floats.
|
||||||
|
///
|
||||||
|
/// The effects processor function takes 4 parameters:
|
||||||
|
/// - The input data frames, channels interleaved
|
||||||
|
/// - The number of input data frames available
|
||||||
|
/// - The buffer to write output data frames to, channels interleaved
|
||||||
|
/// - The number of output data frames that the output buffer can hold
|
||||||
|
/// - The channel count
|
||||||
|
///
|
||||||
|
/// The input and output frame counts are in/out parameters.
|
||||||
|
///
|
||||||
|
/// When this function is called, the input count will
|
||||||
|
/// contain the number of frames available in the input
|
||||||
|
/// buffer. The output count will contain the size of the
|
||||||
|
/// output buffer i.e. the maximum number of frames that
|
||||||
|
/// can be written to the output buffer.
|
||||||
|
///
|
||||||
|
/// Attempting to read more frames than the input frame
|
||||||
|
/// count or write more frames than the output frame count
|
||||||
|
/// will result in undefined behaviour.
|
||||||
|
///
|
||||||
|
/// It is important to note that the channel count of the
|
||||||
|
/// audio engine currently sourcing data from this sound
|
||||||
|
/// will always be provided in `frameChannelCount`. This can
|
||||||
|
/// be different from the channel count of the sound source
|
||||||
|
/// so make sure to size necessary processing buffers
|
||||||
|
/// according to the engine channel count and not the sound
|
||||||
|
/// source channel count.
|
||||||
|
///
|
||||||
|
/// When done processing the frames, the input and output
|
||||||
|
/// frame counts must be updated to reflect the actual
|
||||||
|
/// number of frames that were read from the input and
|
||||||
|
/// written to the output.
|
||||||
|
///
|
||||||
|
/// The processing function should always try to process as
|
||||||
|
/// much sound data as possible i.e. always try to fill the
|
||||||
|
/// output buffer to the maximum. In certain situations for
|
||||||
|
/// specific effects it can be possible that the input frame
|
||||||
|
/// count and output frame count aren't equal. As long as
|
||||||
|
/// the frame counts are updated accordingly this is
|
||||||
|
/// perfectly valid.
|
||||||
|
///
|
||||||
|
/// If the audio engine determines that no audio data is
|
||||||
|
/// available from the data source, the input data frames
|
||||||
|
/// pointer is set to `nullptr` and the input frame count is
|
||||||
|
/// set to 0. In this case it is up to the function to
|
||||||
|
/// decide how to handle the situation. For specific effects
|
||||||
|
/// e.g. Echo/Delay buffered data might still be able to be
|
||||||
|
/// written to the output buffer even if there is no longer
|
||||||
|
/// any input data.
|
||||||
|
///
|
||||||
|
/// An important thing to remember is that this function is
|
||||||
|
/// directly called by the audio engine. Because the audio
|
||||||
|
/// engine runs on an internal thread of its own, make sure
|
||||||
|
/// access to shared data is synchronized appropriately.
|
||||||
|
///
|
||||||
|
/// Because this function is stored by the `SoundSource`
|
||||||
|
/// object it will be able to be called as long as the
|
||||||
|
/// `SoundSource` object hasn't yet been destroyed. Make sure
|
||||||
|
/// that any data this function references outlives the
|
||||||
|
/// SoundSource object otherwise use-after-free errors will
|
||||||
|
/// occur.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
using EffectProcessor = std::function<
|
||||||
|
void(const float* inputFrames, unsigned int& inputFrameCount, float* outputFrames, unsigned int& outputFrameCount, unsigned int frameChannelCount)>;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Copy constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SoundSource(const SoundSource&) = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SoundSource(SoundSource&&) noexcept = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move assignment
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SoundSource& operator=(SoundSource&&) noexcept = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Destructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
virtual ~SoundSource() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the pitch of the sound
|
||||||
|
///
|
||||||
|
/// The pitch represents the perceived fundamental frequency
|
||||||
|
/// of a sound; thus you can make a sound more acute or grave
|
||||||
|
/// by changing its pitch. A side effect of changing the pitch
|
||||||
|
/// is to modify the playing speed of the sound as well.
|
||||||
|
/// The default value for the pitch is 1.
|
||||||
|
///
|
||||||
|
/// \param pitch New pitch to apply to the sound
|
||||||
|
///
|
||||||
|
/// \see `getPitch`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setPitch(float pitch);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the pan of the sound
|
||||||
|
///
|
||||||
|
/// Using panning, a mono sound can be panned between
|
||||||
|
/// stereo channels. When the pan is set to -1, the sound
|
||||||
|
/// is played only on the left channel, when the pan is set
|
||||||
|
/// to +1, the sound is played only on the right channel.
|
||||||
|
///
|
||||||
|
/// \param pan New pan to apply to the sound [-1, +1]
|
||||||
|
///
|
||||||
|
/// \see `getPan`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setPan(float pan);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the volume of the sound
|
||||||
|
///
|
||||||
|
/// The volume is a value between 0 (mute) and 100 (full volume).
|
||||||
|
/// The default value for the volume is 100.
|
||||||
|
///
|
||||||
|
/// \param volume Volume of the sound
|
||||||
|
///
|
||||||
|
/// \see `getVolume`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setVolume(float volume);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set whether spatialization of the sound is enabled
|
||||||
|
///
|
||||||
|
/// Spatialization is the application of various effects to
|
||||||
|
/// simulate a sound being emitted at a virtual position in
|
||||||
|
/// 3D space and exhibiting various physical phenomena such as
|
||||||
|
/// directional attenuation and doppler shift.
|
||||||
|
///
|
||||||
|
/// \param enabled `true` to enable spatialization, `false` to disable
|
||||||
|
///
|
||||||
|
/// \see `isSpatializationEnabled`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setSpatializationEnabled(bool enabled);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the 3D position of the sound in the audio scene
|
||||||
|
///
|
||||||
|
/// Only sounds with one channel (mono sounds) can be
|
||||||
|
/// spatialized.
|
||||||
|
/// The default position of a sound is (0, 0, 0).
|
||||||
|
///
|
||||||
|
/// \param position Position of the sound in the scene
|
||||||
|
///
|
||||||
|
/// \see `getPosition`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setPosition(const Vector3f& position);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the 3D direction of the sound in the audio scene
|
||||||
|
///
|
||||||
|
/// The direction defines where the sound source is facing
|
||||||
|
/// in 3D space. It will affect how the sound is attenuated
|
||||||
|
/// if facing away from the listener.
|
||||||
|
/// The default direction of a sound is (0, 0, -1).
|
||||||
|
///
|
||||||
|
/// \param direction Direction of the sound in the scene
|
||||||
|
///
|
||||||
|
/// \see `getDirection`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setDirection(const Vector3f& direction);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the cone properties of the sound in the audio scene
|
||||||
|
///
|
||||||
|
/// The cone defines how directional attenuation is applied.
|
||||||
|
/// The default cone of a sound is (2 * PI, 2 * PI, 1).
|
||||||
|
///
|
||||||
|
/// \param cone Cone properties of the sound in the scene
|
||||||
|
///
|
||||||
|
/// \see `getCone`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setCone(const Cone& cone);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the 3D velocity of the sound in the audio scene
|
||||||
|
///
|
||||||
|
/// The velocity is used to determine how to doppler shift
|
||||||
|
/// the sound. Sounds moving towards the listener will be
|
||||||
|
/// perceived to have a higher pitch and sounds moving away
|
||||||
|
/// from the listener will be perceived to have a lower pitch.
|
||||||
|
///
|
||||||
|
/// \param velocity Velocity of the sound in the scene
|
||||||
|
///
|
||||||
|
/// \see `getVelocity`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setVelocity(const Vector3f& velocity);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the doppler factor of the sound
|
||||||
|
///
|
||||||
|
/// The doppler factor determines how strong the doppler
|
||||||
|
/// shift will be.
|
||||||
|
///
|
||||||
|
/// \param factor New doppler factor to apply to the sound
|
||||||
|
///
|
||||||
|
/// \see `getDopplerFactor`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setDopplerFactor(float factor);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the directional attenuation factor of the sound
|
||||||
|
///
|
||||||
|
/// Depending on the virtual position of an output channel
|
||||||
|
/// relative to the listener (such as in surround sound
|
||||||
|
/// setups), sounds will be attenuated when emitting them
|
||||||
|
/// from certain channels. This factor determines how strong
|
||||||
|
/// the attenuation based on output channel position
|
||||||
|
/// relative to the listener is.
|
||||||
|
///
|
||||||
|
/// \param factor New directional attenuation factor to apply to the sound
|
||||||
|
///
|
||||||
|
/// \see `getDirectionalAttenuationFactor`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setDirectionalAttenuationFactor(float factor);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Make the sound's position relative to the listener or absolute
|
||||||
|
///
|
||||||
|
/// Making a sound relative to the listener will ensure that it will always
|
||||||
|
/// be played the same way regardless of the position of the listener.
|
||||||
|
/// This can be useful for non-spatialized sounds, sounds that are
|
||||||
|
/// produced by the listener, or sounds attached to it.
|
||||||
|
/// The default value is `false` (position is absolute).
|
||||||
|
///
|
||||||
|
/// \param relative `true` to set the position relative, `false` to set it absolute
|
||||||
|
///
|
||||||
|
/// \see `isRelativeToListener`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setRelativeToListener(bool relative);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the minimum distance of the sound
|
||||||
|
///
|
||||||
|
/// The "minimum distance" of a sound is the maximum
|
||||||
|
/// distance at which it is heard at its maximum volume. Further
|
||||||
|
/// than the minimum distance, it will start to fade out according
|
||||||
|
/// to its attenuation factor. A value of 0 ("inside the head
|
||||||
|
/// of the listener") is an invalid value and is forbidden.
|
||||||
|
/// The default value of the minimum distance is 1.
|
||||||
|
///
|
||||||
|
/// \param distance New minimum distance of the sound
|
||||||
|
///
|
||||||
|
/// \see `getMinDistance`, `setAttenuation`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setMinDistance(float distance);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the maximum distance of the sound
|
||||||
|
///
|
||||||
|
/// The "maximum distance" of a sound is the minimum
|
||||||
|
/// distance at which it is heard at its minimum volume. Closer
|
||||||
|
/// than the maximum distance, it will start to fade in according
|
||||||
|
/// to its attenuation factor.
|
||||||
|
/// The default value of the maximum distance is the maximum
|
||||||
|
/// value a float can represent.
|
||||||
|
///
|
||||||
|
/// \param distance New maximum distance of the sound
|
||||||
|
///
|
||||||
|
/// \see `getMaxDistance`, `setAttenuation`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setMaxDistance(float distance);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the minimum gain of the sound
|
||||||
|
///
|
||||||
|
/// When the sound is further away from the listener than
|
||||||
|
/// the "maximum distance" the attenuated gain is clamped
|
||||||
|
/// so it cannot go below the minimum gain value.
|
||||||
|
///
|
||||||
|
/// \param gain New minimum gain of the sound
|
||||||
|
///
|
||||||
|
/// \see `getMinGain`, `setAttenuation`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setMinGain(float gain);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the maximum gain of the sound
|
||||||
|
///
|
||||||
|
/// When the sound is closer from the listener than
|
||||||
|
/// the "minimum distance" the attenuated gain is clamped
|
||||||
|
/// so it cannot go above the maximum gain value.
|
||||||
|
///
|
||||||
|
/// \param gain New maximum gain of the sound
|
||||||
|
///
|
||||||
|
/// \see `getMaxGain`, `setAttenuation`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setMaxGain(float gain);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the attenuation factor of the sound
|
||||||
|
///
|
||||||
|
/// The attenuation is a multiplicative factor which makes
|
||||||
|
/// the sound more or less loud according to its distance
|
||||||
|
/// from the listener. An attenuation of 0 will produce a
|
||||||
|
/// non-attenuated sound, i.e. its volume will always be the same
|
||||||
|
/// whether it is heard from near or from far. On the other hand,
|
||||||
|
/// an attenuation value such as 100 will make the sound fade out
|
||||||
|
/// very quickly as it gets further from the listener.
|
||||||
|
/// The default value of the attenuation is 1.
|
||||||
|
///
|
||||||
|
/// \param attenuation New attenuation factor of the sound
|
||||||
|
///
|
||||||
|
/// \see `getAttenuation`, `setMinDistance`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setAttenuation(float attenuation);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the effect processor to be applied to the sound
|
||||||
|
///
|
||||||
|
/// The effect processor is a callable that will be called
|
||||||
|
/// with sound data to be processed.
|
||||||
|
///
|
||||||
|
/// \param effectProcessor The effect processor to attach to this sound, attach an empty processor to disable processing
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
virtual void setEffectProcessor(EffectProcessor effectProcessor);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the pitch of the sound
|
||||||
|
///
|
||||||
|
/// \return Pitch of the sound
|
||||||
|
///
|
||||||
|
/// \see `setPitch`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] float getPitch() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the pan of the sound
|
||||||
|
///
|
||||||
|
/// \return Pan of the sound
|
||||||
|
///
|
||||||
|
/// \see `setPan`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] float getPan() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the volume of the sound
|
||||||
|
///
|
||||||
|
/// \return Volume of the sound, in the range [0, 100]
|
||||||
|
///
|
||||||
|
/// \see `setVolume`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] float getVolume() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Tell whether spatialization of the sound is enabled
|
||||||
|
///
|
||||||
|
/// \return `true` if spatialization is enabled, `false` if it's disabled
|
||||||
|
///
|
||||||
|
/// \see `setSpatializationEnabled`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool isSpatializationEnabled() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the 3D position of the sound in the audio scene
|
||||||
|
///
|
||||||
|
/// \return Position of the sound
|
||||||
|
///
|
||||||
|
/// \see `setPosition`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Vector3f getPosition() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the 3D direction of the sound in the audio scene
|
||||||
|
///
|
||||||
|
/// \return Direction of the sound
|
||||||
|
///
|
||||||
|
/// \see `setDirection`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Vector3f getDirection() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the cone properties of the sound in the audio scene
|
||||||
|
///
|
||||||
|
/// \return Cone properties of the sound
|
||||||
|
///
|
||||||
|
/// \see `setCone`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Cone getCone() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the 3D velocity of the sound in the audio scene
|
||||||
|
///
|
||||||
|
/// \return Velocity of the sound
|
||||||
|
///
|
||||||
|
/// \see `setVelocity`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Vector3f getVelocity() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the doppler factor of the sound
|
||||||
|
///
|
||||||
|
/// \return Doppler factor of the sound
|
||||||
|
///
|
||||||
|
/// \see `setDopplerFactor`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] float getDopplerFactor() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the directional attenuation factor of the sound
|
||||||
|
///
|
||||||
|
/// \return Directional attenuation factor of the sound
|
||||||
|
///
|
||||||
|
/// \see `setDirectionalAttenuationFactor`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] float getDirectionalAttenuationFactor() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Tell whether the sound's position is relative to the
|
||||||
|
/// listener or is absolute
|
||||||
|
///
|
||||||
|
/// \return `true` if the position is relative, `false` if it's absolute
|
||||||
|
///
|
||||||
|
/// \see `setRelativeToListener`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool isRelativeToListener() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the minimum distance of the sound
|
||||||
|
///
|
||||||
|
/// \return Minimum distance of the sound
|
||||||
|
///
|
||||||
|
/// \see `setMinDistance`, `getAttenuation`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] float getMinDistance() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the maximum distance of the sound
|
||||||
|
///
|
||||||
|
/// \return Maximum distance of the sound
|
||||||
|
///
|
||||||
|
/// \see `setMaxDistance`, `getAttenuation`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] float getMaxDistance() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the minimum gain of the sound
|
||||||
|
///
|
||||||
|
/// \return Minimum gain of the sound
|
||||||
|
///
|
||||||
|
/// \see `setMinGain`, `getAttenuation`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] float getMinGain() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the maximum gain of the sound
|
||||||
|
///
|
||||||
|
/// \return Maximum gain of the sound
|
||||||
|
///
|
||||||
|
/// \see `setMaxGain`, `getAttenuation`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] float getMaxGain() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the attenuation factor of the sound
|
||||||
|
///
|
||||||
|
/// \return Attenuation factor of the sound
|
||||||
|
///
|
||||||
|
/// \see `setAttenuation`, `getMinDistance`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] float getAttenuation() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Overload of assignment operator
|
||||||
|
///
|
||||||
|
/// \param right Instance to assign
|
||||||
|
///
|
||||||
|
/// \return Reference to self
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SoundSource& operator=(const SoundSource& right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Start or resume playing the sound source
|
||||||
|
///
|
||||||
|
/// This function starts the source if it was stopped, resumes
|
||||||
|
/// it if it was paused, and restarts it from the beginning if
|
||||||
|
/// it was already playing.
|
||||||
|
///
|
||||||
|
/// \see `pause`, `stop`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
virtual void play() = 0;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Pause the sound source
|
||||||
|
///
|
||||||
|
/// This function pauses the source if it was playing,
|
||||||
|
/// otherwise (source already paused or stopped) it has no effect.
|
||||||
|
///
|
||||||
|
/// \see `play`, `stop`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
virtual void pause() = 0;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Stop playing the sound source
|
||||||
|
///
|
||||||
|
/// This function stops the source if it was playing or paused,
|
||||||
|
/// and does nothing if it was already stopped.
|
||||||
|
/// It also resets the playing position (unlike `pause()`).
|
||||||
|
///
|
||||||
|
/// \see `play`, `pause`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
virtual void stop() = 0;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the current status of the sound (stopped, paused, playing)
|
||||||
|
///
|
||||||
|
/// \return Current status of the sound
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] virtual Status getStatus() const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// This constructor is meant to be called by derived classes only.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SoundSource() = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the sound object
|
||||||
|
///
|
||||||
|
/// \return The sound object
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] virtual void* getSound() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// NOLINTEND(readability-make-member-function-const)
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::SoundSource
|
||||||
|
/// \ingroup audio
|
||||||
|
///
|
||||||
|
/// `sf::SoundSource` is not meant to be used directly, it
|
||||||
|
/// only serves as a common base for all audio objects
|
||||||
|
/// that can live in the audio environment.
|
||||||
|
///
|
||||||
|
/// It defines several properties for the sound: pitch,
|
||||||
|
/// volume, position, attenuation, etc. All of them can be
|
||||||
|
/// changed at any time with no impact on performances.
|
||||||
|
///
|
||||||
|
/// \see `sf::Sound`, `sf::SoundStream`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,385 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Audio/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Audio/SoundChannel.hpp>
|
||||||
|
#include <SFML/Audio/SoundSource.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/Time.hpp>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Abstract base class for streamed audio sources
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_AUDIO_API SoundStream : public SoundSource
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Structure defining a chunk of audio data to stream
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
struct Chunk
|
||||||
|
{
|
||||||
|
const std::int16_t* samples{}; //!< Pointer to the audio samples
|
||||||
|
std::size_t sampleCount{}; //!< Number of samples pointed by Samples
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Destructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
~SoundStream() override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SoundStream(SoundStream&&) noexcept;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move assignment
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SoundStream& operator=(SoundStream&&) noexcept;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Start or resume playing the audio stream
|
||||||
|
///
|
||||||
|
/// This function starts the stream if it was stopped, resumes
|
||||||
|
/// it if it was paused, and restarts it from the beginning if
|
||||||
|
/// it was already playing.
|
||||||
|
/// This function uses its own thread so that it doesn't block
|
||||||
|
/// the rest of the program while the stream is played.
|
||||||
|
///
|
||||||
|
/// \see `pause`, `stop`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void play() override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Pause the audio stream
|
||||||
|
///
|
||||||
|
/// This function pauses the stream if it was playing,
|
||||||
|
/// otherwise (stream already paused or stopped) it has no effect.
|
||||||
|
///
|
||||||
|
/// \see `play`, `stop`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void pause() override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Stop playing the audio stream
|
||||||
|
///
|
||||||
|
/// This function stops the stream if it was playing or paused,
|
||||||
|
/// and does nothing if it was already stopped.
|
||||||
|
/// It also resets the playing position (unlike `pause()`).
|
||||||
|
///
|
||||||
|
/// \see `play`, `pause`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void stop() override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Return the number of channels of the stream
|
||||||
|
///
|
||||||
|
/// 1 channel means a mono sound, 2 means stereo, etc.
|
||||||
|
///
|
||||||
|
/// \return Number of channels
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] unsigned int getChannelCount() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the stream sample rate of the stream
|
||||||
|
///
|
||||||
|
/// The sample rate is the number of audio samples played per
|
||||||
|
/// second. The higher, the better the quality.
|
||||||
|
///
|
||||||
|
/// \return Sample rate, in number of samples per second
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] unsigned int getSampleRate() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the map of position in sample frame to sound channel
|
||||||
|
///
|
||||||
|
/// This is used to map a sample in the sample stream to a
|
||||||
|
/// position during spatialization.
|
||||||
|
///
|
||||||
|
/// \return Map of position in sample frame to sound channel
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] std::vector<SoundChannel> getChannelMap() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the current status of the stream (stopped, paused, playing)
|
||||||
|
///
|
||||||
|
/// \return Current status
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Status getStatus() const override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Change the current playing position of the stream
|
||||||
|
///
|
||||||
|
/// The playing position can be changed when the stream is
|
||||||
|
/// either paused or playing. Changing the playing position
|
||||||
|
/// when the stream is stopped has no effect, since playing
|
||||||
|
/// the stream would reset its position.
|
||||||
|
///
|
||||||
|
/// \param timeOffset New playing position, from the beginning of the stream
|
||||||
|
///
|
||||||
|
/// \see `getPlayingOffset`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setPlayingOffset(Time timeOffset);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the current playing position of the stream
|
||||||
|
///
|
||||||
|
/// \return Current playing position, from the beginning of the stream
|
||||||
|
///
|
||||||
|
/// \see `setPlayingOffset`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Time getPlayingOffset() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set whether or not the stream should loop after reaching the end
|
||||||
|
///
|
||||||
|
/// If set, the stream will restart from beginning after
|
||||||
|
/// reaching the end and so on, until it is stopped or
|
||||||
|
/// `setLooping(false)` is called.
|
||||||
|
/// The default looping state for streams is `false`.
|
||||||
|
///
|
||||||
|
/// \param loop `true` to play in loop, `false` to play once
|
||||||
|
///
|
||||||
|
/// \see `isLooping`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setLooping(bool loop);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Tell whether or not the stream is in loop mode
|
||||||
|
///
|
||||||
|
/// \return `true` if the stream is looping, `false` otherwise
|
||||||
|
///
|
||||||
|
/// \see `setLooping`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool isLooping() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the effect processor to be applied to the sound
|
||||||
|
///
|
||||||
|
/// The effect processor is a callable that will be called
|
||||||
|
/// with sound data to be processed.
|
||||||
|
///
|
||||||
|
/// \param effectProcessor The effect processor to attach to this sound, attach an empty processor to disable processing
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setEffectProcessor(EffectProcessor effectProcessor) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// This constructor is only meant to be called by derived classes.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SoundStream();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Define the audio stream parameters
|
||||||
|
///
|
||||||
|
/// This function must be called by derived classes as soon
|
||||||
|
/// as they know the audio settings of the stream to play.
|
||||||
|
/// Any attempt to manipulate the stream (`play()`, ...) before
|
||||||
|
/// calling this function will fail.
|
||||||
|
/// It can be called multiple times if the settings of the
|
||||||
|
/// audio stream change, but only when the stream is stopped.
|
||||||
|
///
|
||||||
|
/// \param channelCount Number of channels of the stream
|
||||||
|
/// \param sampleRate Sample rate, in samples per second
|
||||||
|
/// \param channelMap Map of position in sample frame to sound channel
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void initialize(unsigned int channelCount, unsigned int sampleRate, const std::vector<SoundChannel>& channelMap);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Request a new chunk of audio samples from the stream source
|
||||||
|
///
|
||||||
|
/// This function must be overridden by derived classes to provide
|
||||||
|
/// the audio samples to play. It is called continuously by the
|
||||||
|
/// streaming loop, in a separate thread.
|
||||||
|
/// The source can choose to stop the streaming loop at any time, by
|
||||||
|
/// returning `false` to the caller.
|
||||||
|
/// If you return `true` (i.e. continue streaming) it is important that
|
||||||
|
/// the returned array of samples is not empty; this would stop the stream
|
||||||
|
/// due to an internal limitation.
|
||||||
|
///
|
||||||
|
/// \param data Chunk of data to fill
|
||||||
|
///
|
||||||
|
/// \return `true` to continue playback, `false` to stop
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] virtual bool onGetData(Chunk& data) = 0;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Change the current playing position in the stream source
|
||||||
|
///
|
||||||
|
/// This function must be overridden by derived classes to
|
||||||
|
/// allow random seeking into the stream source.
|
||||||
|
///
|
||||||
|
/// \param timeOffset New playing position, relative to the beginning of the stream
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
virtual void onSeek(Time timeOffset) = 0;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Change the current playing position in the stream source to the beginning of the loop
|
||||||
|
///
|
||||||
|
/// This function can be overridden by derived classes to
|
||||||
|
/// allow implementation of custom loop points. Otherwise,
|
||||||
|
/// it just calls `onSeek(Time::Zero)` and returns 0.
|
||||||
|
///
|
||||||
|
/// \return The seek position after looping (or `std::nullopt` if there's no loop)
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
virtual std::optional<std::uint64_t> onLoop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the sound object
|
||||||
|
///
|
||||||
|
/// \return The sound object
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] void* getSound() const override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
struct Impl;
|
||||||
|
std::unique_ptr<Impl> m_impl; //!< Implementation details
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::SoundStream
|
||||||
|
/// \ingroup audio
|
||||||
|
///
|
||||||
|
/// Unlike audio buffers (see `sf::SoundBuffer`), audio streams
|
||||||
|
/// are never completely loaded in memory. Instead, the audio
|
||||||
|
/// data is acquired continuously while the stream is playing.
|
||||||
|
/// This behavior allows to play a sound with no loading delay,
|
||||||
|
/// and keeps the memory consumption very low.
|
||||||
|
///
|
||||||
|
/// Sound sources that need to be streamed are usually big files
|
||||||
|
/// (compressed audio musics that would eat hundreds of MB in memory)
|
||||||
|
/// or files that would take a lot of time to be received
|
||||||
|
/// (sounds played over the network).
|
||||||
|
///
|
||||||
|
/// `sf::SoundStream` is a base class that doesn't care about the
|
||||||
|
/// stream source, which is left to the derived class. SFML provides
|
||||||
|
/// a built-in specialization for big files (see `sf::Music`).
|
||||||
|
/// No network stream source is provided, but you can write your own
|
||||||
|
/// by combining this class with the network module.
|
||||||
|
///
|
||||||
|
/// A derived class has to override two virtual functions:
|
||||||
|
/// \li `onGetData` fills a new chunk of audio data to be played
|
||||||
|
/// \li `onSeek` changes the current playing position in the source
|
||||||
|
///
|
||||||
|
/// It is important to note that each SoundStream is played in its
|
||||||
|
/// own separate thread, so that the streaming loop doesn't block the
|
||||||
|
/// rest of the program. In particular, the `onGetData` and `onSeek`
|
||||||
|
/// virtual functions may sometimes be called from this separate thread.
|
||||||
|
/// It is important to keep this in mind, because you may have to take
|
||||||
|
/// care of synchronization issues if you share data between threads.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// class CustomStream : public sf::SoundStream
|
||||||
|
/// {
|
||||||
|
/// public:
|
||||||
|
///
|
||||||
|
/// [[nodiscard]] bool open(const std::string& location)
|
||||||
|
/// {
|
||||||
|
/// // Open the source and get audio settings
|
||||||
|
/// ...
|
||||||
|
/// unsigned int channelCount = 2; // Stereo
|
||||||
|
/// unsigned int sampleRate = 44100; // 44100 Hz
|
||||||
|
///
|
||||||
|
/// // Initialize the stream -- important!
|
||||||
|
/// initialize(channelCount, sampleRate, {sf::SoundChannel::FrontLeft, sf::SoundChannel::FrontRight});
|
||||||
|
/// return true;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// private:
|
||||||
|
///
|
||||||
|
/// bool onGetData(Chunk& data) override
|
||||||
|
/// {
|
||||||
|
/// // Fill the chunk with audio data from the stream source
|
||||||
|
/// // (note: must not be empty if you want to continue playing)
|
||||||
|
/// data.samples = ...;
|
||||||
|
///
|
||||||
|
/// // Return true to continue playing
|
||||||
|
/// data.sampleCount = ...;
|
||||||
|
/// return true;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// void onSeek(sf::Time timeOffset) override
|
||||||
|
/// {
|
||||||
|
/// // Change the current position in the stream source
|
||||||
|
/// ...
|
||||||
|
/// }
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// // Usage
|
||||||
|
/// CustomStream stream;
|
||||||
|
/// stream.open("path/to/stream");
|
||||||
|
/// stream.play();
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::Music`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,164 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// SFML version
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#define SFML_VERSION_MAJOR 3
|
||||||
|
#define SFML_VERSION_MINOR 0
|
||||||
|
#define SFML_VERSION_PATCH 1
|
||||||
|
#define SFML_VERSION_IS_RELEASE true
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Identify the operating system
|
||||||
|
// see https://sourceforge.net/p/predef/wiki/Home/
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#if defined(_WIN32)
|
||||||
|
|
||||||
|
// Windows
|
||||||
|
#define SFML_SYSTEM_WINDOWS
|
||||||
|
#ifndef NOMINMAX
|
||||||
|
#define NOMINMAX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(__APPLE__) && defined(__MACH__)
|
||||||
|
|
||||||
|
// Apple platform, see which one it is
|
||||||
|
#include "TargetConditionals.h"
|
||||||
|
|
||||||
|
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
|
||||||
|
|
||||||
|
// iOS
|
||||||
|
#define SFML_SYSTEM_IOS
|
||||||
|
|
||||||
|
#elif TARGET_OS_MAC
|
||||||
|
|
||||||
|
// macOS
|
||||||
|
#define SFML_SYSTEM_MACOS
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// Unsupported Apple system
|
||||||
|
#error This Apple operating system is not supported by SFML library
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(__unix__)
|
||||||
|
|
||||||
|
// UNIX system, see which one it is
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
|
||||||
|
// Android
|
||||||
|
#define SFML_SYSTEM_ANDROID
|
||||||
|
|
||||||
|
#elif defined(__linux__)
|
||||||
|
|
||||||
|
// Linux
|
||||||
|
#define SFML_SYSTEM_LINUX
|
||||||
|
|
||||||
|
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||||
|
|
||||||
|
// FreeBSD
|
||||||
|
#define SFML_SYSTEM_FREEBSD
|
||||||
|
|
||||||
|
#elif defined(__OpenBSD__)
|
||||||
|
|
||||||
|
// OpenBSD
|
||||||
|
#define SFML_SYSTEM_OPENBSD
|
||||||
|
|
||||||
|
#elif defined(__NetBSD__)
|
||||||
|
|
||||||
|
// NetBSD
|
||||||
|
#define SFML_SYSTEM_NETBSD
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// Unsupported UNIX system
|
||||||
|
#error This UNIX operating system is not supported by SFML library
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// Unsupported system
|
||||||
|
#error This operating system is not supported by SFML library
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Ensure minimum C++ language standard version is met
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#if (defined(_MSVC_LANG) && _MSVC_LANG < 201703L) || (!defined(_MSVC_LANG) && __cplusplus < 201703L)
|
||||||
|
#error "Enable C++17 or newer for your compiler (e.g. -std=c++17 for GCC/Clang or /std:c++17 for MSVC)"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Portable debug macro
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(NDEBUG)
|
||||||
|
|
||||||
|
#define SFML_DEBUG
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Helpers to create portable import / export macros for each module
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(SFML_STATIC)
|
||||||
|
|
||||||
|
#if defined(SFML_SYSTEM_WINDOWS)
|
||||||
|
|
||||||
|
// Windows compilers need specific (and different) keywords for export and import
|
||||||
|
#define SFML_API_EXPORT __declspec(dllexport)
|
||||||
|
#define SFML_API_IMPORT __declspec(dllimport)
|
||||||
|
|
||||||
|
// For Visual C++ compilers, we also need to turn off this annoying C4251 & C4275 warning
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
|
#pragma warning(disable : 4251) // Using standard library types in our own exported types is okay
|
||||||
|
#pragma warning(disable : 4275) // Exporting types derived from the standard library is okay
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else // Linux, FreeBSD, macOS
|
||||||
|
|
||||||
|
#define SFML_API_EXPORT __attribute__((__visibility__("default")))
|
||||||
|
#define SFML_API_IMPORT __attribute__((__visibility__("default")))
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// Static build doesn't need import/export macros
|
||||||
|
#define SFML_API_EXPORT
|
||||||
|
#define SFML_API_IMPORT
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Config.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \file
|
||||||
|
///
|
||||||
|
/// \brief File containing SFML_DEFINE_DISCRETE_GPU_PREFERENCE
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \def SFML_DEFINE_DISCRETE_GPU_PREFERENCE
|
||||||
|
///
|
||||||
|
/// \brief A macro to encourage usage of the discrete GPU
|
||||||
|
///
|
||||||
|
/// In order to inform the Nvidia/AMD driver that an SFML
|
||||||
|
/// application could benefit from using the more powerful
|
||||||
|
/// discrete GPU, special symbols have to be publicly
|
||||||
|
/// exported from the final executable.
|
||||||
|
///
|
||||||
|
/// SFML defines a helper macro to easily do this.
|
||||||
|
///
|
||||||
|
/// Place `SFML_DEFINE_DISCRETE_GPU_PREFERENCE` in the
|
||||||
|
/// global scope of a source file that will be linked into
|
||||||
|
/// the final executable. Typically it is best to place it
|
||||||
|
/// where the main function is also defined.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#if defined(SFML_SYSTEM_WINDOWS)
|
||||||
|
|
||||||
|
#define SFML_DEFINE_DISCRETE_GPU_PREFERENCE \
|
||||||
|
extern "C" __declspec(dllexport) unsigned long NvOptimusEnablement = 1; \
|
||||||
|
extern "C" __declspec(dllexport) unsigned long AmdPowerXpressRequestHighPerformance = 1;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define SFML_DEFINE_DISCRETE_GPU_PREFERENCE
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <SFML/Graphics/BlendMode.hpp>
|
||||||
|
#include <SFML/Graphics/CircleShape.hpp>
|
||||||
|
#include <SFML/Graphics/Color.hpp>
|
||||||
|
#include <SFML/Graphics/ConvexShape.hpp>
|
||||||
|
#include <SFML/Graphics/Drawable.hpp>
|
||||||
|
#include <SFML/Graphics/Font.hpp>
|
||||||
|
#include <SFML/Graphics/Glyph.hpp>
|
||||||
|
#include <SFML/Graphics/Image.hpp>
|
||||||
|
#include <SFML/Graphics/PrimitiveType.hpp>
|
||||||
|
#include <SFML/Graphics/Rect.hpp>
|
||||||
|
#include <SFML/Graphics/RectangleShape.hpp>
|
||||||
|
#include <SFML/Graphics/RenderStates.hpp>
|
||||||
|
#include <SFML/Graphics/RenderTarget.hpp>
|
||||||
|
#include <SFML/Graphics/RenderTexture.hpp>
|
||||||
|
#include <SFML/Graphics/RenderWindow.hpp>
|
||||||
|
#include <SFML/Graphics/Shader.hpp>
|
||||||
|
#include <SFML/Graphics/Shape.hpp>
|
||||||
|
#include <SFML/Graphics/Sprite.hpp>
|
||||||
|
#include <SFML/Graphics/StencilMode.hpp>
|
||||||
|
#include <SFML/Graphics/Text.hpp>
|
||||||
|
#include <SFML/Graphics/Texture.hpp>
|
||||||
|
#include <SFML/Graphics/Transform.hpp>
|
||||||
|
#include <SFML/Graphics/Transformable.hpp>
|
||||||
|
#include <SFML/Graphics/Vertex.hpp>
|
||||||
|
#include <SFML/Graphics/VertexArray.hpp>
|
||||||
|
#include <SFML/Graphics/VertexBuffer.hpp>
|
||||||
|
#include <SFML/Graphics/View.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Window.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \defgroup graphics Graphics module
|
||||||
|
///
|
||||||
|
/// 2D graphics module: sprites, text, shapes, ...
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,220 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Export.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Blending modes for drawing
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
struct SFML_GRAPHICS_API BlendMode
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////
|
||||||
|
/// \brief Enumeration of the blending factors
|
||||||
|
///
|
||||||
|
/// The factors are mapped directly to their OpenGL equivalents,
|
||||||
|
/// specified by glBlendFunc() or glBlendFuncSeparate().
|
||||||
|
////////////////////////////////////////////////////////
|
||||||
|
enum class Factor
|
||||||
|
{
|
||||||
|
Zero, //!< (0, 0, 0, 0)
|
||||||
|
One, //!< (1, 1, 1, 1)
|
||||||
|
SrcColor, //!< (src.r, src.g, src.b, src.a)
|
||||||
|
OneMinusSrcColor, //!< (1, 1, 1, 1) - (src.r, src.g, src.b, src.a)
|
||||||
|
DstColor, //!< (dst.r, dst.g, dst.b, dst.a)
|
||||||
|
OneMinusDstColor, //!< (1, 1, 1, 1) - (dst.r, dst.g, dst.b, dst.a)
|
||||||
|
SrcAlpha, //!< (src.a, src.a, src.a, src.a)
|
||||||
|
OneMinusSrcAlpha, //!< (1, 1, 1, 1) - (src.a, src.a, src.a, src.a)
|
||||||
|
DstAlpha, //!< (dst.a, dst.a, dst.a, dst.a)
|
||||||
|
OneMinusDstAlpha //!< (1, 1, 1, 1) - (dst.a, dst.a, dst.a, dst.a)
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////
|
||||||
|
/// \brief Enumeration of the blending equations
|
||||||
|
///
|
||||||
|
/// The equations are mapped directly to their OpenGL equivalents,
|
||||||
|
/// specified by glBlendEquation() or glBlendEquationSeparate().
|
||||||
|
////////////////////////////////////////////////////////
|
||||||
|
enum class Equation
|
||||||
|
{
|
||||||
|
Add, //!< Pixel = Src * SrcFactor + Dst * DstFactor
|
||||||
|
Subtract, //!< Pixel = Src * SrcFactor - Dst * DstFactor
|
||||||
|
ReverseSubtract, //!< Pixel = Dst * DstFactor - Src * SrcFactor
|
||||||
|
Min, //!< Pixel = min(Dst, Src)
|
||||||
|
Max //!< Pixel = max(Dst, Src)
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// Constructs a blending mode that does alpha blending.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
BlendMode() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the blend mode given the factors and equation.
|
||||||
|
///
|
||||||
|
/// This constructor uses the same factors and equation for both
|
||||||
|
/// color and alpha components. It also defaults to the Add equation.
|
||||||
|
///
|
||||||
|
/// \param sourceFactor Specifies how to compute the source factor for the color and alpha channels.
|
||||||
|
/// \param destinationFactor Specifies how to compute the destination factor for the color and alpha channels.
|
||||||
|
/// \param blendEquation Specifies how to combine the source and destination colors and alpha.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
BlendMode(Factor sourceFactor, Factor destinationFactor, Equation blendEquation = Equation::Add);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the blend mode given the factors and equation.
|
||||||
|
///
|
||||||
|
/// \param colorSourceFactor Specifies how to compute the source factor for the color channels.
|
||||||
|
/// \param colorDestinationFactor Specifies how to compute the destination factor for the color channels.
|
||||||
|
/// \param colorBlendEquation Specifies how to combine the source and destination colors.
|
||||||
|
/// \param alphaSourceFactor Specifies how to compute the source factor.
|
||||||
|
/// \param alphaDestinationFactor Specifies how to compute the destination factor.
|
||||||
|
/// \param alphaBlendEquation Specifies how to combine the source and destination alphas.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
BlendMode(Factor colorSourceFactor,
|
||||||
|
Factor colorDestinationFactor,
|
||||||
|
Equation colorBlendEquation,
|
||||||
|
Factor alphaSourceFactor,
|
||||||
|
Factor alphaDestinationFactor,
|
||||||
|
Equation alphaBlendEquation);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member Data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Factor colorSrcFactor{BlendMode::Factor::SrcAlpha}; //!< Source blending factor for the color channels
|
||||||
|
Factor colorDstFactor{BlendMode::Factor::OneMinusSrcAlpha}; //!< Destination blending factor for the color channels
|
||||||
|
Equation colorEquation{BlendMode::Equation::Add}; //!< Blending equation for the color channels
|
||||||
|
Factor alphaSrcFactor{BlendMode::Factor::One}; //!< Source blending factor for the alpha channel
|
||||||
|
Factor alphaDstFactor{BlendMode::Factor::OneMinusSrcAlpha}; //!< Destination blending factor for the alpha channel
|
||||||
|
Equation alphaEquation{BlendMode::Equation::Add}; //!< Blending equation for the alpha channel
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates BlendMode
|
||||||
|
/// \brief Overload of the `operator==`
|
||||||
|
///
|
||||||
|
/// \param left Left operand
|
||||||
|
/// \param right Right operand
|
||||||
|
///
|
||||||
|
/// \return `true` if blending modes are equal, `false` if they are different
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] SFML_GRAPHICS_API bool operator==(const BlendMode& left, const BlendMode& right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates BlendMode
|
||||||
|
/// \brief Overload of the `operator!=`
|
||||||
|
///
|
||||||
|
/// \param left Left operand
|
||||||
|
/// \param right Right operand
|
||||||
|
///
|
||||||
|
/// \return `true` if blending modes are different, `false` if they are equal
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] SFML_GRAPHICS_API bool operator!=(const BlendMode& left, const BlendMode& right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Commonly used blending modes
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// NOLINTBEGIN(readability-identifier-naming)
|
||||||
|
SFML_GRAPHICS_API extern const BlendMode BlendAlpha; //!< Blend source and dest according to dest alpha
|
||||||
|
SFML_GRAPHICS_API extern const BlendMode BlendAdd; //!< Add source to dest
|
||||||
|
SFML_GRAPHICS_API extern const BlendMode BlendMultiply; //!< Multiply source and dest
|
||||||
|
SFML_GRAPHICS_API extern const BlendMode BlendMin; //!< Take minimum between source and dest
|
||||||
|
SFML_GRAPHICS_API extern const BlendMode BlendMax; //!< Take maximum between source and dest
|
||||||
|
SFML_GRAPHICS_API extern const BlendMode BlendNone; //!< Overwrite dest with source
|
||||||
|
// NOLINTEND(readability-identifier-naming)
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::BlendMode
|
||||||
|
/// \ingroup graphics
|
||||||
|
///
|
||||||
|
/// `sf::BlendMode` is a class that represents a blend mode. A blend
|
||||||
|
/// mode determines how the colors of an object you draw are
|
||||||
|
/// mixed with the colors that are already in the buffer.
|
||||||
|
///
|
||||||
|
/// The class is composed of 6 components, each of which has its
|
||||||
|
/// own public member variable:
|
||||||
|
/// \li %Color Source Factor (@ref colorSrcFactor)
|
||||||
|
/// \li %Color Destination Factor (@ref colorDstFactor)
|
||||||
|
/// \li %Color Blend Equation (@ref colorEquation)
|
||||||
|
/// \li Alpha Source Factor (@ref alphaSrcFactor)
|
||||||
|
/// \li Alpha Destination Factor (@ref alphaDstFactor)
|
||||||
|
/// \li Alpha Blend Equation (@ref alphaEquation)
|
||||||
|
///
|
||||||
|
/// The source factor specifies how the pixel you are drawing contributes
|
||||||
|
/// to the final color. The destination factor specifies how the pixel
|
||||||
|
/// already drawn in the buffer contributes to the final color.
|
||||||
|
///
|
||||||
|
/// The color channels RGB (red, green, blue; simply referred to as
|
||||||
|
/// color) and A (alpha; the transparency) can be treated separately. This
|
||||||
|
/// separation can be useful for specific blend modes, but most often you
|
||||||
|
/// won't need it and will simply treat the color as a single unit.
|
||||||
|
///
|
||||||
|
/// The blend factors and equations correspond to their OpenGL equivalents.
|
||||||
|
/// In general, the color of the resulting pixel is calculated according
|
||||||
|
/// to the following formula (`src` is the color of the source pixel, `dst`
|
||||||
|
/// the color of the destination pixel, the other variables correspond to the
|
||||||
|
/// public members, with the equations being + or - operators):
|
||||||
|
/// \code
|
||||||
|
/// dst.rgb = colorSrcFactor * src.rgb (colorEquation) colorDstFactor * dst.rgb
|
||||||
|
/// dst.a = alphaSrcFactor * src.a (alphaEquation) alphaDstFactor * dst.a
|
||||||
|
/// \endcode
|
||||||
|
/// All factors and colors are represented as floating point numbers between
|
||||||
|
/// 0 and 1. Where necessary, the result is clamped to fit in that range.
|
||||||
|
///
|
||||||
|
/// The most common blending modes are defined as constants
|
||||||
|
/// in the sf namespace:
|
||||||
|
///
|
||||||
|
/// \code
|
||||||
|
/// sf::BlendMode alphaBlending = sf::BlendAlpha;
|
||||||
|
/// sf::BlendMode additiveBlending = sf::BlendAdd;
|
||||||
|
/// sf::BlendMode multiplicativeBlending = sf::BlendMultiply;
|
||||||
|
/// sf::BlendMode noBlending = sf::BlendNone;
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// In SFML, a blend mode can be specified every time you draw a `sf::Drawable`
|
||||||
|
/// object to a render target. It is part of the `sf::RenderStates` compound
|
||||||
|
/// that is passed to the member function `sf::RenderTarget::draw()`.
|
||||||
|
///
|
||||||
|
/// \see `sf::RenderStates`, `sf::RenderTarget`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,165 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Graphics/Shape.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/Vector2.hpp>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Specialized shape representing a circle
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_GRAPHICS_API CircleShape : public Shape
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// \param radius Radius of the circle
|
||||||
|
/// \param pointCount Number of points composing the circle
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit CircleShape(float radius = 0, std::size_t pointCount = 30);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the radius of the circle
|
||||||
|
///
|
||||||
|
/// \param radius New radius of the circle
|
||||||
|
///
|
||||||
|
/// \see `getRadius`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setRadius(float radius);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the radius of the circle
|
||||||
|
///
|
||||||
|
/// \return Radius of the circle
|
||||||
|
///
|
||||||
|
/// \see `setRadius`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] float getRadius() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the number of points of the circle
|
||||||
|
///
|
||||||
|
/// \param count New number of points of the circle
|
||||||
|
///
|
||||||
|
/// \see `getPointCount`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setPointCount(std::size_t count);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the number of points of the circle
|
||||||
|
///
|
||||||
|
/// \return Number of points of the circle
|
||||||
|
///
|
||||||
|
/// \see `setPointCount`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] std::size_t getPointCount() const override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get a point of the circle
|
||||||
|
///
|
||||||
|
/// The returned point is in local coordinates, that is,
|
||||||
|
/// the shape's transforms (position, rotation, scale) are
|
||||||
|
/// not taken into account.
|
||||||
|
/// The result is undefined if `index` is out of the valid range.
|
||||||
|
///
|
||||||
|
/// \param index Index of the point to get, in range [0 .. getPointCount() - 1]
|
||||||
|
///
|
||||||
|
/// \return `index`-th point of the shape
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Vector2f getPoint(std::size_t index) const override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the geometric center of the circle
|
||||||
|
///
|
||||||
|
/// The returned point is in local coordinates, that is,
|
||||||
|
/// the shape's transforms (position, rotation, scale) are
|
||||||
|
/// not taken into account.
|
||||||
|
///
|
||||||
|
/// \return The geometric center of the shape
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Vector2f getGeometricCenter() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
float m_radius; //!< Radius of the circle
|
||||||
|
std::size_t m_pointCount; //!< Number of points composing the circle
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::CircleShape
|
||||||
|
/// \ingroup graphics
|
||||||
|
///
|
||||||
|
/// This class inherits all the functions of `sf::Transformable`
|
||||||
|
/// (position, rotation, scale, bounds, ...) as well as the
|
||||||
|
/// functions of `sf::Shape` (outline, color, texture, ...).
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// sf::CircleShape circle;
|
||||||
|
/// circle.setRadius(150);
|
||||||
|
/// circle.setOutlineColor(sf::Color::Red);
|
||||||
|
/// circle.setOutlineThickness(5);
|
||||||
|
/// circle.setPosition({10, 20});
|
||||||
|
/// ...
|
||||||
|
/// window.draw(circle);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// Since the graphics card can't draw perfect circles, we have to
|
||||||
|
/// fake them with multiple triangles connected to each other. The
|
||||||
|
/// "points count" property of `sf::CircleShape` defines how many of these
|
||||||
|
/// triangles to use, and therefore defines the quality of the circle.
|
||||||
|
///
|
||||||
|
/// The number of points can also be used for another purpose; with
|
||||||
|
/// small numbers you can create any regular polygon shape:
|
||||||
|
/// equilateral triangle, square, pentagon, hexagon, ...
|
||||||
|
///
|
||||||
|
/// \see `sf::Shape`, `sf::RectangleShape`, `sf::ConvexShape`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,274 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Utility class for manipulating RGBA colors
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class Color
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// Constructs an opaque black color. It is equivalent to
|
||||||
|
/// `sf::Color(0, 0, 0, 255)`.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Color() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the color from its 4 RGBA components
|
||||||
|
///
|
||||||
|
/// \param red Red component (in the range [0, 255])
|
||||||
|
/// \param green Green component (in the range [0, 255])
|
||||||
|
/// \param blue Blue component (in the range [0, 255])
|
||||||
|
/// \param alpha Alpha (opacity) component (in the range [0, 255])
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Color(std::uint8_t red, std::uint8_t green, std::uint8_t blue, std::uint8_t alpha = 255);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the color from 32-bit unsigned integer
|
||||||
|
///
|
||||||
|
/// \param color Number containing the RGBA components (in that order)
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr explicit Color(std::uint32_t color);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Retrieve the color as a 32-bit unsigned integer
|
||||||
|
///
|
||||||
|
/// \return Color represented as a 32-bit unsigned integer
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr std::uint32_t toInteger() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Static member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// NOLINTBEGIN(readability-identifier-naming)
|
||||||
|
static const Color Black; //!< Black predefined color
|
||||||
|
static const Color White; //!< White predefined color
|
||||||
|
static const Color Red; //!< Red predefined color
|
||||||
|
static const Color Green; //!< Green predefined color
|
||||||
|
static const Color Blue; //!< Blue predefined color
|
||||||
|
static const Color Yellow; //!< Yellow predefined color
|
||||||
|
static const Color Magenta; //!< Magenta predefined color
|
||||||
|
static const Color Cyan; //!< Cyan predefined color
|
||||||
|
static const Color Transparent; //!< Transparent (black) predefined color
|
||||||
|
// NOLINTEND(readability-identifier-naming)
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::uint8_t r{}; //!< Red component
|
||||||
|
std::uint8_t g{}; //!< Green component
|
||||||
|
std::uint8_t b{}; //!< Blue component
|
||||||
|
std::uint8_t a{255}; //!< Alpha (opacity) component
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Color
|
||||||
|
/// \brief Overload of the `operator==`
|
||||||
|
///
|
||||||
|
/// This operator compares two colors and check if they are equal.
|
||||||
|
///
|
||||||
|
/// \param left Left operand
|
||||||
|
/// \param right Right operand
|
||||||
|
///
|
||||||
|
/// \return `true` if colors are equal, `false` if they are different
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr bool operator==(Color left, Color right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Color
|
||||||
|
/// \brief Overload of the `operator!=`
|
||||||
|
///
|
||||||
|
/// This operator compares two colors and check if they are different.
|
||||||
|
///
|
||||||
|
/// \param left Left operand
|
||||||
|
/// \param right Right operand
|
||||||
|
///
|
||||||
|
/// \return `true` if colors are different, `false` if they are equal
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr bool operator!=(Color left, Color right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Color
|
||||||
|
/// \brief Overload of the binary `operator+`
|
||||||
|
///
|
||||||
|
/// This operator returns the component-wise sum of two colors.
|
||||||
|
/// Components that exceed 255 are clamped to 255.
|
||||||
|
///
|
||||||
|
/// \param left Left operand
|
||||||
|
/// \param right Right operand
|
||||||
|
///
|
||||||
|
/// \return Result of \a left + \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr Color operator+(Color left, Color right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Color
|
||||||
|
/// \brief Overload of the binary `operator-`
|
||||||
|
///
|
||||||
|
/// This operator returns the component-wise subtraction of two colors.
|
||||||
|
/// Components below 0 are clamped to 0.
|
||||||
|
///
|
||||||
|
/// \param left Left operand
|
||||||
|
/// \param right Right operand
|
||||||
|
///
|
||||||
|
/// \return Result of \a left - \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr Color operator-(Color left, Color right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Color
|
||||||
|
/// \brief Overload of the binary `operator*`
|
||||||
|
///
|
||||||
|
/// This operator returns the component-wise multiplication
|
||||||
|
/// (also called "modulation") of two colors.
|
||||||
|
/// Components are then divided by 255 so that the result is
|
||||||
|
/// still in the range [0, 255].
|
||||||
|
///
|
||||||
|
/// \param left Left operand
|
||||||
|
/// \param right Right operand
|
||||||
|
///
|
||||||
|
/// \return Result of \a left * \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr Color operator*(Color left, Color right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Color
|
||||||
|
/// \brief Overload of the binary `operator+=`
|
||||||
|
///
|
||||||
|
/// This operator computes the component-wise sum of two colors,
|
||||||
|
/// and assigns the result to the left operand.
|
||||||
|
/// Components that exceed 255 are clamped to 255.
|
||||||
|
///
|
||||||
|
/// \param left Left operand
|
||||||
|
/// \param right Right operand
|
||||||
|
///
|
||||||
|
/// \return Reference to \a left
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Color& operator+=(Color& left, Color right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Color
|
||||||
|
/// \brief Overload of the binary `operator-=`
|
||||||
|
///
|
||||||
|
/// This operator computes the component-wise subtraction of two colors,
|
||||||
|
/// and assigns the result to the left operand.
|
||||||
|
/// Components below 0 are clamped to 0.
|
||||||
|
///
|
||||||
|
/// \param left Left operand
|
||||||
|
/// \param right Right operand
|
||||||
|
///
|
||||||
|
/// \return Reference to \a left
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Color& operator-=(Color& left, Color right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Color
|
||||||
|
/// \brief Overload of the binary `operator*=`
|
||||||
|
///
|
||||||
|
/// This operator returns the component-wise multiplication
|
||||||
|
/// (also called "modulation") of two colors, and assigns
|
||||||
|
/// the result to the left operand.
|
||||||
|
/// Components are then divided by 255 so that the result is
|
||||||
|
/// still in the range [0, 255].
|
||||||
|
///
|
||||||
|
/// \param left Left operand
|
||||||
|
/// \param right Right operand
|
||||||
|
///
|
||||||
|
/// \return Reference to \a left
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Color& operator*=(Color& left, Color right);
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
#include <SFML/Graphics/Color.inl>
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::Color
|
||||||
|
/// \ingroup graphics
|
||||||
|
///
|
||||||
|
/// `sf::Color` is a simple color class composed of 4 components:
|
||||||
|
/// \li Red
|
||||||
|
/// \li Green
|
||||||
|
/// \li Blue
|
||||||
|
/// \li Alpha (opacity)
|
||||||
|
///
|
||||||
|
/// Each component is a public member, an unsigned integer in
|
||||||
|
/// the range [0, 255]. Thus, colors can be constructed and
|
||||||
|
/// manipulated very easily:
|
||||||
|
///
|
||||||
|
/// \code
|
||||||
|
/// sf::Color color(255, 0, 0); // red
|
||||||
|
/// color.r = 0; // make it black
|
||||||
|
/// color.b = 128; // make it dark blue
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// The fourth component of colors, named "alpha", represents
|
||||||
|
/// the opacity of the color. A color with an alpha value of
|
||||||
|
/// 255 will be fully opaque, while an alpha value of 0 will
|
||||||
|
/// make a color fully transparent, whatever the value of the
|
||||||
|
/// other components is.
|
||||||
|
///
|
||||||
|
/// The most common colors are already defined as static variables:
|
||||||
|
/// \code
|
||||||
|
/// sf::Color black = sf::Color::Black;
|
||||||
|
/// sf::Color white = sf::Color::White;
|
||||||
|
/// sf::Color red = sf::Color::Red;
|
||||||
|
/// sf::Color green = sf::Color::Green;
|
||||||
|
/// sf::Color blue = sf::Color::Blue;
|
||||||
|
/// sf::Color yellow = sf::Color::Yellow;
|
||||||
|
/// sf::Color magenta = sf::Color::Magenta;
|
||||||
|
/// sf::Color cyan = sf::Color::Cyan;
|
||||||
|
/// sf::Color transparent = sf::Color::Transparent;
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// Colors can also be added and modulated (multiplied) using the
|
||||||
|
/// overloaded operators + and *.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,156 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Color.hpp> // NOLINT(misc-header-include-cycle)
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Color::Color(std::uint8_t red, std::uint8_t green, std::uint8_t blue, std::uint8_t alpha) :
|
||||||
|
r(red),
|
||||||
|
g(green),
|
||||||
|
b(blue),
|
||||||
|
a(alpha)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Color::Color(std::uint32_t color) :
|
||||||
|
r(static_cast<std::uint8_t>((color & 0xff000000) >> 24)),
|
||||||
|
g(static_cast<std::uint8_t>((color & 0x00ff0000) >> 16)),
|
||||||
|
b(static_cast<std::uint8_t>((color & 0x0000ff00) >> 8)),
|
||||||
|
a(static_cast<std::uint8_t>(color & 0x000000ff))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr std::uint32_t Color::toInteger() const
|
||||||
|
{
|
||||||
|
return static_cast<std::uint32_t>((r << 24) | (g << 16) | (b << 8) | a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr bool operator==(Color left, Color right)
|
||||||
|
{
|
||||||
|
return (left.r == right.r) && (left.g == right.g) && (left.b == right.b) && (left.a == right.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr bool operator!=(Color left, Color right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Color operator+(Color left, Color right)
|
||||||
|
{
|
||||||
|
const auto clampedAdd = [](std::uint8_t lhs, std::uint8_t rhs)
|
||||||
|
{
|
||||||
|
const int intResult = int{lhs} + int{rhs};
|
||||||
|
return static_cast<std::uint8_t>(intResult < 255 ? intResult : 255);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {clampedAdd(left.r, right.r),
|
||||||
|
clampedAdd(left.g, right.g),
|
||||||
|
clampedAdd(left.b, right.b),
|
||||||
|
clampedAdd(left.a, right.a)};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Color operator-(Color left, Color right)
|
||||||
|
{
|
||||||
|
const auto clampedSub = [](std::uint8_t lhs, std::uint8_t rhs)
|
||||||
|
{
|
||||||
|
const int intResult = int{lhs} - int{rhs};
|
||||||
|
return static_cast<std::uint8_t>(intResult > 0 ? intResult : 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {clampedSub(left.r, right.r),
|
||||||
|
clampedSub(left.g, right.g),
|
||||||
|
clampedSub(left.b, right.b),
|
||||||
|
clampedSub(left.a, right.a)};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Color operator*(Color left, Color right)
|
||||||
|
{
|
||||||
|
const auto scaledMul = [](std::uint8_t lhs, std::uint8_t rhs)
|
||||||
|
{
|
||||||
|
const auto uint16Result = static_cast<std::uint16_t>(std::uint16_t{lhs} * std::uint16_t{rhs});
|
||||||
|
return static_cast<std::uint8_t>(uint16Result / 255u);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {scaledMul(left.r, right.r), scaledMul(left.g, right.g), scaledMul(left.b, right.b), scaledMul(left.a, right.a)};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Color& operator+=(Color& left, Color right)
|
||||||
|
{
|
||||||
|
return left = left + right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Color& operator-=(Color& left, Color right)
|
||||||
|
{
|
||||||
|
return left = left - right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Color& operator*=(Color& left, Color right)
|
||||||
|
{
|
||||||
|
return left = left * right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Static member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Note: the 'inline' keyword here is technically not required, but VS2019 fails
|
||||||
|
// to compile with a bogus "multiple definition" error if not explicitly used.
|
||||||
|
inline constexpr Color Color::Black(0, 0, 0);
|
||||||
|
inline constexpr Color Color::White(255, 255, 255);
|
||||||
|
inline constexpr Color Color::Red(255, 0, 0);
|
||||||
|
inline constexpr Color Color::Green(0, 255, 0);
|
||||||
|
inline constexpr Color Color::Blue(0, 0, 255);
|
||||||
|
inline constexpr Color Color::Yellow(255, 255, 0);
|
||||||
|
inline constexpr Color Color::Magenta(255, 0, 255);
|
||||||
|
inline constexpr Color Color::Cyan(0, 255, 255);
|
||||||
|
inline constexpr Color Color::Transparent(0, 0, 0, 0);
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
@ -0,0 +1,155 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Graphics/Shape.hpp>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Specialized shape representing a convex polygon
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_GRAPHICS_API ConvexShape : public Shape
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// \param pointCount Number of points of the polygon
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit ConvexShape(std::size_t pointCount = 0);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the number of points of the polygon
|
||||||
|
///
|
||||||
|
/// For the shape to be rendered as expected, `count` must
|
||||||
|
/// be greater or equal to 3.
|
||||||
|
///
|
||||||
|
/// \param count New number of points of the polygon
|
||||||
|
///
|
||||||
|
/// \see `getPointCount`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setPointCount(std::size_t count);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the number of points of the polygon
|
||||||
|
///
|
||||||
|
/// \return Number of points of the polygon
|
||||||
|
///
|
||||||
|
/// \see `setPointCount`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] std::size_t getPointCount() const override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the position of a point
|
||||||
|
///
|
||||||
|
/// Don't forget that the shape must be convex and the
|
||||||
|
/// order of points matters. Points should not overlap.
|
||||||
|
/// This applies to rendering; it is explicitly allowed
|
||||||
|
/// to temporarily have non-convex or degenerate shapes
|
||||||
|
/// when not drawn (e.g. during shape initialization).
|
||||||
|
///
|
||||||
|
/// Point count must be specified beforehand. The behavior is
|
||||||
|
/// undefined if `index` is greater than or equal to getPointCount.
|
||||||
|
///
|
||||||
|
/// \param index Index of the point to change, in range [0 .. getPointCount() - 1]
|
||||||
|
/// \param point New position of the point
|
||||||
|
///
|
||||||
|
/// \see `getPoint`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setPoint(std::size_t index, Vector2f point);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the position of a point
|
||||||
|
///
|
||||||
|
/// The returned point is in local coordinates, that is,
|
||||||
|
/// the shape's transforms (position, rotation, scale) are
|
||||||
|
/// not taken into account.
|
||||||
|
/// The result is undefined if `index` is out of the valid range.
|
||||||
|
///
|
||||||
|
/// \param index Index of the point to get, in range [0 .. getPointCount() - 1]
|
||||||
|
///
|
||||||
|
/// \return Position of the `index`-th point of the polygon
|
||||||
|
///
|
||||||
|
/// \see `setPoint`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Vector2f getPoint(std::size_t index) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::vector<Vector2f> m_points; //!< Points composing the convex polygon
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::ConvexShape
|
||||||
|
/// \ingroup graphics
|
||||||
|
///
|
||||||
|
/// This class inherits all the functions of `sf::Transformable`
|
||||||
|
/// (position, rotation, scale, bounds, ...) as well as the
|
||||||
|
/// functions of `sf::Shape` (outline, color, texture, ...).
|
||||||
|
///
|
||||||
|
/// It is important to keep in mind that a convex shape must
|
||||||
|
/// always be... convex, otherwise it may not be drawn correctly.
|
||||||
|
/// Moreover, the points must be defined in order; using a random
|
||||||
|
/// order would result in an incorrect shape.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// sf::ConvexShape polygon;
|
||||||
|
/// polygon.setPointCount(3);
|
||||||
|
/// polygon.setPoint(0, sf::Vector2f(0, 0));
|
||||||
|
/// polygon.setPoint(1, sf::Vector2f(0, 10));
|
||||||
|
/// polygon.setPoint(2, sf::Vector2f(25, 5));
|
||||||
|
/// polygon.setOutlineColor(sf::Color::Red);
|
||||||
|
/// polygon.setOutlineThickness(5);
|
||||||
|
/// polygon.setPosition({10, 20});
|
||||||
|
/// ...
|
||||||
|
/// window.draw(polygon);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::Shape`, `sf::RectangleShape`, `sf::CircleShape`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \ingroup graphics
|
||||||
|
/// \brief Types of texture coordinates that can be used for rendering
|
||||||
|
///
|
||||||
|
/// \see `sf::Texture::bind`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
enum class CoordinateType
|
||||||
|
{
|
||||||
|
Normalized, //!< Texture coordinates in range [0 .. 1]
|
||||||
|
Pixels //!< Texture coordinates in range [0 .. size]
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
@ -0,0 +1,120 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Export.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class RenderTarget;
|
||||||
|
struct RenderStates;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Abstract base class for objects that can be drawn
|
||||||
|
/// to a render target
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_GRAPHICS_API Drawable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Virtual destructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
virtual ~Drawable() = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
friend class RenderTarget;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Draw the object to a render target
|
||||||
|
///
|
||||||
|
/// This is a pure virtual function that has to be implemented
|
||||||
|
/// by the derived class to define how the drawable should be
|
||||||
|
/// drawn.
|
||||||
|
///
|
||||||
|
/// \param target Render target to draw to
|
||||||
|
/// \param states Current render states
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
virtual void draw(RenderTarget& target, RenderStates states) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::Drawable
|
||||||
|
/// \ingroup graphics
|
||||||
|
///
|
||||||
|
/// `sf::Drawable` is a very simple base class that allows objects
|
||||||
|
/// of derived classes to be drawn to a `sf::RenderTarget`.
|
||||||
|
///
|
||||||
|
/// All you have to do in your derived class is to override the
|
||||||
|
/// draw virtual function.
|
||||||
|
///
|
||||||
|
/// Note that inheriting from `sf::Drawable` is not mandatory,
|
||||||
|
/// but it allows this nice syntax `window.draw(object)` rather
|
||||||
|
/// than `object.draw(window)`, which is more consistent with other
|
||||||
|
/// SFML classes.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// \code
|
||||||
|
/// class MyDrawable : public sf::Drawable
|
||||||
|
/// {
|
||||||
|
/// public:
|
||||||
|
///
|
||||||
|
/// ...
|
||||||
|
///
|
||||||
|
/// private:
|
||||||
|
///
|
||||||
|
/// void draw(sf::RenderTarget& target, sf::RenderStates states) const override
|
||||||
|
/// {
|
||||||
|
/// // You can draw other high-level objects
|
||||||
|
/// target.draw(m_sprite, states);
|
||||||
|
///
|
||||||
|
/// // ... or use the low-level API
|
||||||
|
/// states.texture = &m_texture;
|
||||||
|
/// target.draw(m_vertices, states);
|
||||||
|
///
|
||||||
|
/// // ... or draw with OpenGL directly
|
||||||
|
/// glBegin(GL_TRIANGLES);
|
||||||
|
/// ...
|
||||||
|
/// glEnd();
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// sf::Sprite m_sprite;
|
||||||
|
/// sf::Texture m_texture;
|
||||||
|
/// sf::VertexArray m_vertices;
|
||||||
|
/// };
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::RenderTarget`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Config.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Portable import / export macros
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#if defined(SFML_GRAPHICS_EXPORTS)
|
||||||
|
|
||||||
|
#define SFML_GRAPHICS_API SFML_API_EXPORT
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define SFML_GRAPHICS_API SFML_API_IMPORT
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,529 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Graphics/Glyph.hpp>
|
||||||
|
#include <SFML/Graphics/Rect.hpp>
|
||||||
|
#include <SFML/Graphics/Texture.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/Vector2.hpp>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class InputStream;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Class for loading and manipulating character fonts
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_GRAPHICS_API Font
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Holds various information about a font
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
struct Info
|
||||||
|
{
|
||||||
|
std::string family; //!< The font family
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// Construct an empty font that does not contain any glyphs.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Font() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the font from a file
|
||||||
|
///
|
||||||
|
/// The supported font formats are: TrueType, Type 1, CFF,
|
||||||
|
/// OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42.
|
||||||
|
/// Note that this function knows nothing about the standard
|
||||||
|
/// fonts installed on the user's system, thus you can't
|
||||||
|
/// load them directly.
|
||||||
|
///
|
||||||
|
/// \warning SFML cannot preload all the font data in this
|
||||||
|
/// function, so the file has to remain accessible until
|
||||||
|
/// the `sf::Font` object opens a new font or is destroyed.
|
||||||
|
///
|
||||||
|
/// \param filename Path of the font file to open
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if opening was unsuccessful
|
||||||
|
///
|
||||||
|
/// \see `openFromFile`, `openFromMemory`, `openFromStream`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit Font(const std::filesystem::path& filename);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the font from a file in memory
|
||||||
|
///
|
||||||
|
/// The supported font formats are: TrueType, Type 1, CFF,
|
||||||
|
/// OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42.
|
||||||
|
///
|
||||||
|
/// \warning SFML cannot preload all the font data in this
|
||||||
|
/// function, so the buffer pointed by `data` has to remain
|
||||||
|
/// valid until the `sf::Font` object opens a new font or
|
||||||
|
/// is destroyed.
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the file data in memory
|
||||||
|
/// \param sizeInBytes Size of the data to load, in bytes
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if loading was unsuccessful
|
||||||
|
///
|
||||||
|
/// \see `openFromFile`, `openFromMemory`, `openFromStream`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Font(const void* data, std::size_t sizeInBytes);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the font from a custom stream
|
||||||
|
///
|
||||||
|
/// The supported font formats are: TrueType, Type 1, CFF,
|
||||||
|
/// OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42.
|
||||||
|
/// Warning: SFML cannot preload all the font data in this
|
||||||
|
/// function, so the contents of `stream` have to remain
|
||||||
|
/// valid as long as the font is used.
|
||||||
|
///
|
||||||
|
/// \warning SFML cannot preload all the font data in this
|
||||||
|
/// function, so the stream has to remain accessible until
|
||||||
|
/// the `sf::Font` object opens a new font or is destroyed.
|
||||||
|
///
|
||||||
|
/// \param stream Source stream to read from
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if loading was unsuccessful
|
||||||
|
///
|
||||||
|
/// \see `openFromFile`, `openFromMemory`, `openFromStream`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit Font(InputStream& stream);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Open the font from a file
|
||||||
|
///
|
||||||
|
/// The supported font formats are: TrueType, Type 1, CFF,
|
||||||
|
/// OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42.
|
||||||
|
/// Note that this function knows nothing about the standard
|
||||||
|
/// fonts installed on the user's system, thus you can't
|
||||||
|
/// load them directly.
|
||||||
|
///
|
||||||
|
/// \warning SFML cannot preload all the font data in this
|
||||||
|
/// function, so the file has to remain accessible until
|
||||||
|
/// the `sf::Font` object opens a new font or is destroyed.
|
||||||
|
///
|
||||||
|
/// \param filename Path of the font file to load
|
||||||
|
///
|
||||||
|
/// \return `true` if opening succeeded, `false` if it failed
|
||||||
|
///
|
||||||
|
/// \see `openFromMemory`, `openFromStream`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool openFromFile(const std::filesystem::path& filename);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Open the font from a file in memory
|
||||||
|
///
|
||||||
|
/// The supported font formats are: TrueType, Type 1, CFF,
|
||||||
|
/// OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42.
|
||||||
|
///
|
||||||
|
/// \warning SFML cannot preload all the font data in this
|
||||||
|
/// function, so the buffer pointed by `data` has to remain
|
||||||
|
/// valid until the `sf::Font` object opens a new font or
|
||||||
|
/// is destroyed.
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the file data in memory
|
||||||
|
/// \param sizeInBytes Size of the data to load, in bytes
|
||||||
|
///
|
||||||
|
/// \return `true` if opening succeeded, `false` if it failed
|
||||||
|
///
|
||||||
|
/// \see `openFromFile`, `openFromStream`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool openFromMemory(const void* data, std::size_t sizeInBytes);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Open the font from a custom stream
|
||||||
|
///
|
||||||
|
/// The supported font formats are: TrueType, Type 1, CFF,
|
||||||
|
/// OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42.
|
||||||
|
///
|
||||||
|
/// \warning SFML cannot preload all the font data in this
|
||||||
|
/// function, so the stream has to remain accessible until
|
||||||
|
/// the `sf::Font` object opens a new font or is destroyed.
|
||||||
|
///
|
||||||
|
/// \param stream Source stream to read from
|
||||||
|
///
|
||||||
|
/// \return `true` if opening succeeded, `false` if it failed
|
||||||
|
///
|
||||||
|
/// \see `openFromFile`, `openFromMemory`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool openFromStream(InputStream& stream);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the font information
|
||||||
|
///
|
||||||
|
/// \return A structure that holds the font information
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const Info& getInfo() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Retrieve a glyph of the font
|
||||||
|
///
|
||||||
|
/// If the font is a bitmap font, not all character sizes
|
||||||
|
/// might be available. If the glyph is not available at the
|
||||||
|
/// requested size, an empty glyph is returned.
|
||||||
|
///
|
||||||
|
/// You may want to use `hasGlyph` to determine if the
|
||||||
|
/// glyph exists before requesting it. If the glyph does not
|
||||||
|
/// exist, a font specific default is returned.
|
||||||
|
///
|
||||||
|
/// Be aware that using a negative value for the outline
|
||||||
|
/// thickness will cause distorted rendering.
|
||||||
|
///
|
||||||
|
/// \param codePoint Unicode code point of the character to get
|
||||||
|
/// \param characterSize Reference character size
|
||||||
|
/// \param bold Retrieve the bold version or the regular one?
|
||||||
|
/// \param outlineThickness Thickness of outline (when != 0 the glyph will not be filled)
|
||||||
|
///
|
||||||
|
/// \return The glyph corresponding to `codePoint` and `characterSize`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const Glyph& getGlyph(char32_t codePoint, unsigned int characterSize, bool bold, float outlineThickness = 0) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Determine if this font has a glyph representing the requested code point
|
||||||
|
///
|
||||||
|
/// Most fonts only include a very limited selection of glyphs from
|
||||||
|
/// specific Unicode subsets, like Latin, Cyrillic, or Asian characters.
|
||||||
|
///
|
||||||
|
/// While code points without representation will return a font specific
|
||||||
|
/// default character, it might be useful to verify whether specific
|
||||||
|
/// code points are included to determine whether a font is suited
|
||||||
|
/// to display text in a specific language.
|
||||||
|
///
|
||||||
|
/// \param codePoint Unicode code point to check
|
||||||
|
///
|
||||||
|
/// \return `true` if the codepoint has a glyph representation, `false` otherwise
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool hasGlyph(char32_t codePoint) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the kerning offset of two glyphs
|
||||||
|
///
|
||||||
|
/// The kerning is an extra offset (negative) to apply between two
|
||||||
|
/// glyphs when rendering them, to make the pair look more "natural".
|
||||||
|
/// For example, the pair "AV" have a special kerning to make them
|
||||||
|
/// closer than other characters. Most of the glyphs pairs have a
|
||||||
|
/// kerning offset of zero, though.
|
||||||
|
///
|
||||||
|
/// \param first Unicode code point of the first character
|
||||||
|
/// \param second Unicode code point of the second character
|
||||||
|
/// \param characterSize Reference character size
|
||||||
|
/// \param bold Retrieve the bold version or the regular one?
|
||||||
|
///
|
||||||
|
/// \return Kerning value for `first` and `second`, in pixels
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] float getKerning(std::uint32_t first, std::uint32_t second, unsigned int characterSize, bool bold = false) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the line spacing
|
||||||
|
///
|
||||||
|
/// Line spacing is the vertical offset to apply between two
|
||||||
|
/// consecutive lines of text.
|
||||||
|
///
|
||||||
|
/// \param characterSize Reference character size
|
||||||
|
///
|
||||||
|
/// \return Line spacing, in pixels
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] float getLineSpacing(unsigned int characterSize) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the position of the underline
|
||||||
|
///
|
||||||
|
/// Underline position is the vertical offset to apply between the
|
||||||
|
/// baseline and the underline.
|
||||||
|
///
|
||||||
|
/// \param characterSize Reference character size
|
||||||
|
///
|
||||||
|
/// \return Underline position, in pixels
|
||||||
|
///
|
||||||
|
/// \see `getUnderlineThickness`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] float getUnderlinePosition(unsigned int characterSize) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the thickness of the underline
|
||||||
|
///
|
||||||
|
/// Underline thickness is the vertical size of the underline.
|
||||||
|
///
|
||||||
|
/// \param characterSize Reference character size
|
||||||
|
///
|
||||||
|
/// \return Underline thickness, in pixels
|
||||||
|
///
|
||||||
|
/// \see `getUnderlinePosition`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] float getUnderlineThickness(unsigned int characterSize) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Retrieve the texture containing the loaded glyphs of a certain size
|
||||||
|
///
|
||||||
|
/// The contents of the returned texture changes as more glyphs
|
||||||
|
/// are requested, thus it is not very relevant. It is mainly
|
||||||
|
/// used internally by `sf::Text`.
|
||||||
|
///
|
||||||
|
/// \param characterSize Reference character size
|
||||||
|
///
|
||||||
|
/// \return Texture containing the glyphs of the requested size
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const Texture& getTexture(unsigned int characterSize) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Enable or disable the smooth filter
|
||||||
|
///
|
||||||
|
/// When the filter is activated, the font appears smoother
|
||||||
|
/// so that pixels are less noticeable. However if you want
|
||||||
|
/// the font to look exactly the same as its source file,
|
||||||
|
/// you should disable it.
|
||||||
|
/// The smooth filter is enabled by default.
|
||||||
|
///
|
||||||
|
/// \param smooth `true` to enable smoothing, `false` to disable it
|
||||||
|
///
|
||||||
|
/// \see `isSmooth`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setSmooth(bool smooth);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Tell whether the smooth filter is enabled or not
|
||||||
|
///
|
||||||
|
/// \return `true` if smoothing is enabled, `false` if it is disabled
|
||||||
|
///
|
||||||
|
/// \see `setSmooth`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool isSmooth() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Structure defining a row of glyphs
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
struct Row
|
||||||
|
{
|
||||||
|
Row(unsigned int rowTop, unsigned int rowHeight) : top(rowTop), height(rowHeight)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int width{}; //!< Current width of the row
|
||||||
|
unsigned int top; //!< Y position of the row into the texture
|
||||||
|
unsigned int height; //!< Height of the row
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Types
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
using GlyphTable = std::unordered_map<std::uint64_t, Glyph>; //!< Table mapping a codepoint to its glyph
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Structure defining a page of glyphs
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
struct Page
|
||||||
|
{
|
||||||
|
explicit Page(bool smooth);
|
||||||
|
|
||||||
|
GlyphTable glyphs; //!< Table mapping code points to their corresponding glyph
|
||||||
|
Texture texture; //!< Texture containing the pixels of the glyphs
|
||||||
|
unsigned int nextRow{3}; //!< Y position of the next new row in the texture
|
||||||
|
std::vector<Row> rows; //!< List containing the position of all the existing rows
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Free all the internal resources
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void cleanup();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Open from stream and print errors with custom message
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool openFromStreamImpl(InputStream& stream, std::string_view type);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Find or create the glyphs page corresponding to the given character size
|
||||||
|
///
|
||||||
|
/// \param characterSize Reference character size
|
||||||
|
///
|
||||||
|
/// \return The glyphs page corresponding to \a characterSize
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Page& loadPage(unsigned int characterSize) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Load a new glyph and store it in the cache
|
||||||
|
///
|
||||||
|
/// \param codePoint Unicode code point of the character to load
|
||||||
|
/// \param characterSize Reference character size
|
||||||
|
/// \param bold Retrieve the bold version or the regular one?
|
||||||
|
/// \param outlineThickness Thickness of outline (when != 0 the glyph will not be filled)
|
||||||
|
///
|
||||||
|
/// \return The glyph corresponding to `codePoint` and `characterSize`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Glyph loadGlyph(char32_t codePoint, unsigned int characterSize, bool bold, float outlineThickness) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Find a suitable rectangle within the texture for a glyph
|
||||||
|
///
|
||||||
|
/// \param page Page of glyphs to search in
|
||||||
|
/// \param size Width and height of the rectangle
|
||||||
|
///
|
||||||
|
/// \return Found rectangle within the texture
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
IntRect findGlyphRect(Page& page, Vector2u size) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Make sure that the given size is the current one
|
||||||
|
///
|
||||||
|
/// \param characterSize Reference character size
|
||||||
|
///
|
||||||
|
/// \return `true` on success, `false` if any error happened
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool setCurrentSize(unsigned int characterSize) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Types
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
struct FontHandles;
|
||||||
|
using PageTable = std::unordered_map<unsigned int, Page>; //!< Table mapping a character size to its page (texture)
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::shared_ptr<FontHandles> m_fontHandles; //!< Shared information about the internal font instance
|
||||||
|
bool m_isSmooth{true}; //!< Status of the smooth filter
|
||||||
|
Info m_info; //!< Information about the font
|
||||||
|
mutable PageTable m_pages; //!< Table containing the glyphs pages by character size
|
||||||
|
mutable std::vector<std::uint8_t> m_pixelBuffer; //!< Pixel buffer holding a glyph's pixels before being written to the texture
|
||||||
|
std::shared_ptr<InputStream> m_stream; //!< Stream for openFromFile and openFromMemory
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::Font
|
||||||
|
/// \ingroup graphics
|
||||||
|
///
|
||||||
|
/// Fonts can be opened from a file, from memory or from a custom
|
||||||
|
/// stream, and supports the most common types of fonts. See
|
||||||
|
/// the openFromFile function for the complete list of supported formats.
|
||||||
|
///
|
||||||
|
/// Once it is opened, a `sf::Font` instance provides three
|
||||||
|
/// types of information about the font:
|
||||||
|
/// \li Global metrics, such as the line spacing
|
||||||
|
/// \li Per-glyph metrics, such as bounding box or kerning
|
||||||
|
/// \li Pixel representation of glyphs
|
||||||
|
///
|
||||||
|
/// Fonts alone are not very useful: they hold the font data
|
||||||
|
/// but cannot make anything useful of it. To do so you need to
|
||||||
|
/// use the `sf::Text` class, which is able to properly output text
|
||||||
|
/// with several options such as character size, style, color,
|
||||||
|
/// position, rotation, etc.
|
||||||
|
/// This separation allows more flexibility and better performances:
|
||||||
|
/// indeed a `sf::Font` is a heavy resource, and any operation on it
|
||||||
|
/// is slow (often too slow for real-time applications). On the other
|
||||||
|
/// side, a `sf::Text` is a lightweight object which can combine the
|
||||||
|
/// glyphs data and metrics of a `sf::Font` to display any text on a
|
||||||
|
/// render target.
|
||||||
|
/// Note that it is also possible to bind several `sf::Text` instances
|
||||||
|
/// to the same `sf::Font`.
|
||||||
|
///
|
||||||
|
/// It is important to note that the `sf::Text` instance doesn't
|
||||||
|
/// copy the font that it uses, it only keeps a reference to it.
|
||||||
|
/// Thus, a `sf::Font` must not be destructed while it is
|
||||||
|
/// used by a `sf::Text` (i.e. never write a function that
|
||||||
|
/// uses a local `sf::Font` instance for creating a text).
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// // Open a new font
|
||||||
|
/// const sf::Font font("arial.ttf");
|
||||||
|
///
|
||||||
|
/// // Create a text which uses our font
|
||||||
|
/// sf::Text text1(font);
|
||||||
|
/// text1.setCharacterSize(30);
|
||||||
|
/// text1.setStyle(sf::Text::Regular);
|
||||||
|
///
|
||||||
|
/// // Create another text using the same font, but with different parameters
|
||||||
|
/// sf::Text text2(font);
|
||||||
|
/// text2.setCharacterSize(50);
|
||||||
|
/// text2.setStyle(sf::Text::Italic);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// Apart from opening font files, and passing them to instances
|
||||||
|
/// of `sf::Text`, you should normally not have to deal directly
|
||||||
|
/// with this class. However, it may be useful to access the
|
||||||
|
/// font metrics or rasterized glyphs for advanced usage.
|
||||||
|
///
|
||||||
|
/// Note that if the font is a bitmap font, it is not scalable,
|
||||||
|
/// thus not all requested sizes will be available to use. This
|
||||||
|
/// needs to be taken into consideration when using `sf::Text`.
|
||||||
|
/// If you need to display text of a certain size, make sure the
|
||||||
|
/// corresponding bitmap font that supports that size is used.
|
||||||
|
///
|
||||||
|
/// \see `sf::Text`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,224 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/System/Vector2.hpp>
|
||||||
|
#include <SFML/System/Vector3.hpp>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
namespace priv
|
||||||
|
{
|
||||||
|
// Forward declarations
|
||||||
|
template <std::size_t Columns, std::size_t Rows>
|
||||||
|
struct Matrix;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct Vector4;
|
||||||
|
|
||||||
|
} // namespace priv
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Namespace with GLSL types
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
namespace Glsl
|
||||||
|
{
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief 2D float vector (\p vec2 in GLSL)
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
using Vec2 = Vector2<float>;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief 2D int vector (\p ivec2 in GLSL)
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
using Ivec2 = Vector2<int>;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief 2D bool vector (\p bvec2 in GLSL)
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
using Bvec2 = Vector2<bool>;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief 3D float vector (\p vec3 in GLSL)
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
using Vec3 = Vector3<float>;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief 3D int vector (\p ivec3 in GLSL)
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
using Ivec3 = Vector3<int>;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief 3D bool vector (\p bvec3 in GLSL)
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
using Bvec3 = Vector3<bool>;
|
||||||
|
|
||||||
|
#ifdef SFML_DOXYGEN
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief 4D float vector (\p vec4 in GLSL)
|
||||||
|
///
|
||||||
|
/// 4D float vectors can be implicitly converted from `sf::Color`
|
||||||
|
/// instances. Each color channel is normalized from integers
|
||||||
|
/// in [0, 255] to floating point values in [0, 1].
|
||||||
|
/// \code
|
||||||
|
/// sf::Glsl::Vec4 zeroVector;
|
||||||
|
/// sf::Glsl::Vec4 vector(1.f, 2.f, 3.f, 4.f);
|
||||||
|
/// sf::Glsl::Vec4 color = sf::Color::Cyan;
|
||||||
|
/// \endcode
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
using Vec4 = ImplementationDefined;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief 4D int vector (\p ivec4 in GLSL)
|
||||||
|
///
|
||||||
|
/// 4D int vectors can be implicitly converted from `sf::Color`
|
||||||
|
/// instances. Each color channel remains unchanged inside
|
||||||
|
/// the integer interval [0, 255].
|
||||||
|
/// \code
|
||||||
|
/// sf::Glsl::Ivec4 zeroVector;
|
||||||
|
/// sf::Glsl::Ivec4 vector(1, 2, 3, 4);
|
||||||
|
/// sf::Glsl::Ivec4 color = sf::Color::Cyan;
|
||||||
|
/// \endcode
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
using Ivec4 = ImplementationDefined;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief 4D bool vector (\p bvec4 in GLSL)
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
using Bvec4 = ImplementationDefined;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief 3x3 float matrix (\p mat3 in GLSL)
|
||||||
|
///
|
||||||
|
/// The matrix can be constructed from an array with 3x3
|
||||||
|
/// elements, aligned in column-major order. For example,
|
||||||
|
/// a translation by (x, y) looks as follows:
|
||||||
|
/// \code
|
||||||
|
/// float array[9] =
|
||||||
|
/// {
|
||||||
|
/// 1, 0, 0,
|
||||||
|
/// 0, 1, 0,
|
||||||
|
/// x, y, 1
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// sf::Glsl::Mat3 matrix(array);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// Mat3 can also be implicitly converted from `sf::Transform`:
|
||||||
|
/// \code
|
||||||
|
/// sf::Transform transform;
|
||||||
|
/// sf::Glsl::Mat3 matrix = transform;
|
||||||
|
/// \endcode
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
using Mat3 = ImplementationDefined;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief 4x4 float matrix (\p mat4 in GLSL)
|
||||||
|
///
|
||||||
|
/// The matrix can be constructed from an array with 4x4
|
||||||
|
/// elements, aligned in column-major order. For example,
|
||||||
|
/// a translation by (x, y, z) looks as follows:
|
||||||
|
/// \code
|
||||||
|
/// float array[16] =
|
||||||
|
/// {
|
||||||
|
/// 1, 0, 0, 0,
|
||||||
|
/// 0, 1, 0, 0,
|
||||||
|
/// 0, 0, 1, 0,
|
||||||
|
/// x, y, z, 1
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// sf::Glsl::Mat4 matrix(array);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// Mat4 can also be implicitly converted from `sf::Transform`:
|
||||||
|
/// \code
|
||||||
|
/// sf::Transform transform;
|
||||||
|
/// sf::Glsl::Mat4 matrix = transform;
|
||||||
|
/// \endcode
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
using Mat4 = ImplementationDefined;
|
||||||
|
|
||||||
|
#else // SFML_DOXYGEN
|
||||||
|
|
||||||
|
using Vec4 = priv::Vector4<float>;
|
||||||
|
using Ivec4 = priv::Vector4<int>;
|
||||||
|
using Bvec4 = priv::Vector4<bool>;
|
||||||
|
using Mat3 = priv::Matrix<3, 3>;
|
||||||
|
using Mat4 = priv::Matrix<4, 4>;
|
||||||
|
|
||||||
|
#endif // SFML_DOXYGEN
|
||||||
|
|
||||||
|
} // namespace Glsl
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
#include <SFML/Graphics/Glsl.inl>
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \namespace sf::Glsl
|
||||||
|
/// \ingroup graphics
|
||||||
|
///
|
||||||
|
/// \details The `sf::Glsl` namespace contains types that match
|
||||||
|
/// their equivalents in GLSL, the OpenGL shading language.
|
||||||
|
/// These types are exclusively used by the `sf::Shader` class.
|
||||||
|
///
|
||||||
|
/// Types that already exist in SFML, such as `sf::Vector2<T>`
|
||||||
|
/// and `sf::Vector3<T>`, are reused as type aliases, so you
|
||||||
|
/// can use the types in this namespace as well as the original ones.
|
||||||
|
/// Others are newly defined, such as `Glsl::Vec4` or `Glsl::Mat3`.
|
||||||
|
/// Their actual type is an implementation detail and should not be used.
|
||||||
|
///
|
||||||
|
/// All vector types support a default constructor that
|
||||||
|
/// initializes every component to zero, in addition to a
|
||||||
|
/// constructor with one parameter for each component.
|
||||||
|
/// The components are stored in member variables called
|
||||||
|
/// x, y, z, and w.
|
||||||
|
///
|
||||||
|
/// All matrix types support a constructor with a `float*`
|
||||||
|
/// parameter that points to a float array of the appropriate
|
||||||
|
/// size (that is, 9 in a 3x3 matrix, 16 in a 4x4 matrix).
|
||||||
|
/// Furthermore, they can be converted from `sf::Transform`
|
||||||
|
/// objects.
|
||||||
|
///
|
||||||
|
/// \see `sf::Shader`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,177 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Graphics/Color.hpp>
|
||||||
|
#include <SFML/Graphics/Glsl.hpp> // NOLINT(misc-header-include-cycle)
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class Transform;
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
namespace sf::priv
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Helper functions to copy `sf::Transform` to `sf::Glsl::Mat3/4`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void SFML_GRAPHICS_API copyMatrix(const Transform& source, Matrix<3, 3>& dest);
|
||||||
|
void SFML_GRAPHICS_API copyMatrix(const Transform& source, Matrix<4, 4>& dest);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Copy array-based matrix with given number of elements
|
||||||
|
///
|
||||||
|
/// Indirection to `std::copy()` to avoid inclusion of
|
||||||
|
/// <algorithm> and MSVC's annoying 4996 warning in header
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void SFML_GRAPHICS_API copyMatrix(const float* source, std::size_t elements, float* dest);
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Matrix type, used to set uniforms in GLSL
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <std::size_t Columns, std::size_t Rows>
|
||||||
|
struct Matrix
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct from raw data
|
||||||
|
///
|
||||||
|
/// \param pointer Points to the beginning of an array that
|
||||||
|
/// has the size of the matrix. The elements
|
||||||
|
/// are copied to the instance.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit Matrix(const float* pointer)
|
||||||
|
{
|
||||||
|
copyMatrix(pointer, Columns * Rows, array.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct implicitly from SFML transform
|
||||||
|
///
|
||||||
|
/// This constructor is only supported for 3x3 and 4x4
|
||||||
|
/// matrices.
|
||||||
|
///
|
||||||
|
/// \param transform Object containing a transform.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Matrix(const Transform& transform)
|
||||||
|
{
|
||||||
|
copyMatrix(transform, *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<float, Columns * Rows> array{}; //!< Array holding matrix data
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief 4D vector type, used to set uniforms in GLSL
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
struct Vector4
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor, creates a zero vector
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Vector4() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct from 4 vector components
|
||||||
|
///
|
||||||
|
/// \param x Component of the 4D vector
|
||||||
|
/// \param y Component of the 4D vector
|
||||||
|
/// \param z Component of the 4D vector
|
||||||
|
/// \param w Component of the 4D vector
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wshadow"
|
||||||
|
#endif
|
||||||
|
constexpr Vector4(T x, T y, T z, T w) : x(x), y(y), z(z), w(w)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Converts the vector to another type of vector
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename U>
|
||||||
|
constexpr explicit operator Vector4<U>() const
|
||||||
|
{
|
||||||
|
return Vector4<U>(static_cast<U>(x), static_cast<U>(y), static_cast<U>(z), static_cast<U>(w));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct vector implicitly from color
|
||||||
|
///
|
||||||
|
/// Vector is normalized to [0, 1] for floats, and left as-is
|
||||||
|
/// for ints. Not defined for other template arguments.
|
||||||
|
///
|
||||||
|
/// \param color Color instance
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Vector4(Color color);
|
||||||
|
|
||||||
|
T x{}; //!< 1st component (X) of the 4D vector
|
||||||
|
T y{}; //!< 2nd component (Y) of the 4D vector
|
||||||
|
T z{}; //!< 3rd component (Z) of the 4D vector
|
||||||
|
T w{}; //!< 4th component (W) of the 4D vector
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <>
|
||||||
|
constexpr Vector4<float>::Vector4(Color color) :
|
||||||
|
x(color.r / 255.f),
|
||||||
|
y(color.g / 255.f),
|
||||||
|
z(color.b / 255.f),
|
||||||
|
w(color.a / 255.f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <>
|
||||||
|
constexpr Vector4<int>::Vector4(Color color) : x(color.r), y(color.g), z(color.b), w(color.a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sf::priv
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Graphics/Rect.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Structure describing a glyph
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
struct SFML_GRAPHICS_API Glyph
|
||||||
|
{
|
||||||
|
float advance{}; //!< Offset to move horizontally to the next character
|
||||||
|
int lsbDelta{}; //!< Left offset after forced autohint. Internally used by getKerning()
|
||||||
|
int rsbDelta{}; //!< Right offset after forced autohint. Internally used by getKerning()
|
||||||
|
FloatRect bounds; //!< Bounding rectangle of the glyph, in coordinates relative to the baseline
|
||||||
|
IntRect textureRect; //!< Texture coordinates of the glyph inside the font's texture
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \struct sf::Glyph
|
||||||
|
/// \ingroup graphics
|
||||||
|
///
|
||||||
|
/// A glyph is the visual representation of a character.
|
||||||
|
///
|
||||||
|
/// The `sf::Glyph` structure provides the information needed
|
||||||
|
/// to handle the glyph:
|
||||||
|
/// \li its coordinates in the font's texture
|
||||||
|
/// \li its bounding rectangle
|
||||||
|
/// \li the offset to apply to get the starting position of the next glyph
|
||||||
|
///
|
||||||
|
/// \see `sf::Font`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,417 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Graphics/Color.hpp>
|
||||||
|
#include <SFML/Graphics/Rect.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/Vector2.hpp>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <optional>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class InputStream;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Class for loading, manipulating and saving images
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_GRAPHICS_API Image
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// Constructs an image with width 0 and height 0.
|
||||||
|
///
|
||||||
|
/// \see `resize`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Image() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the image and fill it with a unique color
|
||||||
|
///
|
||||||
|
/// \param size Width and height of the image
|
||||||
|
/// \param color Fill color
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit Image(Vector2u size, Color color = Color::Black);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the image from an array of pixels
|
||||||
|
///
|
||||||
|
/// The pixel array is assumed to contain 32-bits RGBA pixels,
|
||||||
|
/// and have the given `size`. If not, this is an undefined behavior.
|
||||||
|
/// If `pixels` is `nullptr`, an empty image is created.
|
||||||
|
///
|
||||||
|
/// \param size Width and height of the image
|
||||||
|
/// \param pixels Array of pixels to copy to the image
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Image(Vector2u size, const std::uint8_t* pixels);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the image from a file on disk
|
||||||
|
///
|
||||||
|
/// The supported image formats are bmp, png, tga, jpg, gif,
|
||||||
|
/// psd, hdr, pic and pnm. Some format options are not supported,
|
||||||
|
/// like jpeg with arithmetic coding or ASCII pnm.
|
||||||
|
///
|
||||||
|
/// \param filename Path of the image file to load
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if loading was unsuccessful
|
||||||
|
///
|
||||||
|
/// \see `loadFromFile`, `loadFromMemory`, `loadFromStream`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit Image(const std::filesystem::path& filename);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the image from a file in memory
|
||||||
|
///
|
||||||
|
/// The supported image formats are bmp, png, tga, jpg, gif,
|
||||||
|
/// psd, hdr, pic and pnm. Some format options are not supported,
|
||||||
|
/// like jpeg with arithmetic coding or ASCII pnm.
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the file data in memory
|
||||||
|
/// \param size Size of the data to load, in bytes
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if loading was unsuccessful
|
||||||
|
///
|
||||||
|
/// \see `loadFromFile`, `loadFromMemory`, `loadFromStream`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Image(const void* data, std::size_t size);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the image from a custom stream
|
||||||
|
///
|
||||||
|
/// The supported image formats are bmp, png, tga, jpg, gif,
|
||||||
|
/// psd, hdr, pic and pnm. Some format options are not supported,
|
||||||
|
/// like jpeg with arithmetic coding or ASCII pnm.
|
||||||
|
///
|
||||||
|
/// \param stream Source stream to read from
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if loading was unsuccessful
|
||||||
|
///
|
||||||
|
/// \see `loadFromFile`, `loadFromMemory`, `loadFromStream`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit Image(InputStream& stream);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Resize the image and fill it with a unique color
|
||||||
|
///
|
||||||
|
/// \param size Width and height of the image
|
||||||
|
/// \param color Fill color
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void resize(Vector2u size, Color color = Color::Black);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Resize the image from an array of pixels
|
||||||
|
///
|
||||||
|
/// The pixel array is assumed to contain 32-bits RGBA pixels,
|
||||||
|
/// and have the given `size`. If not, this is an undefined behavior.
|
||||||
|
/// If `pixels` is `nullptr`, an empty image is created.
|
||||||
|
///
|
||||||
|
/// \param size Width and height of the image
|
||||||
|
/// \param pixels Array of pixels to copy to the image
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void resize(Vector2u size, const std::uint8_t* pixels);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Load the image from a file on disk
|
||||||
|
///
|
||||||
|
/// The supported image formats are bmp, png, tga, jpg, gif,
|
||||||
|
/// psd, hdr, pic and pnm. Some format options are not supported,
|
||||||
|
/// like jpeg with arithmetic coding or ASCII pnm.
|
||||||
|
/// If this function fails, the image is left unchanged.
|
||||||
|
///
|
||||||
|
/// \param filename Path of the image file to load
|
||||||
|
///
|
||||||
|
/// \return `true` if loading was successful
|
||||||
|
///
|
||||||
|
/// \see `loadFromMemory`, `loadFromStream`, `saveToFile`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool loadFromFile(const std::filesystem::path& filename);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Load the image from a file in memory
|
||||||
|
///
|
||||||
|
/// The supported image formats are bmp, png, tga, jpg, gif,
|
||||||
|
/// psd, hdr, pic and pnm. Some format options are not supported,
|
||||||
|
/// like jpeg with arithmetic coding or ASCII pnm.
|
||||||
|
/// If this function fails, the image is left unchanged.
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the file data in memory
|
||||||
|
/// \param size Size of the data to load, in bytes
|
||||||
|
///
|
||||||
|
/// \return `true` if loading was successful
|
||||||
|
///
|
||||||
|
/// \see `loadFromFile`, `loadFromStream`, `saveToMemory`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool loadFromMemory(const void* data, std::size_t size);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Load the image from a custom stream
|
||||||
|
///
|
||||||
|
/// The supported image formats are bmp, png, tga, jpg, gif,
|
||||||
|
/// psd, hdr, pic and pnm. Some format options are not supported,
|
||||||
|
/// like jpeg with arithmetic coding or ASCII pnm.
|
||||||
|
/// If this function fails, the image is left unchanged.
|
||||||
|
///
|
||||||
|
/// \param stream Source stream to read from
|
||||||
|
///
|
||||||
|
/// \return `true` if loading was successful
|
||||||
|
///
|
||||||
|
/// \see `loadFromFile`, `loadFromMemory`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool loadFromStream(InputStream& stream);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Save the image to a file on disk
|
||||||
|
///
|
||||||
|
/// The format of the image is automatically deduced from
|
||||||
|
/// the extension. The supported image formats are bmp, png,
|
||||||
|
/// tga and jpg. The destination file is overwritten
|
||||||
|
/// if it already exists. This function fails if the image is empty.
|
||||||
|
///
|
||||||
|
/// \param filename Path of the file to save
|
||||||
|
///
|
||||||
|
/// \return `true` if saving was successful
|
||||||
|
///
|
||||||
|
/// \see `saveToMemory`, `loadFromFile`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool saveToFile(const std::filesystem::path& filename) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Save the image to a buffer in memory
|
||||||
|
///
|
||||||
|
/// The format of the image must be specified.
|
||||||
|
/// The supported image formats are bmp, png, tga and jpg.
|
||||||
|
/// This function fails if the image is empty, or if
|
||||||
|
/// the format was invalid.
|
||||||
|
///
|
||||||
|
/// \param format Encoding format to use
|
||||||
|
///
|
||||||
|
/// \return Buffer with encoded data if saving was successful,
|
||||||
|
/// otherwise `std::nullopt`
|
||||||
|
///
|
||||||
|
/// \see `saveToFile`, `loadFromMemory`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] std::optional<std::vector<std::uint8_t>> saveToMemory(std::string_view format) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Return the size (width and height) of the image
|
||||||
|
///
|
||||||
|
/// \return Size of the image, in pixels
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Vector2u getSize() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Create a transparency mask from a specified color-key
|
||||||
|
///
|
||||||
|
/// This function sets the alpha value of every pixel matching
|
||||||
|
/// the given color to `alpha` (0 by default), so that they
|
||||||
|
/// become transparent.
|
||||||
|
///
|
||||||
|
/// \param color Color to make transparent
|
||||||
|
/// \param alpha Alpha value to assign to transparent pixels
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void createMaskFromColor(Color color, std::uint8_t alpha = 0);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Copy pixels from another image onto this one
|
||||||
|
///
|
||||||
|
/// This function does a slow pixel copy and should not be
|
||||||
|
/// used intensively. It can be used to prepare a complex
|
||||||
|
/// static image from several others, but if you need this
|
||||||
|
/// kind of feature in real-time you'd better use `sf::RenderTexture`.
|
||||||
|
///
|
||||||
|
/// If `sourceRect` is empty, the whole image is copied.
|
||||||
|
/// If `applyAlpha` is set to `true`, alpha blending is
|
||||||
|
/// applied from the source pixels to the destination pixels
|
||||||
|
/// using the \b over operator. If it is `false`, the source
|
||||||
|
/// pixels are copied unchanged with their alpha value.
|
||||||
|
///
|
||||||
|
/// See https://en.wikipedia.org/wiki/Alpha_compositing for
|
||||||
|
/// details on the \b over operator.
|
||||||
|
///
|
||||||
|
/// Note that this function can fail if either image is invalid
|
||||||
|
/// (i.e. zero-sized width or height), or if `sourceRect` is
|
||||||
|
/// not within the boundaries of the `source` parameter, or
|
||||||
|
/// if the destination area is out of the boundaries of this image.
|
||||||
|
///
|
||||||
|
/// On failure, the destination image is left unchanged.
|
||||||
|
///
|
||||||
|
/// \param source Source image to copy
|
||||||
|
/// \param dest Coordinates of the destination position
|
||||||
|
/// \param sourceRect Sub-rectangle of the source image to copy
|
||||||
|
/// \param applyAlpha Should the copy take into account the source transparency?
|
||||||
|
///
|
||||||
|
/// \return `true` if the operation was successful, `false` otherwise
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool copy(const Image& source, Vector2u dest, const IntRect& sourceRect = {}, bool applyAlpha = false);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Change the color of a pixel
|
||||||
|
///
|
||||||
|
/// This function doesn't check the validity of the pixel
|
||||||
|
/// coordinates, using out-of-range values will result in
|
||||||
|
/// an undefined behavior.
|
||||||
|
///
|
||||||
|
/// \param coords Coordinates of pixel to change
|
||||||
|
/// \param color New color of the pixel
|
||||||
|
///
|
||||||
|
/// \see `getPixel`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setPixel(Vector2u coords, Color color);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the color of a pixel
|
||||||
|
///
|
||||||
|
/// This function doesn't check the validity of the pixel
|
||||||
|
/// coordinates, using out-of-range values will result in
|
||||||
|
/// an undefined behavior.
|
||||||
|
///
|
||||||
|
/// \param coords Coordinates of pixel to change
|
||||||
|
///
|
||||||
|
/// \return Color of the pixel at given coordinates
|
||||||
|
///
|
||||||
|
/// \see `setPixel`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Color getPixel(Vector2u coords) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get a read-only pointer to the array of pixels
|
||||||
|
///
|
||||||
|
/// The returned value points to an array of RGBA pixels made of
|
||||||
|
/// 8 bit integer components. The size of the array is
|
||||||
|
/// `width * height * 4 (getSize().x * getSize().y * 4)`.
|
||||||
|
/// Warning: the returned pointer may become invalid if you
|
||||||
|
/// modify the image, so you should never store it for too long.
|
||||||
|
/// If the image is empty, a null pointer is returned.
|
||||||
|
///
|
||||||
|
/// \return Read-only pointer to the array of pixels
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const std::uint8_t* getPixelsPtr() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Flip the image horizontally (left <-> right)
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void flipHorizontally();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Flip the image vertically (top <-> bottom)
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void flipVertically();
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Vector2u m_size; //!< Image size
|
||||||
|
std::vector<std::uint8_t> m_pixels; //!< Pixels of the image
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::Image
|
||||||
|
/// \ingroup graphics
|
||||||
|
///
|
||||||
|
/// `sf::Image` is an abstraction to manipulate images
|
||||||
|
/// as bi-dimensional arrays of pixels. The class provides
|
||||||
|
/// functions to load, read, write and save pixels, as well
|
||||||
|
/// as many other useful functions.
|
||||||
|
///
|
||||||
|
/// `sf::Image` can handle a unique internal representation of
|
||||||
|
/// pixels, which is RGBA 32 bits. This means that a pixel
|
||||||
|
/// must be composed of 8 bit red, green, blue and alpha
|
||||||
|
/// channels -- just like a `sf::Color`.
|
||||||
|
/// All the functions that return an array of pixels follow
|
||||||
|
/// this rule, and all parameters that you pass to `sf::Image`
|
||||||
|
/// functions (such as `loadFromMemory`) must use this
|
||||||
|
/// representation as well.
|
||||||
|
///
|
||||||
|
/// A `sf::Image` can be copied, but it is a heavy resource and
|
||||||
|
/// if possible you should always use [const] references to
|
||||||
|
/// pass or return them to avoid useless copies.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// // Load an image file from a file
|
||||||
|
/// const sf::Image background("background.jpg");
|
||||||
|
///
|
||||||
|
/// // Create a 20x20 image filled with black color
|
||||||
|
/// sf::Image image({20, 20}, sf::Color::Black);
|
||||||
|
///
|
||||||
|
/// // Copy background on image at position (10, 10)
|
||||||
|
/// if (!image.copy(background, {10, 10}))
|
||||||
|
/// return -1;
|
||||||
|
///
|
||||||
|
/// // Make the top-left pixel transparent
|
||||||
|
/// sf::Color color = image.getPixel({0, 0});
|
||||||
|
/// color.a = 0;
|
||||||
|
/// image.setPixel({0, 0}, color);
|
||||||
|
///
|
||||||
|
/// // Save the image to a file
|
||||||
|
/// if (!image.saveToFile("result.png"))
|
||||||
|
/// return -1;
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::Texture`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \ingroup graphics
|
||||||
|
/// \brief Types of primitives that a `sf::VertexArray` can render
|
||||||
|
///
|
||||||
|
/// Points and lines have no area, therefore their thickness
|
||||||
|
/// will always be 1 pixel, regardless the current transform
|
||||||
|
/// and view.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
enum class PrimitiveType
|
||||||
|
{
|
||||||
|
Points, //!< List of individual points
|
||||||
|
Lines, //!< List of individual lines
|
||||||
|
LineStrip, //!< List of connected lines, a point uses the previous point to form a line
|
||||||
|
Triangles, //!< List of individual triangles
|
||||||
|
TriangleStrip, //!< List of connected triangles, a point uses the two previous points to form a triangle
|
||||||
|
TriangleFan //!< List of connected triangles, a point uses the common center and the previous point to form a triangle
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
@ -0,0 +1,203 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/System/Vector2.hpp>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Utility class for manipulating 2D axis aligned rectangles
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
class Rect
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// Creates an empty rectangle (it is equivalent to calling
|
||||||
|
/// `Rect({0, 0}, {0, 0})`).
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Rect() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the rectangle from position and size
|
||||||
|
///
|
||||||
|
/// Be careful, the last parameter is the size,
|
||||||
|
/// not the bottom-right corner!
|
||||||
|
///
|
||||||
|
/// \param position Position of the top-left corner of the rectangle
|
||||||
|
/// \param size Size of the rectangle
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Rect(Vector2<T> position, Vector2<T> size);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Converts the rectangle to another type of rectangle
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename U>
|
||||||
|
constexpr explicit operator Rect<U>() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Check if a point is inside the rectangle's area
|
||||||
|
///
|
||||||
|
/// This check is non-inclusive. If the point lies on the
|
||||||
|
/// edge of the rectangle, this function will return `false`.
|
||||||
|
///
|
||||||
|
/// \param point Point to test
|
||||||
|
///
|
||||||
|
/// \return `true` if the point is inside, `false` otherwise
|
||||||
|
///
|
||||||
|
/// \see `findIntersection`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr bool contains(Vector2<T> point) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Check the intersection between two rectangles
|
||||||
|
///
|
||||||
|
/// \param rectangle Rectangle to test
|
||||||
|
///
|
||||||
|
/// \return Intersection rectangle if intersecting, `std::nullopt` otherwise
|
||||||
|
///
|
||||||
|
/// \see `contains`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr std::optional<Rect<T>> findIntersection(const Rect<T>& rectangle) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the position of the center of the rectangle
|
||||||
|
///
|
||||||
|
/// \return Center of rectangle
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr Vector2<T> getCenter() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Vector2<T> position{}; //!< Position of the top-left corner of the rectangle
|
||||||
|
Vector2<T> size{}; //!< Size of the rectangle
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Rect
|
||||||
|
/// \brief Overload of binary `operator==`
|
||||||
|
///
|
||||||
|
/// This operator compares strict equality between two rectangles.
|
||||||
|
///
|
||||||
|
/// \param lhs Left operand (a rectangle)
|
||||||
|
/// \param rhs Right operand (a rectangle)
|
||||||
|
///
|
||||||
|
/// \return `true` if \a lhs is equal to \a rhs
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
[[nodiscard]] constexpr bool operator==(const Rect<T>& lhs, const Rect<T>& rhs);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Rect
|
||||||
|
/// \brief Overload of binary `operator!=`
|
||||||
|
///
|
||||||
|
/// This operator compares strict difference between two rectangles.
|
||||||
|
///
|
||||||
|
/// \param lhs Left operand (a rectangle)
|
||||||
|
/// \param rhs Right operand (a rectangle)
|
||||||
|
///
|
||||||
|
/// \return `true` if \a lhs is not equal to \a rhs
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
[[nodiscard]] constexpr bool operator!=(const Rect<T>& lhs, const Rect<T>& rhs);
|
||||||
|
|
||||||
|
// Create type aliases for the most common types
|
||||||
|
using IntRect = Rect<int>;
|
||||||
|
using FloatRect = Rect<float>;
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
#include <SFML/Graphics/Rect.inl>
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::Rect
|
||||||
|
/// \ingroup graphics
|
||||||
|
///
|
||||||
|
/// A rectangle is defined by its top-left corner and its size.
|
||||||
|
/// It is a very simple class defined for convenience, so
|
||||||
|
/// its member variables (position and size) are public
|
||||||
|
/// and can be accessed directly, just like the vector classes
|
||||||
|
/// (`Vector2` and `Vector3`).
|
||||||
|
///
|
||||||
|
/// To keep things simple, `sf::Rect` doesn't define
|
||||||
|
/// functions to emulate the properties that are not directly
|
||||||
|
/// members (such as right, bottom, etc.), it rather
|
||||||
|
/// only provides intersection functions.
|
||||||
|
///
|
||||||
|
/// `sf::Rect` uses the usual rules for its boundaries:
|
||||||
|
/// \li The left and top edges are included in the rectangle's area
|
||||||
|
/// \li The right and bottom edges are excluded from the rectangle's area
|
||||||
|
///
|
||||||
|
/// This means that `sf::IntRect({0, 0}, {1, 1})` and `sf::IntRect({1, 1}, {1, 1})`
|
||||||
|
/// don't intersect.
|
||||||
|
///
|
||||||
|
/// `sf::Rect` is a template and may be used with any numeric type, but
|
||||||
|
/// for simplicity type aliases for the instantiations used by SFML are given:
|
||||||
|
/// \li `sf::Rect<int>` is `sf::IntRect`
|
||||||
|
/// \li `sf::Rect<float>` is `sf::FloatRect`
|
||||||
|
///
|
||||||
|
/// So that you don't have to care about the template syntax.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// // Define a rectangle, located at (0, 0) with a size of 20x5
|
||||||
|
/// sf::IntRect r1({0, 0}, {20, 5});
|
||||||
|
///
|
||||||
|
/// // Define another rectangle, located at (4, 2) with a size of 18x10
|
||||||
|
/// sf::Vector2i position(4, 2);
|
||||||
|
/// sf::Vector2i size(18, 10);
|
||||||
|
/// sf::IntRect r2(position, size);
|
||||||
|
///
|
||||||
|
/// // Test intersections with the point (3, 1)
|
||||||
|
/// bool b1 = r1.contains({3, 1}); // true
|
||||||
|
/// bool b2 = r2.contains({3, 1}); // false
|
||||||
|
///
|
||||||
|
/// // Test the intersection between r1 and r2
|
||||||
|
/// std::optional<sf::IntRect> result = r1.findIntersection(r2);
|
||||||
|
/// // result.has_value() == true
|
||||||
|
/// // result.value() == sf::IntRect({4, 2}, {16, 3})
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,130 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Rect.hpp> // NOLINT(misc-header-include-cycle)
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
constexpr Rect<T>::Rect(Vector2<T> thePosition, Vector2<T> theSize) : position(thePosition), size(theSize)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
template <typename U>
|
||||||
|
constexpr Rect<T>::operator Rect<U>() const
|
||||||
|
{
|
||||||
|
return Rect<U>(Vector2<U>(position), Vector2<U>(size));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
constexpr bool Rect<T>::contains(Vector2<T> point) const
|
||||||
|
{
|
||||||
|
// Not using 'std::min' and 'std::max' to avoid depending on '<algorithm>'
|
||||||
|
const auto min = [](T a, T b) { return (a < b) ? a : b; };
|
||||||
|
const auto max = [](T a, T b) { return (a < b) ? b : a; };
|
||||||
|
|
||||||
|
// Rectangles with negative dimensions are allowed, so we must handle them correctly
|
||||||
|
|
||||||
|
// Compute the real min and max of the rectangle on both axes
|
||||||
|
const T minX = min(position.x, static_cast<T>(position.x + size.x));
|
||||||
|
const T maxX = max(position.x, static_cast<T>(position.x + size.x));
|
||||||
|
const T minY = min(position.y, static_cast<T>(position.y + size.y));
|
||||||
|
const T maxY = max(position.y, static_cast<T>(position.y + size.y));
|
||||||
|
|
||||||
|
return (point.x >= minX) && (point.x < maxX) && (point.y >= minY) && (point.y < maxY);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
constexpr std::optional<Rect<T>> Rect<T>::findIntersection(const Rect<T>& rectangle) const
|
||||||
|
{
|
||||||
|
// Not using 'std::min' and 'std::max' to avoid depending on '<algorithm>'
|
||||||
|
const auto min = [](T a, T b) { return (a < b) ? a : b; };
|
||||||
|
const auto max = [](T a, T b) { return (a < b) ? b : a; };
|
||||||
|
|
||||||
|
// Rectangles with negative dimensions are allowed, so we must handle them correctly
|
||||||
|
|
||||||
|
// Compute the min and max of the first rectangle on both axes
|
||||||
|
const T r1MinX = min(position.x, static_cast<T>(position.x + size.x));
|
||||||
|
const T r1MaxX = max(position.x, static_cast<T>(position.x + size.x));
|
||||||
|
const T r1MinY = min(position.y, static_cast<T>(position.y + size.y));
|
||||||
|
const T r1MaxY = max(position.y, static_cast<T>(position.y + size.y));
|
||||||
|
|
||||||
|
// Compute the min and max of the second rectangle on both axes
|
||||||
|
const T r2MinX = min(rectangle.position.x, static_cast<T>(rectangle.position.x + rectangle.size.x));
|
||||||
|
const T r2MaxX = max(rectangle.position.x, static_cast<T>(rectangle.position.x + rectangle.size.x));
|
||||||
|
const T r2MinY = min(rectangle.position.y, static_cast<T>(rectangle.position.y + rectangle.size.y));
|
||||||
|
const T r2MaxY = max(rectangle.position.y, static_cast<T>(rectangle.position.y + rectangle.size.y));
|
||||||
|
|
||||||
|
// Compute the intersection boundaries
|
||||||
|
const T interLeft = max(r1MinX, r2MinX);
|
||||||
|
const T interTop = max(r1MinY, r2MinY);
|
||||||
|
const T interRight = min(r1MaxX, r2MaxX);
|
||||||
|
const T interBottom = min(r1MaxY, r2MaxY);
|
||||||
|
|
||||||
|
// If the intersection is valid (positive non zero area), then there is an intersection
|
||||||
|
if ((interLeft < interRight) && (interTop < interBottom))
|
||||||
|
{
|
||||||
|
return Rect<T>({interLeft, interTop}, {interRight - interLeft, interBottom - interTop});
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
constexpr Vector2<T> Rect<T>::getCenter() const
|
||||||
|
{
|
||||||
|
return position + size / T{2};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
constexpr bool operator==(const Rect<T>& lhs, const Rect<T>& rhs)
|
||||||
|
{
|
||||||
|
return (lhs.position == rhs.position) && (lhs.size == rhs.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
constexpr bool operator!=(const Rect<T>& lhs, const Rect<T>& rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
@ -0,0 +1,143 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Graphics/Shape.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/Vector2.hpp>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Specialized shape representing a rectangle
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_GRAPHICS_API RectangleShape : public Shape
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// \param size Size of the rectangle
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit RectangleShape(Vector2f size = {});
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the size of the rectangle
|
||||||
|
///
|
||||||
|
/// \param size New size of the rectangle
|
||||||
|
///
|
||||||
|
/// \see `getSize`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setSize(Vector2f size);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the size of the rectangle
|
||||||
|
///
|
||||||
|
/// \return Size of the rectangle
|
||||||
|
///
|
||||||
|
/// \see `setSize`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Vector2f getSize() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the number of points defining the shape
|
||||||
|
///
|
||||||
|
/// \return Number of points of the shape. For rectangle
|
||||||
|
/// shapes, this number is always 4.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] std::size_t getPointCount() const override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get a point of the rectangle
|
||||||
|
///
|
||||||
|
/// The returned point is in local coordinates, that is,
|
||||||
|
/// the shape's transforms (position, rotation, scale) are
|
||||||
|
/// not taken into account.
|
||||||
|
/// The result is undefined if `index` is out of the valid range.
|
||||||
|
///
|
||||||
|
/// \param index Index of the point to get, in range [0 .. 3]
|
||||||
|
///
|
||||||
|
/// \return `index`-th point of the shape
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Vector2f getPoint(std::size_t index) const override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the geometric center of the rectangle
|
||||||
|
///
|
||||||
|
/// The returned point is in local coordinates, that is,
|
||||||
|
/// the shape's transforms (position, rotation, scale) are
|
||||||
|
/// not taken into account.
|
||||||
|
///
|
||||||
|
/// \return The geometric center of the shape
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Vector2f getGeometricCenter() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Vector2f m_size; //!< Size of the rectangle
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::RectangleShape
|
||||||
|
/// \ingroup graphics
|
||||||
|
///
|
||||||
|
/// This class inherits all the functions of `sf::Transformable`
|
||||||
|
/// (position, rotation, scale, bounds, ...) as well as the
|
||||||
|
/// functions of `sf::Shape` (outline, color, texture, ...).
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// sf::RectangleShape rectangle;
|
||||||
|
/// rectangle.setSize(sf::Vector2f(100, 50));
|
||||||
|
/// rectangle.setOutlineColor(sf::Color::Red);
|
||||||
|
/// rectangle.setOutlineThickness(5);
|
||||||
|
/// rectangle.setPosition({10, 20});
|
||||||
|
/// ...
|
||||||
|
/// window.draw(rectangle);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::Shape`, `sf::CircleShape`, `sf::ConvexShape`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,191 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Graphics/BlendMode.hpp>
|
||||||
|
#include <SFML/Graphics/CoordinateType.hpp>
|
||||||
|
#include <SFML/Graphics/StencilMode.hpp>
|
||||||
|
#include <SFML/Graphics/Transform.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class Shader;
|
||||||
|
class Texture;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Define the states used for drawing to a `RenderTarget`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
struct SFML_GRAPHICS_API RenderStates
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// Constructing a default set of render states is equivalent
|
||||||
|
/// to using `sf::RenderStates::Default`.
|
||||||
|
/// The default set defines:
|
||||||
|
/// \li the `BlendAlpha` blend mode
|
||||||
|
/// \li the default `StencilMode` (no stencil)
|
||||||
|
/// \li the identity transform
|
||||||
|
/// \li a `nullptr` texture
|
||||||
|
/// \li a `nullptr` shader
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
RenderStates() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct a default set of render states with a custom blend mode
|
||||||
|
///
|
||||||
|
/// \param theBlendMode Blend mode to use
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
RenderStates(const BlendMode& theBlendMode);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct a default set of render states with a custom stencil mode
|
||||||
|
///
|
||||||
|
/// \param theStencilMode Stencil mode to use
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
RenderStates(const StencilMode& theStencilMode);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct a default set of render states with a custom transform
|
||||||
|
///
|
||||||
|
/// \param theTransform Transform to use
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
RenderStates(const Transform& theTransform);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct a default set of render states with a custom texture
|
||||||
|
///
|
||||||
|
/// \param theTexture Texture to use
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
RenderStates(const Texture* theTexture);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct a default set of render states with a custom shader
|
||||||
|
///
|
||||||
|
/// \param theShader Shader to use
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
RenderStates(const Shader* theShader);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct a set of render states with all its attributes
|
||||||
|
///
|
||||||
|
/// \param theBlendMode Blend mode to use
|
||||||
|
/// \param theStencilMode Stencil mode to use
|
||||||
|
/// \param theTransform Transform to use
|
||||||
|
/// \param theCoordinateType Texture coordinate type to use
|
||||||
|
/// \param theTexture Texture to use
|
||||||
|
/// \param theShader Shader to use
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
RenderStates(const BlendMode& theBlendMode,
|
||||||
|
const StencilMode& theStencilMode,
|
||||||
|
const Transform& theTransform,
|
||||||
|
CoordinateType theCoordinateType,
|
||||||
|
const Texture* theTexture,
|
||||||
|
const Shader* theShader);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Static member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||||
|
static const RenderStates Default; //!< Special instance holding the default render states
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
BlendMode blendMode{BlendAlpha}; //!< Blending mode
|
||||||
|
StencilMode stencilMode; //!< Stencil mode
|
||||||
|
Transform transform; //!< Transform
|
||||||
|
CoordinateType coordinateType{CoordinateType::Pixels}; //!< Texture coordinate type
|
||||||
|
const Texture* texture{}; //!< Texture
|
||||||
|
const Shader* shader{}; //!< Shader
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::RenderStates
|
||||||
|
/// \ingroup graphics
|
||||||
|
///
|
||||||
|
/// There are six global states that can be applied to
|
||||||
|
/// the drawn objects:
|
||||||
|
/// \li the blend mode: how pixels of the object are blended with the background
|
||||||
|
/// \li the stencil mode: how pixels of the object interact with the stencil buffer
|
||||||
|
/// \li the transform: how the object is positioned/rotated/scaled
|
||||||
|
/// \li the texture coordinate type: how texture coordinates are interpreted
|
||||||
|
/// \li the texture: what image is mapped to the object
|
||||||
|
/// \li the shader: what custom effect is applied to the object
|
||||||
|
///
|
||||||
|
/// High-level objects such as sprites or text force some of
|
||||||
|
/// these states when they are drawn. For example, a sprite
|
||||||
|
/// will set its own texture, so that you don't have to care
|
||||||
|
/// about it when drawing the sprite.
|
||||||
|
///
|
||||||
|
/// The transform is a special case: sprites, texts and shapes
|
||||||
|
/// (and it's a good idea to do it with your own drawable classes
|
||||||
|
/// too) combine their transform with the one that is passed in the
|
||||||
|
/// RenderStates structure. So that you can use a "global" transform
|
||||||
|
/// on top of each object's transform.
|
||||||
|
///
|
||||||
|
/// Most objects, especially high-level drawables, can be drawn
|
||||||
|
/// directly without defining render states explicitly -- the
|
||||||
|
/// default set of states is ok in most cases.
|
||||||
|
/// \code
|
||||||
|
/// window.draw(sprite);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// If you want to use a single specific render state,
|
||||||
|
/// for example a shader, you can pass it directly to the Draw
|
||||||
|
/// function: `sf::RenderStates` has an implicit one-argument
|
||||||
|
/// constructor for each state.
|
||||||
|
/// \code
|
||||||
|
/// window.draw(sprite, shader);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// When you're inside the Draw function of a drawable
|
||||||
|
/// object (inherited from `sf::Drawable`), you can
|
||||||
|
/// either pass the render states unmodified, or change
|
||||||
|
/// some of them.
|
||||||
|
/// For example, a transformable object will combine the
|
||||||
|
/// current transform with its own transform. A sprite will
|
||||||
|
/// set its texture. Etc.
|
||||||
|
///
|
||||||
|
/// \see `sf::RenderTarget`, `sf::Drawable`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,606 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Graphics/BlendMode.hpp>
|
||||||
|
#include <SFML/Graphics/Color.hpp>
|
||||||
|
#include <SFML/Graphics/CoordinateType.hpp>
|
||||||
|
#include <SFML/Graphics/PrimitiveType.hpp>
|
||||||
|
#include <SFML/Graphics/Rect.hpp>
|
||||||
|
#include <SFML/Graphics/RenderStates.hpp>
|
||||||
|
#include <SFML/Graphics/StencilMode.hpp>
|
||||||
|
#include <SFML/Graphics/Vertex.hpp>
|
||||||
|
#include <SFML/Graphics/View.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/Vector2.hpp>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class Drawable;
|
||||||
|
class Shader;
|
||||||
|
class Texture;
|
||||||
|
class Transform;
|
||||||
|
class VertexBuffer;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Base class for all render targets (window, texture, ...)
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_GRAPHICS_API RenderTarget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Destructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
virtual ~RenderTarget() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Deleted copy constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
RenderTarget(const RenderTarget&) = delete;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Deleted copy assignment
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
RenderTarget& operator=(const RenderTarget&) = delete;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
RenderTarget(RenderTarget&&) noexcept = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move assignment
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
RenderTarget& operator=(RenderTarget&&) noexcept = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Clear the entire target with a single color
|
||||||
|
///
|
||||||
|
/// This function is usually called once every frame,
|
||||||
|
/// to clear the previous contents of the target.
|
||||||
|
///
|
||||||
|
/// \param color Fill color to use to clear the render target
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void clear(Color color = Color::Black);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Clear the stencil buffer to a specific value
|
||||||
|
///
|
||||||
|
/// The specified value is truncated to the bit width of
|
||||||
|
/// the current stencil buffer.
|
||||||
|
///
|
||||||
|
/// \param stencilValue Stencil value to clear to
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void clearStencil(StencilValue stencilValue);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Clear the entire target with a single color and stencil value
|
||||||
|
///
|
||||||
|
/// The specified stencil value is truncated to the bit
|
||||||
|
/// width of the current stencil buffer.
|
||||||
|
///
|
||||||
|
/// \param color Fill color to use to clear the render target
|
||||||
|
/// \param stencilValue Stencil value to clear to
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void clear(Color color, StencilValue stencilValue);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Change the current active view
|
||||||
|
///
|
||||||
|
/// The view is like a 2D camera, it controls which part of
|
||||||
|
/// the 2D scene is visible, and how it is viewed in the
|
||||||
|
/// render target.
|
||||||
|
/// The new view will affect everything that is drawn, until
|
||||||
|
/// another view is set.
|
||||||
|
/// The render target keeps its own copy of the view object,
|
||||||
|
/// so it is not necessary to keep the original one alive
|
||||||
|
/// after calling this function.
|
||||||
|
/// To restore the original view of the target, you can pass
|
||||||
|
/// the result of `getDefaultView()` to this function.
|
||||||
|
///
|
||||||
|
/// \param view New view to use
|
||||||
|
///
|
||||||
|
/// \see `getView`, `getDefaultView`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setView(const View& view);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the view currently in use in the render target
|
||||||
|
///
|
||||||
|
/// \return The view object that is currently used
|
||||||
|
///
|
||||||
|
/// \see `setView`, `getDefaultView`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const View& getView() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the default view of the render target
|
||||||
|
///
|
||||||
|
/// The default view has the initial size of the render target,
|
||||||
|
/// and never changes after the target has been created.
|
||||||
|
///
|
||||||
|
/// \return The default view of the render target
|
||||||
|
///
|
||||||
|
/// \see `setView`, `getView`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const View& getDefaultView() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the viewport of a view, applied to this render target
|
||||||
|
///
|
||||||
|
/// The viewport is defined in the view as a ratio, this function
|
||||||
|
/// simply applies this ratio to the current dimensions of the
|
||||||
|
/// render target to calculate the pixels rectangle that the viewport
|
||||||
|
/// actually covers in the target.
|
||||||
|
///
|
||||||
|
/// \param view The view for which we want to compute the viewport
|
||||||
|
///
|
||||||
|
/// \return Viewport rectangle, expressed in pixels
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] IntRect getViewport(const View& view) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the scissor rectangle of a view, applied to this render target
|
||||||
|
///
|
||||||
|
/// The scissor rectangle is defined in the view as a ratio. This
|
||||||
|
/// function simply applies this ratio to the current dimensions
|
||||||
|
/// of the render target to calculate the pixels rectangle
|
||||||
|
/// that the scissor rectangle actually covers in the target.
|
||||||
|
///
|
||||||
|
/// \param view The view for which we want to compute the scissor rectangle
|
||||||
|
///
|
||||||
|
/// \return Scissor rectangle, expressed in pixels
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] IntRect getScissor(const View& view) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert a point from target coordinates to world
|
||||||
|
/// coordinates, using the current view
|
||||||
|
///
|
||||||
|
/// This function is an overload of the mapPixelToCoords
|
||||||
|
/// function that implicitly uses the current view.
|
||||||
|
/// It is equivalent to:
|
||||||
|
/// \code
|
||||||
|
/// target.mapPixelToCoords(point, target.getView());
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \param point Pixel to convert
|
||||||
|
///
|
||||||
|
/// \return The converted point, in "world" coordinates
|
||||||
|
///
|
||||||
|
/// \see `mapCoordsToPixel`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Vector2f mapPixelToCoords(Vector2i point) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert a point from target coordinates to world coordinates
|
||||||
|
///
|
||||||
|
/// This function finds the 2D position that matches the
|
||||||
|
/// given pixel of the render target. In other words, it does
|
||||||
|
/// the inverse of what the graphics card does, to find the
|
||||||
|
/// initial position of a rendered pixel.
|
||||||
|
///
|
||||||
|
/// Initially, both coordinate systems (world units and target pixels)
|
||||||
|
/// match perfectly. But if you define a custom view or resize your
|
||||||
|
/// render target, this assertion is not `true` anymore, i.e. a point
|
||||||
|
/// located at (10, 50) in your render target may map to the point
|
||||||
|
/// (150, 75) in your 2D world -- if the view is translated by (140, 25).
|
||||||
|
///
|
||||||
|
/// For render-windows, this function is typically used to find
|
||||||
|
/// which point (or object) is located below the mouse cursor.
|
||||||
|
///
|
||||||
|
/// This version uses a custom view for calculations, see the other
|
||||||
|
/// overload of the function if you want to use the current view of the
|
||||||
|
/// render target.
|
||||||
|
///
|
||||||
|
/// \param point Pixel to convert
|
||||||
|
/// \param view The view to use for converting the point
|
||||||
|
///
|
||||||
|
/// \return The converted point, in "world" units
|
||||||
|
///
|
||||||
|
/// \see `mapCoordsToPixel`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Vector2f mapPixelToCoords(Vector2i point, const View& view) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert a point from world coordinates to target
|
||||||
|
/// coordinates, using the current view
|
||||||
|
///
|
||||||
|
/// This function is an overload of the `mapCoordsToPixel`
|
||||||
|
/// function that implicitly uses the current view.
|
||||||
|
/// It is equivalent to:
|
||||||
|
/// \code
|
||||||
|
/// target.mapCoordsToPixel(point, target.getView());
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \param point Point to convert
|
||||||
|
///
|
||||||
|
/// \return The converted point, in target coordinates (pixels)
|
||||||
|
///
|
||||||
|
/// \see `mapPixelToCoords`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Vector2i mapCoordsToPixel(Vector2f point) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Convert a point from world coordinates to target coordinates
|
||||||
|
///
|
||||||
|
/// This function finds the pixel of the render target that matches
|
||||||
|
/// the given 2D point. In other words, it goes through the same process
|
||||||
|
/// as the graphics card, to compute the final position of a rendered point.
|
||||||
|
///
|
||||||
|
/// Initially, both coordinate systems (world units and target pixels)
|
||||||
|
/// match perfectly. But if you define a custom view or resize your
|
||||||
|
/// render target, this assertion is not `true` anymore, i.e. a point
|
||||||
|
/// located at (150, 75) in your 2D world may map to the pixel
|
||||||
|
/// (10, 50) of your render target -- if the view is translated by (140, 25).
|
||||||
|
///
|
||||||
|
/// This version uses a custom view for calculations, see the other
|
||||||
|
/// overload of the function if you want to use the current view of the
|
||||||
|
/// render target.
|
||||||
|
///
|
||||||
|
/// \param point Point to convert
|
||||||
|
/// \param view The view to use for converting the point
|
||||||
|
///
|
||||||
|
/// \return The converted point, in target coordinates (pixels)
|
||||||
|
///
|
||||||
|
/// \see `mapPixelToCoords`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Vector2i mapCoordsToPixel(Vector2f point, const View& view) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Draw a drawable object to the render target
|
||||||
|
///
|
||||||
|
/// \param drawable Object to draw
|
||||||
|
/// \param states Render states to use for drawing
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void draw(const Drawable& drawable, const RenderStates& states = RenderStates::Default);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Draw primitives defined by an array of vertices
|
||||||
|
///
|
||||||
|
/// \param vertices Pointer to the vertices
|
||||||
|
/// \param vertexCount Number of vertices in the array
|
||||||
|
/// \param type Type of primitives to draw
|
||||||
|
/// \param states Render states to use for drawing
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void draw(const Vertex* vertices,
|
||||||
|
std::size_t vertexCount,
|
||||||
|
PrimitiveType type,
|
||||||
|
const RenderStates& states = RenderStates::Default);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Draw primitives defined by a vertex buffer
|
||||||
|
///
|
||||||
|
/// \param vertexBuffer Vertex buffer
|
||||||
|
/// \param states Render states to use for drawing
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void draw(const VertexBuffer& vertexBuffer, const RenderStates& states = RenderStates::Default);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Draw primitives defined by a vertex buffer
|
||||||
|
///
|
||||||
|
/// \param vertexBuffer Vertex buffer
|
||||||
|
/// \param firstVertex Index of the first vertex to render
|
||||||
|
/// \param vertexCount Number of vertices to render
|
||||||
|
/// \param states Render states to use for drawing
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void draw(const VertexBuffer& vertexBuffer,
|
||||||
|
std::size_t firstVertex,
|
||||||
|
std::size_t vertexCount,
|
||||||
|
const RenderStates& states = RenderStates::Default);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Return the size of the rendering region of the target
|
||||||
|
///
|
||||||
|
/// \return Size in pixels
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] virtual Vector2u getSize() const = 0;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Tell if the render target will use sRGB encoding when drawing on it
|
||||||
|
///
|
||||||
|
/// \return `true` if the render target use sRGB encoding, `false` otherwise
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] virtual bool isSrgb() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Activate or deactivate the render target for rendering
|
||||||
|
///
|
||||||
|
/// This function makes the render target's context current for
|
||||||
|
/// future OpenGL rendering operations (so you shouldn't care
|
||||||
|
/// about it if you're not doing direct OpenGL stuff).
|
||||||
|
/// A render target's context is active only on the current thread,
|
||||||
|
/// if you want to make it active on another thread you have
|
||||||
|
/// to deactivate it on the previous thread first if it was active.
|
||||||
|
/// Only one context can be current in a thread, so if you
|
||||||
|
/// want to draw OpenGL geometry to another render target
|
||||||
|
/// don't forget to activate it again. Activating a render
|
||||||
|
/// target will automatically deactivate the previously active
|
||||||
|
/// context (if any).
|
||||||
|
///
|
||||||
|
/// \param active `true` to activate, `false` to deactivate
|
||||||
|
///
|
||||||
|
/// \return `true` if operation was successful, `false` otherwise
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] virtual bool setActive(bool active = true);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Save the current OpenGL render states and matrices
|
||||||
|
///
|
||||||
|
/// This function can be used when you mix SFML drawing
|
||||||
|
/// and direct OpenGL rendering. Combined with popGLStates,
|
||||||
|
/// it ensures that:
|
||||||
|
/// \li SFML's internal states are not messed up by your OpenGL code
|
||||||
|
/// \li your OpenGL states are not modified by a call to a SFML function
|
||||||
|
///
|
||||||
|
/// More specifically, it must be used around code that
|
||||||
|
/// calls `draw` functions. Example:
|
||||||
|
/// \code
|
||||||
|
/// // OpenGL code here...
|
||||||
|
/// window.pushGLStates();
|
||||||
|
/// window.draw(...);
|
||||||
|
/// window.draw(...);
|
||||||
|
/// window.popGLStates();
|
||||||
|
/// // OpenGL code here...
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// Note that this function is quite expensive: it saves all the
|
||||||
|
/// possible OpenGL states and matrices, even the ones you
|
||||||
|
/// don't care about. Therefore it should be used wisely.
|
||||||
|
/// It is provided for convenience, but the best results will
|
||||||
|
/// be achieved if you handle OpenGL states yourself (because
|
||||||
|
/// you know which states have really changed, and need to be
|
||||||
|
/// saved and restored). Take a look at the resetGLStates
|
||||||
|
/// function if you do so.
|
||||||
|
///
|
||||||
|
/// \see `popGLStates`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void pushGLStates();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Restore the previously saved OpenGL render states and matrices
|
||||||
|
///
|
||||||
|
/// See the description of `pushGLStates` to get a detailed
|
||||||
|
/// description of these functions.
|
||||||
|
///
|
||||||
|
/// \see `pushGLStates`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void popGLStates();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Reset the internal OpenGL states so that the target is ready for drawing
|
||||||
|
///
|
||||||
|
/// This function can be used when you mix SFML drawing
|
||||||
|
/// and direct OpenGL rendering, if you choose not to use
|
||||||
|
/// `pushGLStates`/`popGLStates`. It makes sure that all OpenGL
|
||||||
|
/// states needed by SFML are set, so that subsequent `draw()`
|
||||||
|
/// calls will work as expected.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// \code
|
||||||
|
/// // OpenGL code here...
|
||||||
|
/// glPushAttrib(...);
|
||||||
|
/// window.resetGLStates();
|
||||||
|
/// window.draw(...);
|
||||||
|
/// window.draw(...);
|
||||||
|
/// glPopAttrib(...);
|
||||||
|
/// // OpenGL code here...
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void resetGLStates();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
RenderTarget() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Performs the common initialization step after creation
|
||||||
|
///
|
||||||
|
/// The derived classes must call this function after the
|
||||||
|
/// target is created and ready for drawing.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void initialize();
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Apply the current view
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void applyCurrentView();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Apply a new blending mode
|
||||||
|
///
|
||||||
|
/// \param mode Blending mode to apply
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void applyBlendMode(const BlendMode& mode);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Apply a new stencil mode
|
||||||
|
///
|
||||||
|
/// \param mode Stencil mode to apply
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void applyStencilMode(const StencilMode& mode);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Apply a new transform
|
||||||
|
///
|
||||||
|
/// \param transform Transform to apply
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void applyTransform(const Transform& transform);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Apply a new texture
|
||||||
|
///
|
||||||
|
/// \param texture Texture to apply
|
||||||
|
/// \param coordinateType The texture coordinate type to use
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void applyTexture(const Texture* texture, CoordinateType coordinateType = CoordinateType::Pixels);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Apply a new shader
|
||||||
|
///
|
||||||
|
/// \param shader Shader to apply
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void applyShader(const Shader* shader);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Setup environment for drawing
|
||||||
|
///
|
||||||
|
/// \param useVertexCache Are we going to use the vertex cache?
|
||||||
|
/// \param states Render states to use for drawing
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setupDraw(bool useVertexCache, const RenderStates& states);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Draw the primitives
|
||||||
|
///
|
||||||
|
/// \param type Type of primitives to draw
|
||||||
|
/// \param firstVertex Index of the first vertex to use when drawing
|
||||||
|
/// \param vertexCount Number of vertices to use when drawing
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void drawPrimitives(PrimitiveType type, std::size_t firstVertex, std::size_t vertexCount);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Clean up environment after drawing
|
||||||
|
///
|
||||||
|
/// \param states Render states used for drawing
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void cleanupDraw(const RenderStates& states);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Render states cache
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
struct StatesCache
|
||||||
|
{
|
||||||
|
bool enable{}; //!< Is the cache enabled?
|
||||||
|
bool glStatesSet{}; //!< Are our internal GL states set yet?
|
||||||
|
bool viewChanged{}; //!< Has the current view changed since last draw?
|
||||||
|
bool scissorEnabled{}; //!< Is scissor testing enabled?
|
||||||
|
bool stencilEnabled{}; //!< Is stencil testing enabled?
|
||||||
|
BlendMode lastBlendMode; //!< Cached blending mode
|
||||||
|
StencilMode lastStencilMode; //!< Cached stencil
|
||||||
|
std::uint64_t lastTextureId{}; //!< Cached texture
|
||||||
|
CoordinateType lastCoordinateType{}; //!< Texture coordinate type
|
||||||
|
bool texCoordsArrayEnabled{}; //!< Is `GL_TEXTURE_COORD_ARRAY` client state enabled?
|
||||||
|
bool useVertexCache{}; //!< Did we previously use the vertex cache?
|
||||||
|
std::array<Vertex, 4> vertexCache{}; //!< Pre-transformed vertices cache
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
View m_defaultView; //!< Default view
|
||||||
|
View m_view; //!< Current view
|
||||||
|
StatesCache m_cache{}; //!< Render states cache
|
||||||
|
std::uint64_t m_id{}; //!< Unique number that identifies the RenderTarget
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::RenderTarget
|
||||||
|
/// \ingroup graphics
|
||||||
|
///
|
||||||
|
/// `sf::RenderTarget` defines the common behavior of all the
|
||||||
|
/// 2D render targets usable in the graphics module. It makes
|
||||||
|
/// it possible to draw 2D entities like sprites, shapes, text
|
||||||
|
/// without using any OpenGL command directly.
|
||||||
|
///
|
||||||
|
/// A `sf::RenderTarget` is also able to use views (`sf::View`),
|
||||||
|
/// which are a kind of 2D cameras. With views you can globally
|
||||||
|
/// scroll, rotate or zoom everything that is drawn,
|
||||||
|
/// without having to transform every single entity. See the
|
||||||
|
/// documentation of `sf::View` for more details and sample pieces of
|
||||||
|
/// code about this class.
|
||||||
|
///
|
||||||
|
/// On top of that, render targets are still able to render direct
|
||||||
|
/// OpenGL stuff. It is even possible to mix together OpenGL calls
|
||||||
|
/// and regular SFML drawing commands. When doing so, make sure that
|
||||||
|
/// OpenGL states are not messed up by calling the
|
||||||
|
/// `pushGLStates`/`popGLStates` functions.
|
||||||
|
///
|
||||||
|
/// While render targets are moveable, it is not valid to move them
|
||||||
|
/// between threads. This will cause your program to crash. The
|
||||||
|
/// problem boils down to OpenGL being limited with regard to how it
|
||||||
|
/// works in multithreaded environments. Please ensure you only move
|
||||||
|
/// render targets within the same thread.
|
||||||
|
///
|
||||||
|
/// \see `sf::RenderWindow`, `sf::RenderTexture`, `sf::View`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,342 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Graphics/RenderTarget.hpp>
|
||||||
|
#include <SFML/Graphics/Texture.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Window/ContextSettings.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/Vector2.hpp>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
namespace priv
|
||||||
|
{
|
||||||
|
class RenderTextureImpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Target for off-screen 2D rendering into a texture
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_GRAPHICS_API RenderTexture : public RenderTarget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// Constructs a render-texture with width 0 and height 0.
|
||||||
|
///
|
||||||
|
/// \see `resize`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
RenderTexture();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct a render-texture
|
||||||
|
///
|
||||||
|
/// The last parameter, `settings`, is useful if you want to enable
|
||||||
|
/// multi-sampling or use the render-texture for OpenGL rendering that
|
||||||
|
/// requires a depth or stencil buffer. Otherwise it is unnecessary, and
|
||||||
|
/// you should leave this parameter at its default value.
|
||||||
|
///
|
||||||
|
/// After creation, the contents of the render-texture are undefined.
|
||||||
|
/// Call `RenderTexture::clear` first to ensure a single color fill.
|
||||||
|
///
|
||||||
|
/// \param size Width and height of the render-texture
|
||||||
|
/// \param settings Additional settings for the underlying OpenGL texture and context
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if creation was unsuccessful
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
RenderTexture(Vector2u size, const ContextSettings& settings = {});
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Destructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
~RenderTexture() override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Deleted copy constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
RenderTexture(const RenderTexture&) = delete;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Deleted copy assignment
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
RenderTexture& operator=(const RenderTexture&) = delete;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
RenderTexture(RenderTexture&&) noexcept;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move assignment operator
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
RenderTexture& operator=(RenderTexture&&) noexcept;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Resize the render-texture
|
||||||
|
///
|
||||||
|
/// The last parameter, `settings`, is useful if you want to enable
|
||||||
|
/// multi-sampling or use the render-texture for OpenGL rendering that
|
||||||
|
/// requires a depth or stencil buffer. Otherwise it is unnecessary, and
|
||||||
|
/// you should leave this parameter at its default value.
|
||||||
|
///
|
||||||
|
/// After resizing, the contents of the render-texture are undefined.
|
||||||
|
/// Call `RenderTexture::clear` first to ensure a single color fill.
|
||||||
|
///
|
||||||
|
/// \param size Width and height of the render-texture
|
||||||
|
/// \param settings Additional settings for the underlying OpenGL texture and context
|
||||||
|
///
|
||||||
|
/// \return `true` if resizing has been successful, `false` if it failed
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool resize(Vector2u size, const ContextSettings& settings = {});
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the maximum anti-aliasing level supported by the system
|
||||||
|
///
|
||||||
|
/// \return The maximum anti-aliasing level supported by the system
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] static unsigned int getMaximumAntiAliasingLevel();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Enable or disable texture smoothing
|
||||||
|
///
|
||||||
|
/// This function is similar to `Texture::setSmooth`.
|
||||||
|
/// This parameter is disabled by default.
|
||||||
|
///
|
||||||
|
/// \param smooth `true` to enable smoothing, `false` to disable it
|
||||||
|
///
|
||||||
|
/// \see `isSmooth`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setSmooth(bool smooth);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Tell whether the smooth filtering is enabled or not
|
||||||
|
///
|
||||||
|
/// \return `true` if texture smoothing is enabled
|
||||||
|
///
|
||||||
|
/// \see `setSmooth`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool isSmooth() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Enable or disable texture repeating
|
||||||
|
///
|
||||||
|
/// This function is similar to `Texture::setRepeated`.
|
||||||
|
/// This parameter is disabled by default.
|
||||||
|
///
|
||||||
|
/// \param repeated `true` to enable repeating, `false` to disable it
|
||||||
|
///
|
||||||
|
/// \see `isRepeated`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setRepeated(bool repeated);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Tell whether the texture is repeated or not
|
||||||
|
///
|
||||||
|
/// \return `true` if texture is repeated
|
||||||
|
///
|
||||||
|
/// \see `setRepeated`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool isRepeated() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Generate a mipmap using the current texture data
|
||||||
|
///
|
||||||
|
/// This function is similar to `Texture::generateMipmap` and operates
|
||||||
|
/// on the texture used as the target for drawing.
|
||||||
|
/// Be aware that any draw operation may modify the base level image data.
|
||||||
|
/// For this reason, calling this function only makes sense after all
|
||||||
|
/// drawing is completed and display has been called. Not calling display
|
||||||
|
/// after subsequent drawing will lead to undefined behavior if a mipmap
|
||||||
|
/// had been previously generated.
|
||||||
|
///
|
||||||
|
/// \return `true` if mipmap generation was successful, `false` if unsuccessful
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool generateMipmap();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Activate or deactivate the render-texture for rendering
|
||||||
|
///
|
||||||
|
/// This function makes the render-texture's context current for
|
||||||
|
/// future OpenGL rendering operations (so you shouldn't care
|
||||||
|
/// about it if you're not doing direct OpenGL stuff).
|
||||||
|
/// Only one context can be current in a thread, so if you
|
||||||
|
/// want to draw OpenGL geometry to another render target
|
||||||
|
/// (like a RenderWindow) don't forget to activate it again.
|
||||||
|
///
|
||||||
|
/// \param active `true` to activate, `false` to deactivate
|
||||||
|
///
|
||||||
|
/// \return `true` if operation was successful, `false` otherwise
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool setActive(bool active = true) override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Update the contents of the target texture
|
||||||
|
///
|
||||||
|
/// This function updates the target texture with what
|
||||||
|
/// has been drawn so far. Like for windows, calling this
|
||||||
|
/// function is mandatory at the end of rendering. Not calling
|
||||||
|
/// it may leave the texture in an undefined state.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void display();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Return the size of the rendering region of the texture
|
||||||
|
///
|
||||||
|
/// The returned value is the size that you passed to
|
||||||
|
/// the create function.
|
||||||
|
///
|
||||||
|
/// \return Size in pixels
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Vector2u getSize() const override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Tell if the render-texture will use sRGB encoding when drawing on it
|
||||||
|
///
|
||||||
|
/// You can request sRGB encoding for a render-texture
|
||||||
|
/// by having the sRgbCapable flag set for the context parameter of `create()` method
|
||||||
|
///
|
||||||
|
/// \return `true` if the render-texture use sRGB encoding, `false` otherwise
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool isSrgb() const override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get a read-only reference to the target texture
|
||||||
|
///
|
||||||
|
/// After drawing to the render-texture and calling Display,
|
||||||
|
/// you can retrieve the updated texture using this function,
|
||||||
|
/// and draw it using a sprite (for example).
|
||||||
|
/// The internal `sf::Texture` of a render-texture is always the
|
||||||
|
/// same instance, so that it is possible to call this function
|
||||||
|
/// once and keep a reference to the texture even after it is
|
||||||
|
/// modified.
|
||||||
|
///
|
||||||
|
/// \return Const reference to the texture
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const Texture& getTexture() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::unique_ptr<priv::RenderTextureImpl> m_impl; //!< Platform/hardware specific implementation
|
||||||
|
Texture m_texture; //!< Target texture to draw on
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::RenderTexture
|
||||||
|
/// \ingroup graphics
|
||||||
|
///
|
||||||
|
/// `sf::RenderTexture` is the little brother of `sf::RenderWindow`.
|
||||||
|
/// It implements the same 2D drawing and OpenGL-related functions
|
||||||
|
/// (see their base class `sf::RenderTarget` for more details),
|
||||||
|
/// the difference is that the result is stored in an off-screen
|
||||||
|
/// texture rather than being show in a window.
|
||||||
|
///
|
||||||
|
/// Rendering to a texture can be useful in a variety of situations:
|
||||||
|
/// \li precomputing a complex static texture (like a level's background from multiple tiles)
|
||||||
|
/// \li applying post-effects to the whole scene with shaders
|
||||||
|
/// \li creating a sprite from a 3D object rendered with OpenGL
|
||||||
|
/// \li etc.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
///
|
||||||
|
/// \code
|
||||||
|
/// // Create a new render-window
|
||||||
|
/// sf::RenderWindow window(sf::VideoMode({800, 600}), "SFML window");
|
||||||
|
///
|
||||||
|
/// // Create a new render-texture
|
||||||
|
/// sf::RenderTexture texture({500, 500});
|
||||||
|
///
|
||||||
|
/// // The main loop
|
||||||
|
/// while (window.isOpen())
|
||||||
|
/// {
|
||||||
|
/// // Event processing
|
||||||
|
/// // ...
|
||||||
|
///
|
||||||
|
/// // Clear the whole texture with red color
|
||||||
|
/// texture.clear(sf::Color::Red);
|
||||||
|
///
|
||||||
|
/// // Draw stuff to the texture
|
||||||
|
/// texture.draw(sprite); // sprite is a sf::Sprite
|
||||||
|
/// texture.draw(shape); // shape is a sf::Shape
|
||||||
|
/// texture.draw(text); // text is a sf::Text
|
||||||
|
///
|
||||||
|
/// // We're done drawing to the texture
|
||||||
|
/// texture.display();
|
||||||
|
///
|
||||||
|
/// // Now we start rendering to the window, clear it first
|
||||||
|
/// window.clear();
|
||||||
|
///
|
||||||
|
/// // Draw the texture
|
||||||
|
/// sf::Sprite sprite(texture.getTexture());
|
||||||
|
/// window.draw(sprite);
|
||||||
|
///
|
||||||
|
/// // End the current frame and display its contents on screen
|
||||||
|
/// window.display();
|
||||||
|
/// }
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// Like `sf::RenderWindow`, `sf::RenderTexture` is still able to render direct
|
||||||
|
/// OpenGL stuff. It is even possible to mix together OpenGL calls
|
||||||
|
/// and regular SFML drawing commands. If you need a depth buffer for
|
||||||
|
/// 3D rendering, don't forget to request it when calling `RenderTexture::create`.
|
||||||
|
///
|
||||||
|
/// \see `sf::RenderTarget`, `sf::RenderWindow`, `sf::View`, `sf::Texture`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,308 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Graphics/RenderTarget.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Window/ContextSettings.hpp>
|
||||||
|
#include <SFML/Window/VideoMode.hpp>
|
||||||
|
#include <SFML/Window/Window.hpp>
|
||||||
|
#include <SFML/Window/WindowEnums.hpp>
|
||||||
|
#include <SFML/Window/WindowHandle.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/Vector2.hpp>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class Image;
|
||||||
|
class String;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Window that can serve as a target for 2D drawing
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_GRAPHICS_API RenderWindow : public Window, public RenderTarget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// This constructor doesn't actually create the window,
|
||||||
|
/// use the other constructors or call `create()` to do so.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
RenderWindow() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct a new window
|
||||||
|
///
|
||||||
|
/// This constructor creates the window with the size and pixel
|
||||||
|
/// depth defined in `mode`. An optional style can be passed to
|
||||||
|
/// customize the look and behavior of the window (borders,
|
||||||
|
/// title bar, resizable, closable, ...).
|
||||||
|
///
|
||||||
|
/// The last parameter is an optional structure specifying
|
||||||
|
/// advanced OpenGL context settings such as anti-aliasing,
|
||||||
|
/// depth-buffer bits, etc. You shouldn't care about these
|
||||||
|
/// parameters for a regular usage of the graphics module.
|
||||||
|
///
|
||||||
|
/// \param mode Video mode to use (defines the width, height and depth of the rendering area of the window)
|
||||||
|
/// \param title Title of the window
|
||||||
|
/// \param style %Window style, a bitwise OR combination of `sf::Style` enumerators
|
||||||
|
/// \param state %Window state
|
||||||
|
/// \param settings Additional settings for the underlying OpenGL context
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
RenderWindow(VideoMode mode,
|
||||||
|
const String& title,
|
||||||
|
std::uint32_t style = Style::Default,
|
||||||
|
State state = State::Windowed,
|
||||||
|
const ContextSettings& settings = {});
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct a new window
|
||||||
|
///
|
||||||
|
/// This constructor creates the window with the size and pixel
|
||||||
|
/// depth defined in `mode`. If `state` is `State::Fullscreen`,
|
||||||
|
/// then `mode` must be a valid video mode.
|
||||||
|
///
|
||||||
|
/// The last parameter is an optional structure specifying
|
||||||
|
/// advanced OpenGL context settings such as anti-aliasing,
|
||||||
|
/// depth-buffer bits, etc.
|
||||||
|
///
|
||||||
|
/// \param mode Video mode to use (defines the width, height and depth of the rendering area of the window)
|
||||||
|
/// \param title Title of the window
|
||||||
|
/// \param state %Window state
|
||||||
|
/// \param settings Additional settings for the underlying OpenGL context
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
RenderWindow(VideoMode mode, const String& title, State state, const ContextSettings& settings = {});
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the window from an existing control
|
||||||
|
///
|
||||||
|
/// Use this constructor if you want to create an SFML
|
||||||
|
/// rendering area into an already existing control.
|
||||||
|
///
|
||||||
|
/// The second parameter is an optional structure specifying
|
||||||
|
/// advanced OpenGL context settings such as anti-aliasing,
|
||||||
|
/// depth-buffer bits, etc. You shouldn't care about these
|
||||||
|
/// parameters for a regular usage of the graphics module.
|
||||||
|
///
|
||||||
|
/// \param handle Platform-specific handle of the control (\a HWND on
|
||||||
|
/// Windows, \a %Window on Linux/FreeBSD, \a NSWindow on macOS)
|
||||||
|
/// \param settings Additional settings for the underlying OpenGL context
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit RenderWindow(WindowHandle handle, const ContextSettings& settings = {});
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the size of the rendering region of the window
|
||||||
|
///
|
||||||
|
/// The size doesn't include the titlebar and borders
|
||||||
|
/// of the window.
|
||||||
|
///
|
||||||
|
/// \return Size in pixels
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Vector2u getSize() const override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Change the window's icon
|
||||||
|
///
|
||||||
|
/// The OS default icon is used by default.
|
||||||
|
///
|
||||||
|
/// \param icon Image to use as the icon. The image is copied,
|
||||||
|
/// so you need not keep the source alive after
|
||||||
|
/// calling this function.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setIcon(const Image& icon);
|
||||||
|
using Window::setIcon;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Tell if the window will use sRGB encoding when drawing on it
|
||||||
|
///
|
||||||
|
/// You can request sRGB encoding for a window by having the sRgbCapable flag set in the `ContextSettings`
|
||||||
|
///
|
||||||
|
/// \return `true` if the window use sRGB encoding, `false` otherwise
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool isSrgb() const override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Activate or deactivate the window as the current target
|
||||||
|
/// for OpenGL rendering
|
||||||
|
///
|
||||||
|
/// A window is active only on the current thread, if you want to
|
||||||
|
/// make it active on another thread you have to deactivate it
|
||||||
|
/// on the previous thread first if it was active.
|
||||||
|
/// Only one window can be active on a thread at a time, thus
|
||||||
|
/// the window previously active (if any) automatically gets deactivated.
|
||||||
|
/// This is not to be confused with `requestFocus()`.
|
||||||
|
///
|
||||||
|
/// \param active `true` to activate, `false` to deactivate
|
||||||
|
///
|
||||||
|
/// \return `true` if operation was successful, `false` otherwise
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool setActive(bool active = true) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Function called after the window has been created
|
||||||
|
///
|
||||||
|
/// This function is called so that derived classes can
|
||||||
|
/// perform their own specific initialization as soon as
|
||||||
|
/// the window is created.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void onCreate() override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Function called after the window has been resized
|
||||||
|
///
|
||||||
|
/// This function is called so that derived classes can
|
||||||
|
/// perform custom actions when the size of the window changes.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void onResize() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
unsigned int m_defaultFrameBuffer{}; //!< Framebuffer to bind when targeting this window
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::RenderWindow
|
||||||
|
/// \ingroup graphics
|
||||||
|
///
|
||||||
|
/// `sf::RenderWindow` is the main class of the Graphics module.
|
||||||
|
/// It defines an OS window that can be painted using the other
|
||||||
|
/// classes of the graphics module.
|
||||||
|
///
|
||||||
|
/// `sf::RenderWindow` is derived from `sf::Window`, thus it inherits
|
||||||
|
/// all its features: events, window management, OpenGL rendering,
|
||||||
|
/// etc. See the documentation of `sf::Window` for a more complete
|
||||||
|
/// description of all these features, as well as code examples.
|
||||||
|
///
|
||||||
|
/// On top of that, `sf::RenderWindow` adds more features related to
|
||||||
|
/// 2D drawing with the graphics module (see its base class
|
||||||
|
/// `sf::RenderTarget` for more details).
|
||||||
|
/// Here is a typical rendering and event loop with a `sf::RenderWindow`:
|
||||||
|
///
|
||||||
|
/// \code
|
||||||
|
/// // Declare and create a new render-window
|
||||||
|
/// sf::RenderWindow window(sf::VideoMode({800, 600}), "SFML window");
|
||||||
|
///
|
||||||
|
/// // Limit the framerate to 60 frames per second (this step is optional)
|
||||||
|
/// window.setFramerateLimit(60);
|
||||||
|
///
|
||||||
|
/// // The main loop - ends as soon as the window is closed
|
||||||
|
/// while (window.isOpen())
|
||||||
|
/// {
|
||||||
|
/// // Event processing
|
||||||
|
/// while (const std::optional event = window.pollEvent())
|
||||||
|
/// {
|
||||||
|
/// // Request for closing the window
|
||||||
|
/// if (event->is<sf::Event::Closed>())
|
||||||
|
/// window.close();
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // Clear the whole window before rendering a new frame
|
||||||
|
/// window.clear();
|
||||||
|
///
|
||||||
|
/// // Draw some graphical entities
|
||||||
|
/// window.draw(sprite);
|
||||||
|
/// window.draw(circle);
|
||||||
|
/// window.draw(text);
|
||||||
|
///
|
||||||
|
/// // End the current frame and display its contents on screen
|
||||||
|
/// window.display();
|
||||||
|
/// }
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// Like `sf::Window`, `sf::RenderWindow` is still able to render direct
|
||||||
|
/// OpenGL stuff. It is even possible to mix together OpenGL calls
|
||||||
|
/// and regular SFML drawing commands.
|
||||||
|
///
|
||||||
|
/// \code
|
||||||
|
/// // Create the render window
|
||||||
|
/// sf::RenderWindow window(sf::VideoMode({800, 600}), "SFML OpenGL");
|
||||||
|
///
|
||||||
|
/// // Create a sprite and a text to display
|
||||||
|
/// const sf::Texture texture("circle.png");
|
||||||
|
/// sf::Sprite sprite(texture);
|
||||||
|
/// const sf::Font font("arial.ttf");
|
||||||
|
/// sf::Text text(font);
|
||||||
|
/// ...
|
||||||
|
///
|
||||||
|
/// // Perform OpenGL initializations
|
||||||
|
/// glMatrixMode(GL_PROJECTION);
|
||||||
|
/// ...
|
||||||
|
///
|
||||||
|
/// // Start the rendering loop
|
||||||
|
/// while (window.isOpen())
|
||||||
|
/// {
|
||||||
|
/// // Process events
|
||||||
|
/// ...
|
||||||
|
///
|
||||||
|
/// // Draw a background sprite
|
||||||
|
/// window.pushGLStates();
|
||||||
|
/// window.draw(sprite);
|
||||||
|
/// window.popGLStates();
|
||||||
|
///
|
||||||
|
/// // Draw a 3D object using OpenGL
|
||||||
|
/// glBegin(GL_TRIANGLES);
|
||||||
|
/// glVertex3f(...);
|
||||||
|
/// ...
|
||||||
|
/// glEnd();
|
||||||
|
///
|
||||||
|
/// // Draw text on top of the 3D object
|
||||||
|
/// window.pushGLStates();
|
||||||
|
/// window.draw(text);
|
||||||
|
/// window.popGLStates();
|
||||||
|
///
|
||||||
|
/// // Finally, display the rendered frame on screen
|
||||||
|
/// window.display();
|
||||||
|
/// }
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::Window`, `sf::RenderTarget`, `sf::RenderTexture`, `sf::View`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,357 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Graphics/Color.hpp>
|
||||||
|
#include <SFML/Graphics/Drawable.hpp>
|
||||||
|
#include <SFML/Graphics/PrimitiveType.hpp>
|
||||||
|
#include <SFML/Graphics/Rect.hpp>
|
||||||
|
#include <SFML/Graphics/RenderStates.hpp>
|
||||||
|
#include <SFML/Graphics/Transformable.hpp>
|
||||||
|
#include <SFML/Graphics/VertexArray.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/Vector2.hpp>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class Texture;
|
||||||
|
class RenderTarget;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Base class for textured shapes with outline
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_GRAPHICS_API Shape : public Drawable, public Transformable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Change the source texture of the shape
|
||||||
|
///
|
||||||
|
/// The `texture` argument refers to a texture that must
|
||||||
|
/// exist as long as the shape uses it. Indeed, the shape
|
||||||
|
/// doesn't store its own copy of the texture, but rather keeps
|
||||||
|
/// a pointer to the one that you passed to this function.
|
||||||
|
/// If the source texture is destroyed and the shape tries to
|
||||||
|
/// use it, the behavior is undefined.
|
||||||
|
/// `texture` can be a null pointer to disable texturing.
|
||||||
|
/// If `resetRect` is `true`, the `TextureRect` property of
|
||||||
|
/// the shape is automatically adjusted to the size of the new
|
||||||
|
/// texture. If it is `false`, the texture rect is left unchanged.
|
||||||
|
///
|
||||||
|
/// \param texture New texture
|
||||||
|
/// \param resetRect Should the texture rect be reset to the size of the new texture?
|
||||||
|
///
|
||||||
|
/// \see `getTexture`, `setTextureRect`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setTexture(const Texture* texture, bool resetRect = false);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the sub-rectangle of the texture that the shape will display
|
||||||
|
///
|
||||||
|
/// The texture rect is useful when you don't want to display
|
||||||
|
/// the whole texture, but rather a part of it.
|
||||||
|
/// By default, the texture rect covers the entire texture.
|
||||||
|
///
|
||||||
|
/// \param rect Rectangle defining the region of the texture to display
|
||||||
|
///
|
||||||
|
/// \see `getTextureRect`, `setTexture`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setTextureRect(const IntRect& rect);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the fill color of the shape
|
||||||
|
///
|
||||||
|
/// This color is modulated (multiplied) with the shape's
|
||||||
|
/// texture if any. It can be used to colorize the shape,
|
||||||
|
/// or change its global opacity.
|
||||||
|
/// You can use `sf::Color::Transparent` to make the inside of
|
||||||
|
/// the shape transparent, and have the outline alone.
|
||||||
|
/// By default, the shape's fill color is opaque white.
|
||||||
|
///
|
||||||
|
/// \param color New color of the shape
|
||||||
|
///
|
||||||
|
/// \see `getFillColor`, `setOutlineColor`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setFillColor(Color color);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the outline color of the shape
|
||||||
|
///
|
||||||
|
/// By default, the shape's outline color is opaque white.
|
||||||
|
///
|
||||||
|
/// \param color New outline color of the shape
|
||||||
|
///
|
||||||
|
/// \see `getOutlineColor`, `setFillColor`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setOutlineColor(Color color);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the thickness of the shape's outline
|
||||||
|
///
|
||||||
|
/// Note that negative values are allowed (so that the outline
|
||||||
|
/// expands towards the center of the shape), and using zero
|
||||||
|
/// disables the outline.
|
||||||
|
/// By default, the outline thickness is 0.
|
||||||
|
///
|
||||||
|
/// \param thickness New outline thickness
|
||||||
|
///
|
||||||
|
/// \see `getOutlineThickness`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setOutlineThickness(float thickness);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the source texture of the shape
|
||||||
|
///
|
||||||
|
/// If the shape has no source texture, a `nullptr` is returned.
|
||||||
|
/// The returned pointer is const, which means that you can't
|
||||||
|
/// modify the texture when you retrieve it with this function.
|
||||||
|
///
|
||||||
|
/// \return Pointer to the shape's texture
|
||||||
|
///
|
||||||
|
/// \see `setTexture`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const Texture* getTexture() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the sub-rectangle of the texture displayed by the shape
|
||||||
|
///
|
||||||
|
/// \return Texture rectangle of the shape
|
||||||
|
///
|
||||||
|
/// \see `setTextureRect`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const IntRect& getTextureRect() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the fill color of the shape
|
||||||
|
///
|
||||||
|
/// \return Fill color of the shape
|
||||||
|
///
|
||||||
|
/// \see `setFillColor`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Color getFillColor() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the outline color of the shape
|
||||||
|
///
|
||||||
|
/// \return Outline color of the shape
|
||||||
|
///
|
||||||
|
/// \see `setOutlineColor`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Color getOutlineColor() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the outline thickness of the shape
|
||||||
|
///
|
||||||
|
/// \return Outline thickness of the shape
|
||||||
|
///
|
||||||
|
/// \see `setOutlineThickness`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] float getOutlineThickness() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the total number of points of the shape
|
||||||
|
///
|
||||||
|
/// \return Number of points of the shape
|
||||||
|
///
|
||||||
|
/// \see `getPoint`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] virtual std::size_t getPointCount() const = 0;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get a point of the shape
|
||||||
|
///
|
||||||
|
/// The returned point is in local coordinates, that is,
|
||||||
|
/// the shape's transforms (position, rotation, scale) are
|
||||||
|
/// not taken into account.
|
||||||
|
/// The result is undefined if `index` is out of the valid range.
|
||||||
|
///
|
||||||
|
/// \param index Index of the point to get, in range [0 .. getPointCount() - 1]
|
||||||
|
///
|
||||||
|
/// \return `index`-th point of the shape
|
||||||
|
///
|
||||||
|
/// \see `getPointCount`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] virtual Vector2f getPoint(std::size_t index) const = 0;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the geometric center of the shape
|
||||||
|
///
|
||||||
|
/// The returned point is in local coordinates, that is,
|
||||||
|
/// the shape's transforms (position, rotation, scale) are
|
||||||
|
/// not taken into account.
|
||||||
|
///
|
||||||
|
/// \return The geometric center of the shape
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] virtual Vector2f getGeometricCenter() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the local bounding rectangle of the entity
|
||||||
|
///
|
||||||
|
/// The returned rectangle is in local coordinates, which means
|
||||||
|
/// that it ignores the transformations (translation, rotation,
|
||||||
|
/// scale, ...) that are applied to the entity.
|
||||||
|
/// In other words, this function returns the bounds of the
|
||||||
|
/// entity in the entity's coordinate system.
|
||||||
|
///
|
||||||
|
/// \return Local bounding rectangle of the entity
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] FloatRect getLocalBounds() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the global (non-minimal) bounding rectangle of the entity
|
||||||
|
///
|
||||||
|
/// The returned rectangle is in global coordinates, which means
|
||||||
|
/// that it takes into account the transformations (translation,
|
||||||
|
/// rotation, scale, ...) that are applied to the entity.
|
||||||
|
/// In other words, this function returns the bounds of the
|
||||||
|
/// shape in the global 2D world's coordinate system.
|
||||||
|
///
|
||||||
|
/// This function does not necessarily return the _minimal_
|
||||||
|
/// bounding rectangle. It merely ensures that the returned
|
||||||
|
/// rectangle covers all the vertices (but possibly more).
|
||||||
|
/// This allows for a fast approximation of the bounds as a
|
||||||
|
/// first check; you may want to use more precise checks
|
||||||
|
/// on top of that.
|
||||||
|
///
|
||||||
|
/// \return Global bounding rectangle of the entity
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] FloatRect getGlobalBounds() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Recompute the internal geometry of the shape
|
||||||
|
///
|
||||||
|
/// This function must be called by the derived class every time
|
||||||
|
/// the shape's points change (i.e. the result of either
|
||||||
|
/// getPointCount or getPoint is different).
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void update();
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Draw the shape to a render target
|
||||||
|
///
|
||||||
|
/// \param target Render target to draw to
|
||||||
|
/// \param states Current render states
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void draw(RenderTarget& target, RenderStates states) const override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Update the fill vertices' color
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void updateFillColors();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Update the fill vertices' texture coordinates
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void updateTexCoords();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Update the outline vertices' position
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void updateOutline();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Update the outline vertices' color
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void updateOutlineColors();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
const Texture* m_texture{}; //!< Texture of the shape
|
||||||
|
IntRect m_textureRect; //!< Rectangle defining the area of the source texture to display
|
||||||
|
Color m_fillColor{Color::White}; //!< Fill color
|
||||||
|
Color m_outlineColor{Color::White}; //!< Outline color
|
||||||
|
float m_outlineThickness{}; //!< Thickness of the shape's outline
|
||||||
|
VertexArray m_vertices{PrimitiveType::TriangleFan}; //!< Vertex array containing the fill geometry
|
||||||
|
VertexArray m_outlineVertices{PrimitiveType::TriangleStrip}; //!< Vertex array containing the outline geometry
|
||||||
|
FloatRect m_insideBounds; //!< Bounding rectangle of the inside (fill)
|
||||||
|
FloatRect m_bounds; //!< Bounding rectangle of the whole shape (outline + fill)
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::Shape
|
||||||
|
/// \ingroup graphics
|
||||||
|
///
|
||||||
|
/// `sf::Shape` is a drawable class that allows to define and
|
||||||
|
/// display a custom convex shape on a render target.
|
||||||
|
/// It's only an abstract base, it needs to be specialized for
|
||||||
|
/// concrete types of shapes (circle, rectangle, convex polygon,
|
||||||
|
/// star, ...).
|
||||||
|
///
|
||||||
|
/// In addition to the attributes provided by the specialized
|
||||||
|
/// shape classes, a shape always has the following attributes:
|
||||||
|
/// \li a texture
|
||||||
|
/// \li a texture rectangle
|
||||||
|
/// \li a fill color
|
||||||
|
/// \li an outline color
|
||||||
|
/// \li an outline thickness
|
||||||
|
///
|
||||||
|
/// Each feature is optional, and can be disabled easily:
|
||||||
|
/// \li the texture can be null
|
||||||
|
/// \li the fill/outline colors can be `sf::Color::Transparent`
|
||||||
|
/// \li the outline thickness can be zero
|
||||||
|
///
|
||||||
|
/// You can write your own derived shape class, there are only
|
||||||
|
/// two virtual functions to override:
|
||||||
|
/// \li getPointCount must return the number of points of the shape
|
||||||
|
/// \li getPoint must return the points of the shape
|
||||||
|
///
|
||||||
|
/// \see `sf::RectangleShape`, `sf::CircleShape`, `sf::ConvexShape`, `sf::Transformable`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,278 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Graphics/Drawable.hpp>
|
||||||
|
#include <SFML/Graphics/Rect.hpp>
|
||||||
|
#include <SFML/Graphics/RenderStates.hpp>
|
||||||
|
#include <SFML/Graphics/Transformable.hpp>
|
||||||
|
#include <SFML/Graphics/Vertex.hpp>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class Texture;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Drawable representation of a texture, with its
|
||||||
|
/// own transformations, color, etc.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_GRAPHICS_API Sprite : public Drawable, public Transformable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the sprite from a source texture
|
||||||
|
///
|
||||||
|
/// \param texture Source texture
|
||||||
|
///
|
||||||
|
/// \see `setTexture`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit Sprite(const Texture& texture);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Disallow construction from a temporary texture
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit Sprite(const Texture&& texture) = delete;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the sprite from a sub-rectangle of a source texture
|
||||||
|
///
|
||||||
|
/// \param texture Source texture
|
||||||
|
/// \param rectangle Sub-rectangle of the texture to assign to the sprite
|
||||||
|
///
|
||||||
|
/// \see `setTexture`, `setTextureRect`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Sprite(const Texture& texture, const IntRect& rectangle);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Disallow construction from a temporary texture
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Sprite(const Texture&& texture, const IntRect& rectangle) = delete;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Change the source texture of the sprite
|
||||||
|
///
|
||||||
|
/// The `texture` argument refers to a texture that must
|
||||||
|
/// exist as long as the sprite uses it. Indeed, the sprite
|
||||||
|
/// doesn't store its own copy of the texture, but rather keeps
|
||||||
|
/// a pointer to the one that you passed to this function.
|
||||||
|
/// If the source texture is destroyed and the sprite tries to
|
||||||
|
/// use it, the behavior is undefined.
|
||||||
|
/// If `resetRect` is `true`, the `TextureRect` property of
|
||||||
|
/// the sprite is automatically adjusted to the size of the new
|
||||||
|
/// texture. If it is `false`, the texture rect is left unchanged.
|
||||||
|
///
|
||||||
|
/// \param texture New texture
|
||||||
|
/// \param resetRect Should the texture rect be reset to the size of the new texture?
|
||||||
|
///
|
||||||
|
/// \see `getTexture`, `setTextureRect`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setTexture(const Texture& texture, bool resetRect = false);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Disallow setting from a temporary texture
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setTexture(const Texture&& texture, bool resetRect = false) = delete;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the sub-rectangle of the texture that the sprite will display
|
||||||
|
///
|
||||||
|
/// The texture rect is useful when you don't want to display
|
||||||
|
/// the whole texture, but rather a part of it.
|
||||||
|
/// By default, the texture rect covers the entire texture.
|
||||||
|
///
|
||||||
|
/// \param rectangle Rectangle defining the region of the texture to display
|
||||||
|
///
|
||||||
|
/// \see `getTextureRect`, `setTexture`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setTextureRect(const IntRect& rectangle);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the global color of the sprite
|
||||||
|
///
|
||||||
|
/// This color is modulated (multiplied) with the sprite's
|
||||||
|
/// texture. It can be used to colorize the sprite, or change
|
||||||
|
/// its global opacity.
|
||||||
|
/// By default, the sprite's color is opaque white.
|
||||||
|
///
|
||||||
|
/// \param color New color of the sprite
|
||||||
|
///
|
||||||
|
/// \see `getColor`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setColor(Color color);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the source texture of the sprite
|
||||||
|
///
|
||||||
|
/// The returned reference is const, which means that you can't
|
||||||
|
/// modify the texture when you retrieve it with this function.
|
||||||
|
///
|
||||||
|
/// \return Reference to the sprite's texture
|
||||||
|
///
|
||||||
|
/// \see `setTexture`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const Texture& getTexture() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the sub-rectangle of the texture displayed by the sprite
|
||||||
|
///
|
||||||
|
/// \return Texture rectangle of the sprite
|
||||||
|
///
|
||||||
|
/// \see `setTextureRect`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const IntRect& getTextureRect() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the global color of the sprite
|
||||||
|
///
|
||||||
|
/// \return Global color of the sprite
|
||||||
|
///
|
||||||
|
/// \see `setColor`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Color getColor() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the local bounding rectangle of the entity
|
||||||
|
///
|
||||||
|
/// The returned rectangle is in local coordinates, which means
|
||||||
|
/// that it ignores the transformations (translation, rotation,
|
||||||
|
/// scale, ...) that are applied to the entity.
|
||||||
|
/// In other words, this function returns the bounds of the
|
||||||
|
/// entity in the entity's coordinate system.
|
||||||
|
///
|
||||||
|
/// \return Local bounding rectangle of the entity
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] FloatRect getLocalBounds() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the global bounding rectangle of the entity
|
||||||
|
///
|
||||||
|
/// The returned rectangle is in global coordinates, which means
|
||||||
|
/// that it takes into account the transformations (translation,
|
||||||
|
/// rotation, scale, ...) that are applied to the entity.
|
||||||
|
/// In other words, this function returns the bounds of the
|
||||||
|
/// sprite in the global 2D world's coordinate system.
|
||||||
|
///
|
||||||
|
/// \return Global bounding rectangle of the entity
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] FloatRect getGlobalBounds() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Draw the sprite to a render target
|
||||||
|
///
|
||||||
|
/// \param target Render target to draw to
|
||||||
|
/// \param states Current render states
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void draw(RenderTarget& target, RenderStates states) const override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Update the vertices' positions and texture coordinates
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void updateVertices();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::array<Vertex, 4> m_vertices; //!< Vertices defining the sprite's geometry
|
||||||
|
const Texture* m_texture; //!< Texture of the sprite
|
||||||
|
IntRect m_textureRect; //!< Rectangle defining the area of the source texture to display
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::Sprite
|
||||||
|
/// \ingroup graphics
|
||||||
|
///
|
||||||
|
/// `sf::Sprite` is a drawable class that allows to easily display
|
||||||
|
/// a texture (or a part of it) on a render target.
|
||||||
|
///
|
||||||
|
/// It inherits all the functions from `sf::Transformable`:
|
||||||
|
/// position, rotation, scale, origin. It also adds sprite-specific
|
||||||
|
/// properties such as the texture to use, the part of it to display,
|
||||||
|
/// and some convenience functions to change the overall color of the
|
||||||
|
/// sprite, or to get its bounding rectangle.
|
||||||
|
///
|
||||||
|
/// `sf::Sprite` works in combination with the `sf::Texture` class, which
|
||||||
|
/// loads and provides the pixel data of a given texture.
|
||||||
|
///
|
||||||
|
/// The separation of `sf::Sprite` and `sf::Texture` allows more flexibility
|
||||||
|
/// and better performances: indeed a `sf::Texture` is a heavy resource,
|
||||||
|
/// and any operation on it is slow (often too slow for real-time
|
||||||
|
/// applications). On the other side, a `sf::Sprite` is a lightweight
|
||||||
|
/// object which can use the pixel data of a `sf::Texture` and draw
|
||||||
|
/// it with its own transformation/color/blending attributes.
|
||||||
|
///
|
||||||
|
/// It is important to note that the `sf::Sprite` instance doesn't
|
||||||
|
/// copy the texture that it uses, it only keeps a reference to it.
|
||||||
|
/// Thus, a `sf::Texture` must not be destroyed while it is
|
||||||
|
/// used by a `sf::Sprite` (i.e. never write a function that
|
||||||
|
/// uses a local `sf::Texture` instance for creating a sprite).
|
||||||
|
///
|
||||||
|
/// See also the note on coordinates and undistorted rendering in `sf::Transformable`.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// // Load a texture
|
||||||
|
/// const sf::Texture texture("texture.png");
|
||||||
|
///
|
||||||
|
/// // Create a sprite
|
||||||
|
/// sf::Sprite sprite(texture);
|
||||||
|
/// sprite.setTextureRect({{10, 10}, {50, 30}});
|
||||||
|
/// sprite.setColor({255, 255, 255, 200});
|
||||||
|
/// sprite.setPosition({100.f, 25.f});
|
||||||
|
///
|
||||||
|
/// // Draw it
|
||||||
|
/// window.draw(sprite);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::Texture`, `sf::Transformable`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,256 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Export.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////
|
||||||
|
/// \brief Enumeration of the stencil test comparisons that can be performed
|
||||||
|
///
|
||||||
|
/// The comparisons are mapped directly to their OpenGL equivalents,
|
||||||
|
/// specified by `glStencilFunc()`.
|
||||||
|
////////////////////////////////////////////////////////
|
||||||
|
enum class StencilComparison
|
||||||
|
{
|
||||||
|
Never, //!< The stencil test never passes
|
||||||
|
Less, //!< The stencil test passes if the new value is less than the value in the stencil buffer
|
||||||
|
LessEqual, //!< The stencil test passes if the new value is less than or equal to the value in the stencil buffer
|
||||||
|
Greater, //!< The stencil test passes if the new value is greater than the value in the stencil buffer
|
||||||
|
GreaterEqual, //!< The stencil test passes if the new value is greater than or equal to the value in the stencil buffer
|
||||||
|
Equal, //!< The stencil test passes if the new value is strictly equal to the value in the stencil buffer
|
||||||
|
NotEqual, //!< The stencil test passes if the new value is strictly unequal to the value in the stencil buffer
|
||||||
|
Always //!< The stencil test always passes
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////
|
||||||
|
/// \brief Enumeration of the stencil buffer update operations
|
||||||
|
///
|
||||||
|
/// The update operations are mapped directly to their OpenGL equivalents,
|
||||||
|
/// specified by `glStencilOp()`.
|
||||||
|
////////////////////////////////////////////////////////
|
||||||
|
enum class StencilUpdateOperation
|
||||||
|
{
|
||||||
|
Keep, //!< If the stencil test passes, the value in the stencil buffer is not modified
|
||||||
|
Zero, //!< If the stencil test passes, the value in the stencil buffer is set to zero
|
||||||
|
Replace, //!< If the stencil test passes, the value in the stencil buffer is set to the new value
|
||||||
|
Increment, //!< If the stencil test passes, the value in the stencil buffer is incremented and if required clamped
|
||||||
|
Decrement, //!< If the stencil test passes, the value in the stencil buffer is decremented and if required clamped
|
||||||
|
Invert, //!< If the stencil test passes, the value in the stencil buffer is bitwise inverted
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////
|
||||||
|
/// \brief Stencil value type (also used as a mask)
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////
|
||||||
|
struct SFML_GRAPHICS_API StencilValue
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct a stencil value from a signed integer
|
||||||
|
///
|
||||||
|
/// \param theValue Signed integer value to use
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
StencilValue(int theValue);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct a stencil value from an unsigned integer
|
||||||
|
///
|
||||||
|
/// \param theValue Unsigned integer value to use
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
StencilValue(unsigned int theValue);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Disable construction from any other type
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
StencilValue(T) = delete;
|
||||||
|
|
||||||
|
unsigned int value{}; //!< The stored stencil value
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Stencil modes for drawing
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
struct SFML_GRAPHICS_API StencilMode
|
||||||
|
{
|
||||||
|
StencilComparison stencilComparison{StencilComparison::Always}; //!< The comparison we're performing the stencil test with
|
||||||
|
StencilUpdateOperation stencilUpdateOperation{
|
||||||
|
StencilUpdateOperation::Keep}; //!< The update operation to perform if the stencil test passes
|
||||||
|
StencilValue stencilReference{0}; //!< The reference value we're performing the stencil test with
|
||||||
|
StencilValue stencilMask{~0u}; //!< The mask to apply to both the reference value and the value in the stencil buffer
|
||||||
|
bool stencilOnly{}; //!< Whether we should update the color buffer in addition to the stencil buffer
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates StencilMode
|
||||||
|
/// \brief Overload of the `operator==`
|
||||||
|
///
|
||||||
|
/// \param left Left operand
|
||||||
|
/// \param right Right operand
|
||||||
|
///
|
||||||
|
/// \return `true` if stencil modes are equal, `false` if they are different
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] SFML_GRAPHICS_API bool operator==(const StencilMode& left, const StencilMode& right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates StencilMode
|
||||||
|
/// \brief Overload of the `operator!=`
|
||||||
|
///
|
||||||
|
/// \param left Left operand
|
||||||
|
/// \param right Right operand
|
||||||
|
///
|
||||||
|
/// \return `true` if stencil modes are different, `false` if they are equal
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] SFML_GRAPHICS_API bool operator!=(const StencilMode& left, const StencilMode& right);
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::StencilMode
|
||||||
|
/// \ingroup graphics
|
||||||
|
///
|
||||||
|
/// `sf::StencilMode` is a class that controls stencil testing.
|
||||||
|
///
|
||||||
|
/// In addition to drawing to the visible portion of a render target,
|
||||||
|
/// there is the possibility to "draw" to a so-called stencil buffer.
|
||||||
|
/// The stencil buffer is a special non-visible buffer that can contain
|
||||||
|
/// a single value per pixel that is drawn. This can be thought of as a
|
||||||
|
/// fifth value in addition to red, green, blue and alpha values. The maximum
|
||||||
|
/// value that can be represented depends on what is supported by the system.
|
||||||
|
/// Typically support for a 8-bit stencil buffer should always be available.
|
||||||
|
/// This will also have to be requested when creating a render target via
|
||||||
|
/// the `sf::ContextSettings` that is passed during creation. Stencil testing
|
||||||
|
/// will not work if there is no stencil buffer available in the target
|
||||||
|
/// that is being drawn to.
|
||||||
|
///
|
||||||
|
/// Initially, just like with the visible color buffer, the stencil value of
|
||||||
|
/// each pixel is set to an undefined value. Calling `sf::RenderTarget::clear`
|
||||||
|
/// will set each pixel's stencil value to 0. `sf::RenderTarget::clear` can be
|
||||||
|
/// called at any time to reset the stencil values back to 0.
|
||||||
|
///
|
||||||
|
/// When drawing an object, before each pixel of the color buffer is updated
|
||||||
|
/// with its new color value, the stencil test is performed. During this test
|
||||||
|
/// 2 values are compared with each other: the reference value that is passed
|
||||||
|
/// via `sf::StencilMode` and the value that is currently in the stencil buffer.
|
||||||
|
/// The arithmetic comparison that is performed on the 2 values can also be
|
||||||
|
/// controlled via `sf::StencilMode`. Depending on whether the test passes i.e.
|
||||||
|
/// the comparison yields `true`, the color buffer is updated with its new RGBA
|
||||||
|
/// value and if set in `sf::StencilMode` the stencil buffer is updated
|
||||||
|
/// accordingly. The new stencil value will be used during stencil testing the
|
||||||
|
/// next time the pixel is drawn to.
|
||||||
|
///
|
||||||
|
/// The class is composed of 5 components, each of which has its
|
||||||
|
/// own public member variable:
|
||||||
|
/// \li Stencil Comparison (\ref stencilComparison)
|
||||||
|
/// \li Stencil Update Operation (\ref stencilUpdateOperation)
|
||||||
|
/// \li Stencil Reference Value (\ref stencilReference)
|
||||||
|
/// \li Stencil Mask Value (\ref stencilMask)
|
||||||
|
/// \li Stencil Only Update (\ref stencilOnly)
|
||||||
|
///
|
||||||
|
/// The stencil comparison specifies the comparison that is performed between
|
||||||
|
/// the reference value of the currently active `sf::StencilMode` and the value
|
||||||
|
/// that is currently in the stencil buffer. This comparison determines whether
|
||||||
|
/// the stencil test passes or fails.
|
||||||
|
///
|
||||||
|
/// The stencil update operation specifies how the stencil buffer is updated if
|
||||||
|
/// the stencil test passes. If the stencil test fails, neither the color or
|
||||||
|
/// stencil buffers will be modified. If incrementing or decrementing the
|
||||||
|
/// stencil value, the new value will be clamped to the range from 0 to the
|
||||||
|
/// maximum representable value given the bit width of the stencil buffer
|
||||||
|
/// e.g. 255 if an 8-bit stencil buffer is being used.
|
||||||
|
///
|
||||||
|
/// The reference value is used both during the comparison with the current
|
||||||
|
/// stencil buffer value and as the new value to be written when the operation
|
||||||
|
/// is set to Replace.
|
||||||
|
///
|
||||||
|
/// The mask value is used to mask the bits of both the reference value and
|
||||||
|
/// the value in the stencil buffer during the comparison and when updating.
|
||||||
|
/// The mask can be used to e.g. segment the stencil value bits into separate
|
||||||
|
/// regions that are used for different purposes.
|
||||||
|
///
|
||||||
|
/// In certain situations, it might make sense to only write to the stencil
|
||||||
|
/// buffer and not the color buffer during a draw. The written stencil buffer
|
||||||
|
/// value can then be used in subsequent draws as a masking region.
|
||||||
|
///
|
||||||
|
/// In SFML, a stencil mode can be specified every time you draw a `sf::Drawable`
|
||||||
|
/// object to a render target. It is part of the `sf::RenderStates` compound
|
||||||
|
/// that is passed to the member function `sf::RenderTarget::draw()`.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// // Make sure we create a RenderTarget with a stencil buffer by specifying it via the context settings
|
||||||
|
/// sf::RenderWindow window(sf::VideoMode({250, 200}), "Stencil Window", sf::Style::Default, sf::ContextSettings{0, 8});
|
||||||
|
///
|
||||||
|
/// ...
|
||||||
|
///
|
||||||
|
/// // Left circle
|
||||||
|
/// sf::CircleShape left(100.f);
|
||||||
|
/// left.setFillColor(sf::Color::Green);
|
||||||
|
/// left.setPosition({0, 0});
|
||||||
|
///
|
||||||
|
/// // Middle circle
|
||||||
|
/// sf::CircleShape middle(100.f);
|
||||||
|
/// middle.setFillColor(sf::Color::Yellow);
|
||||||
|
/// middle.setPosition({25, 0});
|
||||||
|
///
|
||||||
|
/// // Right circle
|
||||||
|
/// sf::CircleShape right(100.f);
|
||||||
|
/// right.setFillColor(sf::Color::Red);
|
||||||
|
/// right.setPosition({50, 0});
|
||||||
|
///
|
||||||
|
/// ...
|
||||||
|
///
|
||||||
|
/// // Clear the stencil buffer to 0 at the start of every frame
|
||||||
|
/// window.clear(sf::Color::Black, 0);
|
||||||
|
///
|
||||||
|
/// ...
|
||||||
|
///
|
||||||
|
/// // Draw the middle circle in a stencil-only pass and write the value 1
|
||||||
|
/// // to the stencil buffer for every pixel the circle would have affected
|
||||||
|
/// window.draw(middle, sf::StencilMode{sf::StencilComparison::Always, sf::StencilUpdateOperation::Replace, 1, 0xFF, true});
|
||||||
|
///
|
||||||
|
/// // Draw the left and right circles
|
||||||
|
/// // Only allow rendering to pixels whose stencil value is not
|
||||||
|
/// // equal to 1 i.e. weren't written when drawing the middle circle
|
||||||
|
/// window.draw(left, sf::StencilMode{sf::StencilComparison::NotEqual, sf::StencilUpdateOperation::Keep, 1, 0xFF, false});
|
||||||
|
/// window.draw(right, sf::StencilMode{sf::StencilComparison::NotEqual, sf::StencilUpdateOperation::Keep, 1, 0xFF, false});
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::RenderStates`, `sf::RenderTarget`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,486 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Graphics/Color.hpp>
|
||||||
|
#include <SFML/Graphics/Drawable.hpp>
|
||||||
|
#include <SFML/Graphics/PrimitiveType.hpp>
|
||||||
|
#include <SFML/Graphics/Rect.hpp>
|
||||||
|
#include <SFML/Graphics/RenderStates.hpp>
|
||||||
|
#include <SFML/Graphics/Transformable.hpp>
|
||||||
|
#include <SFML/Graphics/VertexArray.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/String.hpp>
|
||||||
|
#include <SFML/System/Vector2.hpp>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class Font;
|
||||||
|
class RenderTarget;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Graphical text that can be drawn to a render target
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_GRAPHICS_API Text : public Drawable, public Transformable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Enumeration of the string drawing styles
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
enum Style
|
||||||
|
{
|
||||||
|
Regular = 0, //!< Regular characters, no style
|
||||||
|
Bold = 1 << 0, //!< Bold characters
|
||||||
|
Italic = 1 << 1, //!< Italic characters
|
||||||
|
Underlined = 1 << 2, //!< Underlined characters
|
||||||
|
StrikeThrough = 1 << 3 //!< Strike through characters
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the text from a string, font and size
|
||||||
|
///
|
||||||
|
/// Note that if the used font is a bitmap font, it is not
|
||||||
|
/// scalable, thus not all requested sizes will be available
|
||||||
|
/// to use. This needs to be taken into consideration when
|
||||||
|
/// setting the character size. If you need to display text
|
||||||
|
/// of a certain size, make sure the corresponding bitmap
|
||||||
|
/// font that supports that size is used.
|
||||||
|
///
|
||||||
|
/// \param string Text assigned to the string
|
||||||
|
/// \param font Font used to draw the string
|
||||||
|
/// \param characterSize Base size of characters, in pixels
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Text(const Font& font, String string = "", unsigned int characterSize = 30);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Disallow construction from a temporary font
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Text(const Font&& font, String string = "", unsigned int characterSize = 30) = delete;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the text's string
|
||||||
|
///
|
||||||
|
/// The `string` argument is a `sf::String`, which can
|
||||||
|
/// automatically be constructed from standard string types.
|
||||||
|
/// So, the following calls are all valid:
|
||||||
|
/// \code
|
||||||
|
/// text.setString("hello");
|
||||||
|
/// text.setString(L"hello");
|
||||||
|
/// text.setString(std::string("hello"));
|
||||||
|
/// text.setString(std::wstring(L"hello"));
|
||||||
|
/// \endcode
|
||||||
|
/// A text's string is empty by default.
|
||||||
|
///
|
||||||
|
/// \param string New string
|
||||||
|
///
|
||||||
|
/// \see `getString`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setString(const String& string);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the text's font
|
||||||
|
///
|
||||||
|
/// The `font` argument refers to a font that must
|
||||||
|
/// exist as long as the text uses it. Indeed, the text
|
||||||
|
/// doesn't store its own copy of the font, but rather keeps
|
||||||
|
/// a pointer to the one that you passed to this function.
|
||||||
|
/// If the font is destroyed and the text tries to
|
||||||
|
/// use it, the behavior is undefined.
|
||||||
|
///
|
||||||
|
/// \param font New font
|
||||||
|
///
|
||||||
|
/// \see `getFont`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setFont(const Font& font);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Disallow setting from a temporary font
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setFont(const Font&& font) = delete;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the character size
|
||||||
|
///
|
||||||
|
/// The default size is 30.
|
||||||
|
///
|
||||||
|
/// Note that if the used font is a bitmap font, it is not
|
||||||
|
/// scalable, thus not all requested sizes will be available
|
||||||
|
/// to use. This needs to be taken into consideration when
|
||||||
|
/// setting the character size. If you need to display text
|
||||||
|
/// of a certain size, make sure the corresponding bitmap
|
||||||
|
/// font that supports that size is used.
|
||||||
|
///
|
||||||
|
/// \param size New character size, in pixels
|
||||||
|
///
|
||||||
|
/// \see `getCharacterSize`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setCharacterSize(unsigned int size);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the line spacing factor
|
||||||
|
///
|
||||||
|
/// The default spacing between lines is defined by the font.
|
||||||
|
/// This method enables you to set a factor for the spacing
|
||||||
|
/// between lines. By default the line spacing factor is 1.
|
||||||
|
///
|
||||||
|
/// \param spacingFactor New line spacing factor
|
||||||
|
///
|
||||||
|
/// \see `getLineSpacing`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setLineSpacing(float spacingFactor);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the letter spacing factor
|
||||||
|
///
|
||||||
|
/// The default spacing between letters is defined by the font.
|
||||||
|
/// This factor doesn't directly apply to the existing
|
||||||
|
/// spacing between each character, it rather adds a fixed
|
||||||
|
/// space between them which is calculated from the font
|
||||||
|
/// metrics and the character size.
|
||||||
|
/// Note that factors below 1 (including negative numbers) bring
|
||||||
|
/// characters closer to each other.
|
||||||
|
/// By default the letter spacing factor is 1.
|
||||||
|
///
|
||||||
|
/// \param spacingFactor New letter spacing factor
|
||||||
|
///
|
||||||
|
/// \see `getLetterSpacing`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setLetterSpacing(float spacingFactor);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the text's style
|
||||||
|
///
|
||||||
|
/// You can pass a combination of one or more styles, for
|
||||||
|
/// example `sf::Text::Bold | sf::Text::Italic`.
|
||||||
|
/// The default style is `sf::Text::Regular`.
|
||||||
|
///
|
||||||
|
/// \param style New style
|
||||||
|
///
|
||||||
|
/// \see `getStyle`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setStyle(std::uint32_t style);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the fill color of the text
|
||||||
|
///
|
||||||
|
/// By default, the text's fill color is opaque white.
|
||||||
|
/// Setting the fill color to a transparent color with an outline
|
||||||
|
/// will cause the outline to be displayed in the fill area of the text.
|
||||||
|
///
|
||||||
|
/// \param color New fill color of the text
|
||||||
|
///
|
||||||
|
/// \see `getFillColor`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setFillColor(Color color);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the outline color of the text
|
||||||
|
///
|
||||||
|
/// By default, the text's outline color is opaque black.
|
||||||
|
///
|
||||||
|
/// \param color New outline color of the text
|
||||||
|
///
|
||||||
|
/// \see `getOutlineColor`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setOutlineColor(Color color);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the thickness of the text's outline
|
||||||
|
///
|
||||||
|
/// By default, the outline thickness is 0.
|
||||||
|
///
|
||||||
|
/// Be aware that using a negative value for the outline
|
||||||
|
/// thickness will cause distorted rendering.
|
||||||
|
///
|
||||||
|
/// \param thickness New outline thickness, in pixels
|
||||||
|
///
|
||||||
|
/// \see `getOutlineThickness`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setOutlineThickness(float thickness);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the text's string
|
||||||
|
///
|
||||||
|
/// The returned string is a `sf::String`, which can automatically
|
||||||
|
/// be converted to standard string types. So, the following
|
||||||
|
/// lines of code are all valid:
|
||||||
|
/// \code
|
||||||
|
/// sf::String s1 = text.getString();
|
||||||
|
/// std::string s2 = text.getString();
|
||||||
|
/// std::wstring s3 = text.getString();
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \return Text's string
|
||||||
|
///
|
||||||
|
/// \see `setString`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const String& getString() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the text's font
|
||||||
|
///
|
||||||
|
/// The returned reference is const, which means that you
|
||||||
|
/// cannot modify the font when you get it from this function.
|
||||||
|
///
|
||||||
|
/// \return Reference to the text's font
|
||||||
|
///
|
||||||
|
/// \see `setFont`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const Font& getFont() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the character size
|
||||||
|
///
|
||||||
|
/// \return Size of the characters, in pixels
|
||||||
|
///
|
||||||
|
/// \see `setCharacterSize`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] unsigned int getCharacterSize() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the size of the letter spacing factor
|
||||||
|
///
|
||||||
|
/// \return Size of the letter spacing factor
|
||||||
|
///
|
||||||
|
/// \see `setLetterSpacing`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] float getLetterSpacing() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the size of the line spacing factor
|
||||||
|
///
|
||||||
|
/// \return Size of the line spacing factor
|
||||||
|
///
|
||||||
|
/// \see `setLineSpacing`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] float getLineSpacing() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the text's style
|
||||||
|
///
|
||||||
|
/// \return Text's style
|
||||||
|
///
|
||||||
|
/// \see `setStyle`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] std::uint32_t getStyle() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the fill color of the text
|
||||||
|
///
|
||||||
|
/// \return Fill color of the text
|
||||||
|
///
|
||||||
|
/// \see `setFillColor`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Color getFillColor() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the outline color of the text
|
||||||
|
///
|
||||||
|
/// \return Outline color of the text
|
||||||
|
///
|
||||||
|
/// \see `setOutlineColor`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Color getOutlineColor() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the outline thickness of the text
|
||||||
|
///
|
||||||
|
/// \return Outline thickness of the text, in pixels
|
||||||
|
///
|
||||||
|
/// \see `setOutlineThickness`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] float getOutlineThickness() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Return the position of the `index`-th character
|
||||||
|
///
|
||||||
|
/// This function computes the visual position of a character
|
||||||
|
/// from its index in the string. The returned position is
|
||||||
|
/// in global coordinates (translation, rotation, scale and
|
||||||
|
/// origin are applied).
|
||||||
|
/// If `index` is out of range, the position of the end of
|
||||||
|
/// the string is returned.
|
||||||
|
///
|
||||||
|
/// \param index Index of the character
|
||||||
|
///
|
||||||
|
/// \return Position of the character
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Vector2f findCharacterPos(std::size_t index) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the local bounding rectangle of the entity
|
||||||
|
///
|
||||||
|
/// The returned rectangle is in local coordinates, which means
|
||||||
|
/// that it ignores the transformations (translation, rotation,
|
||||||
|
/// scale, ...) that are applied to the entity.
|
||||||
|
/// In other words, this function returns the bounds of the
|
||||||
|
/// entity in the entity's coordinate system.
|
||||||
|
///
|
||||||
|
/// \return Local bounding rectangle of the entity
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] FloatRect getLocalBounds() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the global bounding rectangle of the entity
|
||||||
|
///
|
||||||
|
/// The returned rectangle is in global coordinates, which means
|
||||||
|
/// that it takes into account the transformations (translation,
|
||||||
|
/// rotation, scale, ...) that are applied to the entity.
|
||||||
|
/// In other words, this function returns the bounds of the
|
||||||
|
/// text in the global 2D world's coordinate system.
|
||||||
|
///
|
||||||
|
/// \return Global bounding rectangle of the entity
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] FloatRect getGlobalBounds() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Draw the text to a render target
|
||||||
|
///
|
||||||
|
/// \param target Render target to draw to
|
||||||
|
/// \param states Current render states
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void draw(RenderTarget& target, RenderStates states) const override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Make sure the text's geometry is updated
|
||||||
|
///
|
||||||
|
/// All the attributes related to rendering are cached, such
|
||||||
|
/// that the geometry is only updated when necessary.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void ensureGeometryUpdate() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
String m_string; //!< String to display
|
||||||
|
const Font* m_font{}; //!< Font used to display the string
|
||||||
|
unsigned int m_characterSize{30}; //!< Base size of characters, in pixels
|
||||||
|
float m_letterSpacingFactor{1.f}; //!< Spacing factor between letters
|
||||||
|
float m_lineSpacingFactor{1.f}; //!< Spacing factor between lines
|
||||||
|
std::uint32_t m_style{Regular}; //!< Text style (see Style enum)
|
||||||
|
Color m_fillColor{Color::White}; //!< Text fill color
|
||||||
|
Color m_outlineColor{Color::Black}; //!< Text outline color
|
||||||
|
float m_outlineThickness{0.f}; //!< Thickness of the text's outline
|
||||||
|
mutable VertexArray m_vertices{PrimitiveType::Triangles}; //!< Vertex array containing the fill geometry
|
||||||
|
mutable VertexArray m_outlineVertices{PrimitiveType::Triangles}; //!< Vertex array containing the outline geometry
|
||||||
|
mutable FloatRect m_bounds; //!< Bounding rectangle of the text (in local coordinates)
|
||||||
|
mutable bool m_geometryNeedUpdate{}; //!< Does the geometry need to be recomputed?
|
||||||
|
mutable std::uint64_t m_fontTextureId{}; //!< The font texture id
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::Text
|
||||||
|
/// \ingroup graphics
|
||||||
|
///
|
||||||
|
/// `sf::Text` is a drawable class that allows to easily display
|
||||||
|
/// some text with custom style and color on a render target.
|
||||||
|
///
|
||||||
|
/// It inherits all the functions from `sf::Transformable`:
|
||||||
|
/// position, rotation, scale, origin. It also adds text-specific
|
||||||
|
/// properties such as the font to use, the character size,
|
||||||
|
/// the font style (bold, italic, underlined and strike through), the
|
||||||
|
/// text color, the outline thickness, the outline color, the character
|
||||||
|
/// spacing, the line spacing and the text to display of course.
|
||||||
|
/// It also provides convenience functions to calculate the
|
||||||
|
/// graphical size of the text, or to get the global position
|
||||||
|
/// of a given character.
|
||||||
|
///
|
||||||
|
/// `sf::Text` works in combination with the `sf::Font` class, which
|
||||||
|
/// loads and provides the glyphs (visual characters) of a given font.
|
||||||
|
///
|
||||||
|
/// The separation of `sf::Font` and `sf::Text` allows more flexibility
|
||||||
|
/// and better performances: indeed a `sf::Font` is a heavy resource,
|
||||||
|
/// and any operation on it is slow (often too slow for real-time
|
||||||
|
/// applications). On the other side, a `sf::Text` is a lightweight
|
||||||
|
/// object which can combine the glyphs data and metrics of a `sf::Font`
|
||||||
|
/// to display any text on a render target.
|
||||||
|
///
|
||||||
|
/// It is important to note that the `sf::Text` instance doesn't
|
||||||
|
/// copy the font that it uses, it only keeps a reference to it.
|
||||||
|
/// Thus, a `sf::Font` must not be destructed while it is
|
||||||
|
/// used by a `sf::Text` (i.e. never write a function that
|
||||||
|
/// uses a local `sf::Font` instance for creating a text).
|
||||||
|
///
|
||||||
|
/// See also the note on coordinates and undistorted rendering in `sf::Transformable`.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// // Open a font
|
||||||
|
/// const sf::Font font("arial.ttf");
|
||||||
|
///
|
||||||
|
/// // Create a text
|
||||||
|
/// sf::Text text(font, "hello");
|
||||||
|
/// text.setCharacterSize(30);
|
||||||
|
/// text.setStyle(sf::Text::Bold);
|
||||||
|
/// text.setFillColor(sf::Color::Red);
|
||||||
|
///
|
||||||
|
/// // Draw it
|
||||||
|
/// window.draw(text);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::Font`, `sf::Transformable`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,874 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Graphics/CoordinateType.hpp>
|
||||||
|
#include <SFML/Graphics/Rect.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Window/GlResource.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/Vector2.hpp>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class InputStream;
|
||||||
|
class Window;
|
||||||
|
class Image;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Image living on the graphics card that can be used for drawing
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_GRAPHICS_API Texture : GlResource
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// Creates a texture with width 0 and height 0.
|
||||||
|
///
|
||||||
|
/// \see `resize`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Texture();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Destructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
~Texture();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Copy constructor
|
||||||
|
///
|
||||||
|
/// \param copy instance to copy
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Texture(const Texture& copy);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Copy assignment operator
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Texture& operator=(const Texture&);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Texture(Texture&&) noexcept;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move assignment operator
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Texture& operator=(Texture&&) noexcept;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the texture from a file on disk
|
||||||
|
///
|
||||||
|
/// The maximum size for a texture depends on the graphics
|
||||||
|
/// driver and can be retrieved with the getMaximumSize function.
|
||||||
|
///
|
||||||
|
/// \param filename Path of the image file to load
|
||||||
|
/// \param sRgb `true` to enable sRGB conversion, `false` to disable it
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if loading was unsuccessful
|
||||||
|
///
|
||||||
|
/// \see `loadFromFile`, `loadFromMemory`, `loadFromStream`, `loadFromImage`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit Texture(const std::filesystem::path& filename, bool sRgb = false);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the texture from a sub-rectangle of a file on disk
|
||||||
|
///
|
||||||
|
/// The `area` argument can be used to load only a sub-rectangle
|
||||||
|
/// of the whole image. If you want the entire image then leave
|
||||||
|
/// the default value (which is an empty `IntRect`).
|
||||||
|
/// If the `area` rectangle crosses the bounds of the image, it
|
||||||
|
/// is adjusted to fit the image size.
|
||||||
|
///
|
||||||
|
/// The maximum size for a texture depends on the graphics
|
||||||
|
/// driver and can be retrieved with the `getMaximumSize` function.
|
||||||
|
///
|
||||||
|
/// \param filename Path of the image file to load
|
||||||
|
/// \param sRgb `true` to enable sRGB conversion, `false` to disable it
|
||||||
|
/// \param area Area of the image to load
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if loading was unsuccessful
|
||||||
|
///
|
||||||
|
/// \see `loadFromFile`, `loadFromMemory`, `loadFromStream`, `loadFromImage`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Texture(const std::filesystem::path& filename, bool sRgb, const IntRect& area);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the texture from a file in memory
|
||||||
|
///
|
||||||
|
/// The maximum size for a texture depends on the graphics
|
||||||
|
/// driver and can be retrieved with the `getMaximumSize` function.
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the file data in memory
|
||||||
|
/// \param size Size of the data to load, in bytes
|
||||||
|
/// \param sRgb `true` to enable sRGB conversion, `false` to disable it
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if loading was unsuccessful
|
||||||
|
///
|
||||||
|
/// \see `loadFromFile`, `loadFromMemory`, `loadFromStream`, `loadFromImage`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Texture(const void* data, std::size_t size, bool sRgb = false);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the texture from a sub-rectangle of a file in memory
|
||||||
|
///
|
||||||
|
/// The `area` argument can be used to load only a sub-rectangle
|
||||||
|
/// of the whole image. If you want the entire image then leave
|
||||||
|
/// the default value (which is an empty `IntRect`).
|
||||||
|
/// If the `area` rectangle crosses the bounds of the image, it
|
||||||
|
/// is adjusted to fit the image size.
|
||||||
|
///
|
||||||
|
/// The maximum size for a texture depends on the graphics
|
||||||
|
/// driver and can be retrieved with the `getMaximumSize` function.
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the file data in memory
|
||||||
|
/// \param size Size of the data to load, in bytes
|
||||||
|
/// \param sRgb `true` to enable sRGB conversion, `false` to disable it
|
||||||
|
/// \param area Area of the image to load
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if loading was unsuccessful
|
||||||
|
///
|
||||||
|
/// \see `loadFromFile`, `loadFromMemory`, `loadFromStream`, `loadFromImage`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Texture(const void* data, std::size_t size, bool sRgb, const IntRect& area);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the texture from a custom stream
|
||||||
|
///
|
||||||
|
/// The maximum size for a texture depends on the graphics
|
||||||
|
/// driver and can be retrieved with the `getMaximumSize` function.
|
||||||
|
///
|
||||||
|
/// \param stream Source stream to read from
|
||||||
|
/// \param sRgb `true` to enable sRGB conversion, `false` to disable it
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if loading was unsuccessful
|
||||||
|
///
|
||||||
|
/// \see `loadFromFile`, `loadFromMemory`, `loadFromStream`, `loadFromImage`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit Texture(InputStream& stream, bool sRgb = false);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the texture from a sub-rectangle of a custom stream
|
||||||
|
///
|
||||||
|
/// The `area` argument can be used to load only a sub-rectangle
|
||||||
|
/// of the whole image. If you want the entire image then leave
|
||||||
|
/// the default value (which is an empty `IntRect`).
|
||||||
|
/// If the `area` rectangle crosses the bounds of the image, it
|
||||||
|
/// is adjusted to fit the image size.
|
||||||
|
///
|
||||||
|
/// The maximum size for a texture depends on the graphics
|
||||||
|
/// driver and can be retrieved with the `getMaximumSize` function.
|
||||||
|
///
|
||||||
|
/// \param stream Source stream to read from
|
||||||
|
/// \param sRgb `true` to enable sRGB conversion, `false` to disable it
|
||||||
|
/// \param area Area of the image to load
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if loading was unsuccessful
|
||||||
|
///
|
||||||
|
/// \see `loadFromFile`, `loadFromMemory`, `loadFromStream`, `loadFromImage`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Texture(InputStream& stream, bool sRgb, const IntRect& area);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the texture from an image
|
||||||
|
///
|
||||||
|
/// The maximum size for a texture depends on the graphics
|
||||||
|
/// driver and can be retrieved with the `getMaximumSize` function.
|
||||||
|
///
|
||||||
|
/// \param image Image to load into the texture
|
||||||
|
/// \param sRgb `true` to enable sRGB conversion, `false` to disable it
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if loading was unsuccessful
|
||||||
|
///
|
||||||
|
/// \see `loadFromFile`, `loadFromMemory`, `loadFromStream`, `loadFromImage`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit Texture(const Image& image, bool sRgb = false);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the texture from a sub-rectangle of an image
|
||||||
|
///
|
||||||
|
/// The `area` argument is used to load only a sub-rectangle
|
||||||
|
/// of the whole image.
|
||||||
|
/// If the `area` rectangle crosses the bounds of the image, it
|
||||||
|
/// is adjusted to fit the image size.
|
||||||
|
///
|
||||||
|
/// The maximum size for a texture depends on the graphics
|
||||||
|
/// driver and can be retrieved with the `getMaximumSize` function.
|
||||||
|
///
|
||||||
|
/// \param image Image to load into the texture
|
||||||
|
/// \param sRgb `true` to enable sRGB conversion, `false` to disable it
|
||||||
|
/// \param area Area of the image to load
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if loading was unsuccessful
|
||||||
|
///
|
||||||
|
/// \see `loadFromFile`, `loadFromMemory`, `loadFromStream`, `loadFromImage`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Texture(const Image& image, bool sRgb, const IntRect& area);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the texture with a given size
|
||||||
|
///
|
||||||
|
/// \param size Width and height of the texture
|
||||||
|
/// \param sRgb `true` to enable sRGB conversion, `false` to disable it
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception if construction was unsuccessful
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit Texture(Vector2u size, bool sRgb = false);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Resize the texture
|
||||||
|
///
|
||||||
|
/// If this function fails, the texture is left unchanged.
|
||||||
|
///
|
||||||
|
/// \param size Width and height of the texture
|
||||||
|
/// \param sRgb `true` to enable sRGB conversion, `false` to disable it
|
||||||
|
///
|
||||||
|
/// \return `true` if resizing was successful, `false` if it failed
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool resize(Vector2u size, bool sRgb = false);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Load the texture from a file on disk
|
||||||
|
///
|
||||||
|
/// The `area` argument can be used to load only a sub-rectangle
|
||||||
|
/// of the whole image. If you want the entire image then leave
|
||||||
|
/// the default value (which is an empty `IntRect`).
|
||||||
|
/// If the `area` rectangle crosses the bounds of the image, it
|
||||||
|
/// is adjusted to fit the image size.
|
||||||
|
///
|
||||||
|
/// The maximum size for a texture depends on the graphics
|
||||||
|
/// driver and can be retrieved with the `getMaximumSize` function.
|
||||||
|
///
|
||||||
|
/// If this function fails, the texture is left unchanged.
|
||||||
|
///
|
||||||
|
/// \param filename Path of the image file to load
|
||||||
|
/// \param sRgb `true` to enable sRGB conversion, `false` to disable it
|
||||||
|
/// \param area Area of the image to load
|
||||||
|
///
|
||||||
|
/// \return `true` if loading was successful, `false` if it failed
|
||||||
|
///
|
||||||
|
/// \see `loadFromMemory`, `loadFromStream`, `loadFromImage`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool loadFromFile(const std::filesystem::path& filename, bool sRgb = false, const IntRect& area = {});
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Load the texture from a file in memory
|
||||||
|
///
|
||||||
|
/// The `area` argument can be used to load only a sub-rectangle
|
||||||
|
/// of the whole image. If you want the entire image then leave
|
||||||
|
/// the default value (which is an empty `IntRect`).
|
||||||
|
/// If the `area` rectangle crosses the bounds of the image, it
|
||||||
|
/// is adjusted to fit the image size.
|
||||||
|
///
|
||||||
|
/// The maximum size for a texture depends on the graphics
|
||||||
|
/// driver and can be retrieved with the `getMaximumSize` function.
|
||||||
|
///
|
||||||
|
/// If this function fails, the texture is left unchanged.
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the file data in memory
|
||||||
|
/// \param size Size of the data to load, in bytes
|
||||||
|
/// \param sRgb `true` to enable sRGB conversion, `false` to disable it
|
||||||
|
/// \param area Area of the image to load
|
||||||
|
///
|
||||||
|
/// \return `true` if loading was successful, `false` if it failed
|
||||||
|
///
|
||||||
|
/// \see `loadFromFile`, `loadFromStream`, `loadFromImage`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool loadFromMemory(const void* data, std::size_t size, bool sRgb = false, const IntRect& area = {});
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Load the texture from a custom stream
|
||||||
|
///
|
||||||
|
/// The `area` argument can be used to load only a sub-rectangle
|
||||||
|
/// of the whole image. If you want the entire image then leave
|
||||||
|
/// the default value (which is an empty `IntRect`).
|
||||||
|
/// If the `area` rectangle crosses the bounds of the image, it
|
||||||
|
/// is adjusted to fit the image size.
|
||||||
|
///
|
||||||
|
/// The maximum size for a texture depends on the graphics
|
||||||
|
/// driver and can be retrieved with the `getMaximumSize` function.
|
||||||
|
///
|
||||||
|
/// If this function fails, the texture is left unchanged.
|
||||||
|
///
|
||||||
|
/// \param stream Source stream to read from
|
||||||
|
/// \param sRgb `true` to enable sRGB conversion, `false` to disable it
|
||||||
|
/// \param area Area of the image to load
|
||||||
|
///
|
||||||
|
/// \return `true` if loading was successful, `false` if it failed
|
||||||
|
///
|
||||||
|
/// \see `loadFromFile`, `loadFromMemory`, `loadFromImage`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool loadFromStream(InputStream& stream, bool sRgb = false, const IntRect& area = {});
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Load the texture from an image
|
||||||
|
///
|
||||||
|
/// The `area` argument can be used to load only a sub-rectangle
|
||||||
|
/// of the whole image. If you want the entire image then leave
|
||||||
|
/// the default value (which is an empty `IntRect`).
|
||||||
|
/// If the `area` rectangle crosses the bounds of the image, it
|
||||||
|
/// is adjusted to fit the image size.
|
||||||
|
///
|
||||||
|
/// The maximum size for a texture depends on the graphics
|
||||||
|
/// driver and can be retrieved with the `getMaximumSize` function.
|
||||||
|
///
|
||||||
|
/// If this function fails, the texture is left unchanged.
|
||||||
|
///
|
||||||
|
/// \param image Image to load into the texture
|
||||||
|
/// \param sRgb `true` to enable sRGB conversion, `false` to disable it
|
||||||
|
/// \param area Area of the image to load
|
||||||
|
///
|
||||||
|
/// \return `true` if loading was successful, `false` if it failed
|
||||||
|
///
|
||||||
|
/// \see `loadFromFile`, `loadFromMemory`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool loadFromImage(const Image& image, bool sRgb = false, const IntRect& area = {});
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Return the size of the texture
|
||||||
|
///
|
||||||
|
/// \return Size in pixels
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Vector2u getSize() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Copy the texture pixels to an image
|
||||||
|
///
|
||||||
|
/// This function performs a slow operation that downloads
|
||||||
|
/// the texture's pixels from the graphics card and copies
|
||||||
|
/// them to a new image, potentially applying transformations
|
||||||
|
/// to pixels if necessary (texture may be padded or flipped).
|
||||||
|
///
|
||||||
|
/// \return Image containing the texture's pixels
|
||||||
|
///
|
||||||
|
/// \see `loadFromImage`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Image copyToImage() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Update the whole texture from an array of pixels
|
||||||
|
///
|
||||||
|
/// The pixel array is assumed to have the same size as
|
||||||
|
/// the `area` rectangle, and to contain 32-bits RGBA pixels.
|
||||||
|
///
|
||||||
|
/// No additional check is performed on the size of the pixel
|
||||||
|
/// array. Passing invalid arguments will lead to an undefined
|
||||||
|
/// behavior.
|
||||||
|
///
|
||||||
|
/// This function does nothing if `pixels` is `nullptr`
|
||||||
|
/// or if the texture was not previously created.
|
||||||
|
///
|
||||||
|
/// \param pixels Array of pixels to copy to the texture
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void update(const std::uint8_t* pixels);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Update a part of the texture from an array of pixels
|
||||||
|
///
|
||||||
|
/// The size of the pixel array must match the `size` argument,
|
||||||
|
/// and it must contain 32-bits RGBA pixels.
|
||||||
|
///
|
||||||
|
/// No additional check is performed on the size of the pixel
|
||||||
|
/// array or the bounds of the area to update. Passing invalid
|
||||||
|
/// arguments will lead to an undefined behavior.
|
||||||
|
///
|
||||||
|
/// This function does nothing if `pixels` is null or if the
|
||||||
|
/// texture was not previously created.
|
||||||
|
///
|
||||||
|
/// \param pixels Array of pixels to copy to the texture
|
||||||
|
/// \param size Width and height of the pixel region contained in `pixels`
|
||||||
|
/// \param dest Coordinates of the destination position
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void update(const std::uint8_t* pixels, Vector2u size, Vector2u dest);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Update a part of this texture from another texture
|
||||||
|
///
|
||||||
|
/// Although the source texture can be smaller than this texture,
|
||||||
|
/// this function is usually used for updating the whole texture.
|
||||||
|
/// The other overload, which has an additional destination
|
||||||
|
/// argument, is more convenient for updating a sub-area of this
|
||||||
|
/// texture.
|
||||||
|
///
|
||||||
|
/// No additional check is performed on the size of the passed
|
||||||
|
/// texture. Passing a texture bigger than this texture
|
||||||
|
/// will lead to an undefined behavior.
|
||||||
|
///
|
||||||
|
/// This function does nothing if either texture was not
|
||||||
|
/// previously created.
|
||||||
|
///
|
||||||
|
/// \param texture Source texture to copy to this texture
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void update(const Texture& texture);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Update a part of this texture from another texture
|
||||||
|
///
|
||||||
|
/// No additional check is performed on the size of the texture.
|
||||||
|
/// Passing an invalid combination of texture size and destination
|
||||||
|
/// will lead to an undefined behavior.
|
||||||
|
///
|
||||||
|
/// This function does nothing if either texture was not
|
||||||
|
/// previously created.
|
||||||
|
///
|
||||||
|
/// \param texture Source texture to copy to this texture
|
||||||
|
/// \param dest Coordinates of the destination position
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void update(const Texture& texture, Vector2u dest);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Update the texture from an image
|
||||||
|
///
|
||||||
|
/// Although the source image can be smaller than the texture,
|
||||||
|
/// this function is usually used for updating the whole texture.
|
||||||
|
/// The other overload, which has an additional destination
|
||||||
|
/// argument, is more convenient for updating a sub-area of the
|
||||||
|
/// texture.
|
||||||
|
///
|
||||||
|
/// No additional check is performed on the size of the image.
|
||||||
|
/// Passing an image bigger than the texture will lead to an
|
||||||
|
/// undefined behavior.
|
||||||
|
///
|
||||||
|
/// This function does nothing if the texture was not
|
||||||
|
/// previously created.
|
||||||
|
///
|
||||||
|
/// \param image Image to copy to the texture
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void update(const Image& image);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Update a part of the texture from an image
|
||||||
|
///
|
||||||
|
/// No additional check is performed on the size of the image.
|
||||||
|
/// Passing an invalid combination of image size and destination
|
||||||
|
/// will lead to an undefined behavior.
|
||||||
|
///
|
||||||
|
/// This function does nothing if the texture was not
|
||||||
|
/// previously created.
|
||||||
|
///
|
||||||
|
/// \param image Image to copy to the texture
|
||||||
|
/// \param dest Coordinates of the destination position
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void update(const Image& image, Vector2u dest);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Update the texture from the contents of a window
|
||||||
|
///
|
||||||
|
/// Although the source window can be smaller than the texture,
|
||||||
|
/// this function is usually used for updating the whole texture.
|
||||||
|
/// The other overload, which has an additional destination
|
||||||
|
/// argument, is more convenient for updating a sub-area of the
|
||||||
|
/// texture.
|
||||||
|
///
|
||||||
|
/// No additional check is performed on the size of the window.
|
||||||
|
/// Passing a window bigger than the texture will lead to an
|
||||||
|
/// undefined behavior.
|
||||||
|
///
|
||||||
|
/// This function does nothing if either the texture or the window
|
||||||
|
/// was not previously created.
|
||||||
|
///
|
||||||
|
/// \param window Window to copy to the texture
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void update(const Window& window);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Update a part of the texture from the contents of a window
|
||||||
|
///
|
||||||
|
/// No additional check is performed on the size of the window.
|
||||||
|
/// Passing an invalid combination of window size and destination
|
||||||
|
/// will lead to an undefined behavior.
|
||||||
|
///
|
||||||
|
/// This function does nothing if either the texture or the window
|
||||||
|
/// was not previously created.
|
||||||
|
///
|
||||||
|
/// \param window Window to copy to the texture
|
||||||
|
/// \param dest Coordinates of the destination position
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void update(const Window& window, Vector2u dest);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Enable or disable the smooth filter
|
||||||
|
///
|
||||||
|
/// When the filter is activated, the texture appears smoother
|
||||||
|
/// so that pixels are less noticeable. However if you want
|
||||||
|
/// the texture to look exactly the same as its source file,
|
||||||
|
/// you should leave it disabled.
|
||||||
|
/// The smooth filter is disabled by default.
|
||||||
|
///
|
||||||
|
/// \param smooth `true` to enable smoothing, `false` to disable it
|
||||||
|
///
|
||||||
|
/// \see `isSmooth`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setSmooth(bool smooth);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Tell whether the smooth filter is enabled or not
|
||||||
|
///
|
||||||
|
/// \return `true` if smoothing is enabled, `false` if it is disabled
|
||||||
|
///
|
||||||
|
/// \see `setSmooth`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool isSmooth() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Tell whether the texture source is converted from sRGB or not
|
||||||
|
///
|
||||||
|
/// \return `true` if the texture source is converted from sRGB, `false` if not
|
||||||
|
///
|
||||||
|
/// \see `setSrgb`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool isSrgb() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Enable or disable repeating
|
||||||
|
///
|
||||||
|
/// Repeating is involved when using texture coordinates
|
||||||
|
/// outside the texture rectangle [0, 0, width, height].
|
||||||
|
/// In this case, if repeat mode is enabled, the whole texture
|
||||||
|
/// will be repeated as many times as needed to reach the
|
||||||
|
/// coordinate (for example, if the X texture coordinate is
|
||||||
|
/// 3 * width, the texture will be repeated 3 times).
|
||||||
|
/// If repeat mode is disabled, the "extra space" will instead
|
||||||
|
/// be filled with border pixels.
|
||||||
|
/// Warning: on very old graphics cards, white pixels may appear
|
||||||
|
/// when the texture is repeated. With such cards, repeat mode
|
||||||
|
/// can be used reliably only if the texture has power-of-two
|
||||||
|
/// dimensions (such as 256x128).
|
||||||
|
/// Repeating is disabled by default.
|
||||||
|
///
|
||||||
|
/// \param repeated `true` to repeat the texture, `false` to disable repeating
|
||||||
|
///
|
||||||
|
/// \see `isRepeated`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setRepeated(bool repeated);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Tell whether the texture is repeated or not
|
||||||
|
///
|
||||||
|
/// \return `true` if repeat mode is enabled, `false` if it is disabled
|
||||||
|
///
|
||||||
|
/// \see `setRepeated`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool isRepeated() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Generate a mipmap using the current texture data
|
||||||
|
///
|
||||||
|
/// Mipmaps are pre-computed chains of optimized textures. Each
|
||||||
|
/// level of texture in a mipmap is generated by halving each of
|
||||||
|
/// the previous level's dimensions. This is done until the final
|
||||||
|
/// level has the size of 1x1. The textures generated in this process may
|
||||||
|
/// make use of more advanced filters which might improve the visual quality
|
||||||
|
/// of textures when they are applied to objects much smaller than they are.
|
||||||
|
/// This is known as minification. Because fewer texels (texture elements)
|
||||||
|
/// have to be sampled from when heavily minified, usage of mipmaps
|
||||||
|
/// can also improve rendering performance in certain scenarios.
|
||||||
|
///
|
||||||
|
/// Mipmap generation relies on the necessary OpenGL extension being
|
||||||
|
/// available. If it is unavailable or generation fails due to another
|
||||||
|
/// reason, this function will return `false`. Mipmap data is only valid from
|
||||||
|
/// the time it is generated until the next time the base level image is
|
||||||
|
/// modified, at which point this function will have to be called again to
|
||||||
|
/// regenerate it.
|
||||||
|
///
|
||||||
|
/// \return `true` if mipmap generation was successful, `false` if unsuccessful
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool generateMipmap();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Swap the contents of this texture with those of another
|
||||||
|
///
|
||||||
|
/// \param right Instance to swap with
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void swap(Texture& right) noexcept;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the underlying OpenGL handle of the texture.
|
||||||
|
///
|
||||||
|
/// You shouldn't need to use this function, unless you have
|
||||||
|
/// very specific stuff to implement that SFML doesn't support,
|
||||||
|
/// or implement a temporary workaround until a bug is fixed.
|
||||||
|
///
|
||||||
|
/// \return OpenGL handle of the texture or 0 if not yet created
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] unsigned int getNativeHandle() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Bind a texture for rendering
|
||||||
|
///
|
||||||
|
/// This function is not part of the graphics API, it mustn't be
|
||||||
|
/// used when drawing SFML entities. It must be used only if you
|
||||||
|
/// mix `sf::Texture` with OpenGL code.
|
||||||
|
///
|
||||||
|
/// \code
|
||||||
|
/// sf::Texture t1, t2;
|
||||||
|
/// ...
|
||||||
|
/// sf::Texture::bind(&t1);
|
||||||
|
/// // draw OpenGL stuff that use t1...
|
||||||
|
/// sf::Texture::bind(&t2);
|
||||||
|
/// // draw OpenGL stuff that use t2...
|
||||||
|
/// sf::Texture::bind(nullptr);
|
||||||
|
/// // draw OpenGL stuff that use no texture...
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// The `coordinateType` argument controls how texture
|
||||||
|
/// coordinates will be interpreted. If Normalized (the default), they
|
||||||
|
/// must be in range [0 .. 1], which is the default way of handling
|
||||||
|
/// texture coordinates with OpenGL. If Pixels, they must be given
|
||||||
|
/// in pixels (range [0 .. size]). This mode is used internally by
|
||||||
|
/// the graphics classes of SFML, it makes the definition of texture
|
||||||
|
/// coordinates more intuitive for the high-level API, users don't need
|
||||||
|
/// to compute normalized values.
|
||||||
|
///
|
||||||
|
/// \param texture Pointer to the texture to bind, can be null to use no texture
|
||||||
|
/// \param coordinateType Type of texture coordinates to use
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
static void bind(const Texture* texture, CoordinateType coordinateType = CoordinateType::Normalized);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the maximum texture size allowed
|
||||||
|
///
|
||||||
|
/// This maximum size is defined by the graphics driver.
|
||||||
|
/// You can expect a value of 512 pixels for low-end graphics
|
||||||
|
/// card, and up to 8192 pixels or more for newer hardware.
|
||||||
|
///
|
||||||
|
/// \return Maximum size allowed for textures, in pixels
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] static unsigned int getMaximumSize();
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class Text;
|
||||||
|
friend class RenderTexture;
|
||||||
|
friend class RenderTarget;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get a valid image size according to hardware support
|
||||||
|
///
|
||||||
|
/// This function checks whether the graphics driver supports
|
||||||
|
/// non power of two sizes or not, and adjusts the size
|
||||||
|
/// accordingly.
|
||||||
|
/// The returned size is greater than or equal to the original size.
|
||||||
|
///
|
||||||
|
/// \param size size to convert
|
||||||
|
///
|
||||||
|
/// \return Valid nearest size (greater than or equal to specified size)
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] static unsigned int getValidSize(unsigned int size);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Invalidate the mipmap if one exists
|
||||||
|
///
|
||||||
|
/// This also resets the texture's minifying function.
|
||||||
|
/// This function is mainly for internal use by RenderTexture.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void invalidateMipmap();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Vector2u m_size; //!< Public texture size
|
||||||
|
Vector2u m_actualSize; //!< Actual texture size (can be greater than public size because of padding)
|
||||||
|
unsigned int m_texture{}; //!< Internal texture identifier
|
||||||
|
bool m_isSmooth{}; //!< Status of the smooth filter
|
||||||
|
bool m_sRgb{}; //!< Should the texture source be converted from sRGB?
|
||||||
|
bool m_isRepeated{}; //!< Is the texture in repeat mode?
|
||||||
|
mutable bool m_pixelsFlipped{}; //!< To work around the inconsistency in Y orientation
|
||||||
|
bool m_fboAttachment{}; //!< Is this texture owned by a framebuffer object?
|
||||||
|
bool m_hasMipmap{}; //!< Has the mipmap been generated?
|
||||||
|
std::uint64_t m_cacheId; //!< Unique number that identifies the texture to the render target's cache
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Swap the contents of one texture with those of another
|
||||||
|
///
|
||||||
|
/// \param left First instance to swap
|
||||||
|
/// \param right Second instance to swap
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_GRAPHICS_API void swap(Texture& left, Texture& right) noexcept;
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::Texture
|
||||||
|
/// \ingroup graphics
|
||||||
|
///
|
||||||
|
/// `sf::Texture` stores pixels that can be drawn, with a sprite
|
||||||
|
/// for example. A texture lives in the graphics card memory,
|
||||||
|
/// therefore it is very fast to draw a texture to a render target,
|
||||||
|
/// or copy a render target to a texture (the graphics card can
|
||||||
|
/// access both directly).
|
||||||
|
///
|
||||||
|
/// Being stored in the graphics card memory has some drawbacks.
|
||||||
|
/// A texture cannot be manipulated as freely as a `sf::Image`,
|
||||||
|
/// you need to prepare the pixels first and then upload them
|
||||||
|
/// to the texture in a single operation (see `Texture::update`).
|
||||||
|
///
|
||||||
|
/// `sf::Texture` makes it easy to convert from/to `sf::Image`, but
|
||||||
|
/// keep in mind that these calls require transfers between
|
||||||
|
/// the graphics card and the central memory, therefore they are
|
||||||
|
/// slow operations.
|
||||||
|
///
|
||||||
|
/// A texture can be loaded from an image, but also directly
|
||||||
|
/// from a file/memory/stream. The necessary shortcuts are defined
|
||||||
|
/// so that you don't need an image first for the most common cases.
|
||||||
|
/// However, if you want to perform some modifications on the pixels
|
||||||
|
/// before creating the final texture, you can load your file to a
|
||||||
|
/// `sf::Image`, do whatever you need with the pixels, and then call
|
||||||
|
/// `Texture(const Image&)`.
|
||||||
|
///
|
||||||
|
/// Since they live in the graphics card memory, the pixels of a texture
|
||||||
|
/// cannot be accessed without a slow copy first. And they cannot be
|
||||||
|
/// accessed individually. Therefore, if you need to read the texture's
|
||||||
|
/// pixels (like for pixel-perfect collisions), it is recommended to
|
||||||
|
/// store the collision information separately, for example in an array
|
||||||
|
/// of booleans.
|
||||||
|
///
|
||||||
|
/// Like `sf::Image`, `sf::Texture` can handle a unique internal
|
||||||
|
/// representation of pixels, which is RGBA 32 bits. This means
|
||||||
|
/// that a pixel must be composed of 8 bit red, green, blue and
|
||||||
|
/// alpha channels -- just like a `sf::Color`.
|
||||||
|
///
|
||||||
|
/// When providing texture data from an image file or memory, it can
|
||||||
|
/// either be stored in a linear color space or an sRGB color space.
|
||||||
|
/// Most digital images account for gamma correction already, so they
|
||||||
|
/// would need to be "uncorrected" back to linear color space before
|
||||||
|
/// being processed by the hardware. The hardware can automatically
|
||||||
|
/// convert it from the sRGB color space to a linear color space when
|
||||||
|
/// it gets sampled. When the rendered image gets output to the final
|
||||||
|
/// framebuffer, it gets converted back to sRGB.
|
||||||
|
///
|
||||||
|
/// This option is only useful in conjunction with an sRGB capable
|
||||||
|
/// framebuffer. This can be requested during window creation.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// // This example shows the most common use of sf::Texture:
|
||||||
|
/// // drawing a sprite
|
||||||
|
///
|
||||||
|
/// // Load a texture from a file
|
||||||
|
/// const sf::Texture texture("texture.png");
|
||||||
|
///
|
||||||
|
/// // Assign it to a sprite
|
||||||
|
/// sf::Sprite sprite(texture);
|
||||||
|
///
|
||||||
|
/// // Draw the textured sprite
|
||||||
|
/// window.draw(sprite);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \code
|
||||||
|
/// // This example shows another common use of sf::Texture:
|
||||||
|
/// // streaming real-time data, like video frames
|
||||||
|
///
|
||||||
|
/// // Create an empty texture
|
||||||
|
/// sf::Texture texture({640, 480});
|
||||||
|
///
|
||||||
|
/// // Create a sprite that will display the texture
|
||||||
|
/// sf::Sprite sprite(texture);
|
||||||
|
///
|
||||||
|
/// while (...) // the main loop
|
||||||
|
/// {
|
||||||
|
/// ...
|
||||||
|
///
|
||||||
|
/// // update the texture
|
||||||
|
/// std::uint8_t* pixels = ...; // get a fresh chunk of pixels (the next frame of a movie, for example)
|
||||||
|
/// texture.update(pixels);
|
||||||
|
///
|
||||||
|
/// // draw it
|
||||||
|
/// window.draw(sprite);
|
||||||
|
///
|
||||||
|
/// ...
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// Like `sf::Shader` that can be used as a raw OpenGL shader,
|
||||||
|
/// `sf::Texture` can also be used directly as a raw texture for
|
||||||
|
/// custom OpenGL geometry.
|
||||||
|
/// \code
|
||||||
|
/// sf::Texture::bind(&texture);
|
||||||
|
/// ... render OpenGL geometry ...
|
||||||
|
/// sf::Texture::bind(nullptr);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::Sprite`, `sf::Image`, `sf::RenderTexture`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,393 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Graphics/Rect.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/Vector2.hpp>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class Angle;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief 3x3 transform matrix
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class Transform
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// Creates an identity transform (a transform that does nothing).
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Transform() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct a transform from a 3x3 matrix
|
||||||
|
///
|
||||||
|
/// \param a00 Element (0, 0) of the matrix
|
||||||
|
/// \param a01 Element (0, 1) of the matrix
|
||||||
|
/// \param a02 Element (0, 2) of the matrix
|
||||||
|
/// \param a10 Element (1, 0) of the matrix
|
||||||
|
/// \param a11 Element (1, 1) of the matrix
|
||||||
|
/// \param a12 Element (1, 2) of the matrix
|
||||||
|
/// \param a20 Element (2, 0) of the matrix
|
||||||
|
/// \param a21 Element (2, 1) of the matrix
|
||||||
|
/// \param a22 Element (2, 2) of the matrix
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Transform(float a00, float a01, float a02, float a10, float a11, float a12, float a20, float a21, float a22);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Return the transform as a 4x4 matrix
|
||||||
|
///
|
||||||
|
/// This function returns a pointer to an array of 16 floats
|
||||||
|
/// containing the transform elements as a 4x4 matrix, which
|
||||||
|
/// is directly compatible with OpenGL functions.
|
||||||
|
///
|
||||||
|
/// \code
|
||||||
|
/// sf::Transform transform = ...;
|
||||||
|
/// glLoadMatrixf(transform.getMatrix());
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \return Pointer to a 4x4 matrix
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr const float* getMatrix() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Return the inverse of the transform
|
||||||
|
///
|
||||||
|
/// If the inverse cannot be computed, an identity transform
|
||||||
|
/// is returned.
|
||||||
|
///
|
||||||
|
/// \return A new transform which is the inverse of self
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr Transform getInverse() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Transform a 2D point
|
||||||
|
///
|
||||||
|
/// These two statements are equivalent:
|
||||||
|
/// \code
|
||||||
|
/// sf::Vector2f transformedPoint = matrix.transformPoint(point);
|
||||||
|
/// sf::Vector2f transformedPoint = matrix * point;
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \param point Point to transform
|
||||||
|
///
|
||||||
|
/// \return Transformed point
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr Vector2f transformPoint(Vector2f point) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Transform a rectangle
|
||||||
|
///
|
||||||
|
/// Since SFML doesn't provide support for oriented rectangles,
|
||||||
|
/// the result of this function is always an axis-aligned
|
||||||
|
/// rectangle. Which means that if the transform contains a
|
||||||
|
/// rotation, the bounding rectangle of the transformed rectangle
|
||||||
|
/// is returned.
|
||||||
|
///
|
||||||
|
/// \param rectangle Rectangle to transform
|
||||||
|
///
|
||||||
|
/// \return Transformed rectangle
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr FloatRect transformRect(const FloatRect& rectangle) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Combine the current transform with another one
|
||||||
|
///
|
||||||
|
/// The result is a transform that is equivalent to applying
|
||||||
|
/// `transform` followed by `*this`. Mathematically, it is
|
||||||
|
/// equivalent to a matrix multiplication `(*this) * transform`.
|
||||||
|
///
|
||||||
|
/// These two statements are equivalent:
|
||||||
|
/// \code
|
||||||
|
/// left.combine(right);
|
||||||
|
/// left *= right;
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \param transform Transform to combine with this transform
|
||||||
|
///
|
||||||
|
/// \return Reference to `*this`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Transform& combine(const Transform& transform);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Combine the current transform with a translation
|
||||||
|
///
|
||||||
|
/// This function returns a reference to `*this`, so that calls
|
||||||
|
/// can be chained.
|
||||||
|
/// \code
|
||||||
|
/// sf::Transform transform;
|
||||||
|
/// transform.translate(sf::Vector2f(100, 200)).rotate(sf::degrees(45));
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \param offset Translation offset to apply
|
||||||
|
///
|
||||||
|
/// \return Reference to `*this`
|
||||||
|
///
|
||||||
|
/// \see `rotate`, `scale`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Transform& translate(Vector2f offset);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Combine the current transform with a rotation
|
||||||
|
///
|
||||||
|
/// This function returns a reference to `*this`, so that calls
|
||||||
|
/// can be chained.
|
||||||
|
/// \code
|
||||||
|
/// sf::Transform transform;
|
||||||
|
/// transform.rotate(sf::degrees(90)).translate(50, 20);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \param angle Rotation angle
|
||||||
|
///
|
||||||
|
/// \return Reference to `*this`
|
||||||
|
///
|
||||||
|
/// \see `translate`, `scale`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_GRAPHICS_API Transform& rotate(Angle angle);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Combine the current transform with a rotation
|
||||||
|
///
|
||||||
|
/// The center of rotation is provided for convenience as a second
|
||||||
|
/// argument, so that you can build rotations around arbitrary points
|
||||||
|
/// more easily (and efficiently) than the usual
|
||||||
|
/// `translate(-center).rotate(angle).translate(center)`.
|
||||||
|
///
|
||||||
|
/// This function returns a reference to `*this`, so that calls
|
||||||
|
/// can be chained.
|
||||||
|
/// \code
|
||||||
|
/// sf::Transform transform;
|
||||||
|
/// transform.rotate(sf::degrees(90), sf::Vector2f(8, 3)).translate(sf::Vector2f(50, 20));
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \param angle Rotation angle
|
||||||
|
/// \param center Center of rotation
|
||||||
|
///
|
||||||
|
/// \return Reference to `*this`
|
||||||
|
///
|
||||||
|
/// \see `translate`, `scale`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_GRAPHICS_API Transform& rotate(Angle angle, Vector2f center);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Combine the current transform with a scaling
|
||||||
|
///
|
||||||
|
/// This function returns a reference to `*this`, so that calls
|
||||||
|
/// can be chained.
|
||||||
|
/// \code
|
||||||
|
/// sf::Transform transform;
|
||||||
|
/// transform.scale(sf::Vector2f(2, 1)).rotate(sf::degrees(45));
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \param factors Scaling factors
|
||||||
|
///
|
||||||
|
/// \return Reference to `*this`
|
||||||
|
///
|
||||||
|
/// \see `translate`, `rotate`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Transform& scale(Vector2f factors);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Combine the current transform with a scaling
|
||||||
|
///
|
||||||
|
/// The center of scaling is provided for convenience as a second
|
||||||
|
/// argument, so that you can build scaling around arbitrary points
|
||||||
|
/// more easily (and efficiently) than the usual
|
||||||
|
/// `translate(-center).scale(factors).translate(center)`.
|
||||||
|
///
|
||||||
|
/// This function returns a reference to `*this`, so that calls
|
||||||
|
/// can be chained.
|
||||||
|
/// \code
|
||||||
|
/// sf::Transform transform;
|
||||||
|
/// transform.scale(sf::Vector2f(2, 1), sf::Vector2f(8, 3)).rotate(45);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \param factors Scaling factors
|
||||||
|
/// \param center Center of scaling
|
||||||
|
///
|
||||||
|
/// \return Reference to `*this`
|
||||||
|
///
|
||||||
|
/// \see `translate`, `rotate`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Transform& scale(Vector2f factors, Vector2f center);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Static member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||||
|
static const Transform Identity; //!< The identity transform (does nothing)
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// clang-format off
|
||||||
|
std::array<float, 16> m_matrix{1.f, 0.f, 0.f, 0.f,
|
||||||
|
0.f, 1.f, 0.f, 0.f,
|
||||||
|
0.f, 0.f, 1.f, 0.f,
|
||||||
|
0.f, 0.f, 0.f, 1.f}; //!< 4x4 matrix defining the transformation
|
||||||
|
// clang-format off
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates sf::Transform
|
||||||
|
/// \brief Overload of binary `operator*` to combine two transforms
|
||||||
|
///
|
||||||
|
/// This call is equivalent to calling `Transform(left).combine(right)`.
|
||||||
|
///
|
||||||
|
/// \param left Left operand (the first transform)
|
||||||
|
/// \param right Right operand (the second transform)
|
||||||
|
///
|
||||||
|
/// \return New combined transform
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr Transform operator*(const Transform& left, const Transform& right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates sf::Transform
|
||||||
|
/// \brief Overload of binary `operator*=` to combine two transforms
|
||||||
|
///
|
||||||
|
/// This call is equivalent to calling `left.combine(right)`.
|
||||||
|
///
|
||||||
|
/// \param left Left operand (the first transform)
|
||||||
|
/// \param right Right operand (the second transform)
|
||||||
|
///
|
||||||
|
/// \return The combined transform
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Transform& operator*=(Transform& left, const Transform& right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates sf::Transform
|
||||||
|
/// \brief Overload of binary `operator*` to transform a point
|
||||||
|
///
|
||||||
|
/// This call is equivalent to calling `left.transformPoint(right)`.
|
||||||
|
///
|
||||||
|
/// \param left Left operand (the transform)
|
||||||
|
/// \param right Right operand (the point to transform)
|
||||||
|
///
|
||||||
|
/// \return New transformed point
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr Vector2f operator*(const Transform& left, Vector2f right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates sf::Transform
|
||||||
|
/// \brief Overload of binary `operator==` to compare two transforms
|
||||||
|
///
|
||||||
|
/// Performs an element-wise comparison of the elements of the
|
||||||
|
/// left transform with the elements of the right transform.
|
||||||
|
///
|
||||||
|
/// \param left Left operand (the first transform)
|
||||||
|
/// \param right Right operand (the second transform)
|
||||||
|
///
|
||||||
|
/// \return `true` if the transforms are equal, `false` otherwise
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr bool operator==(const Transform& left, const Transform& right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates sf::Transform
|
||||||
|
/// \brief Overload of binary `operator!=` to compare two transforms
|
||||||
|
///
|
||||||
|
/// This call is equivalent to `!(left == right)`.
|
||||||
|
///
|
||||||
|
/// \param left Left operand (the first transform)
|
||||||
|
/// \param right Right operand (the second transform)
|
||||||
|
///
|
||||||
|
/// \return `true` if the transforms are not equal, `false` otherwise
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr bool operator!=(const Transform& left, const Transform& right);
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
#include <SFML/Graphics/Transform.inl>
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::Transform
|
||||||
|
/// \ingroup graphics
|
||||||
|
///
|
||||||
|
/// A `sf::Transform` specifies how to translate, rotate, scale,
|
||||||
|
/// shear, project, whatever things. In mathematical terms, it defines
|
||||||
|
/// how to transform a coordinate system into another.
|
||||||
|
///
|
||||||
|
/// For example, if you apply a rotation transform to a sprite, the
|
||||||
|
/// result will be a rotated sprite. And anything that is transformed
|
||||||
|
/// by this rotation transform will be rotated the same way, according
|
||||||
|
/// to its initial position.
|
||||||
|
///
|
||||||
|
/// Transforms are typically used for drawing. But they can also be
|
||||||
|
/// used for any computation that requires to transform points between
|
||||||
|
/// the local and global coordinate systems of an entity (like collision
|
||||||
|
/// detection).
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// \code
|
||||||
|
/// // define a translation transform
|
||||||
|
/// sf::Transform translation;
|
||||||
|
/// translation.translate(20, 50);
|
||||||
|
///
|
||||||
|
/// // define a rotation transform
|
||||||
|
/// sf::Transform rotation;
|
||||||
|
/// rotation.rotate(45);
|
||||||
|
///
|
||||||
|
/// // combine them
|
||||||
|
/// sf::Transform transform = translation * rotation;
|
||||||
|
///
|
||||||
|
/// // use the result to transform stuff...
|
||||||
|
/// sf::Vector2f point = transform.transformPoint({10, 20});
|
||||||
|
/// sf::FloatRect rect = transform.transformRect(sf::FloatRect({0, 0}, {10, 100}));
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::Transformable`, `sf::RenderStates`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,236 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Transform.hpp> // NOLINT(misc-header-include-cycle)
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// clang-format off
|
||||||
|
constexpr Transform::Transform(float a00, float a01, float a02,
|
||||||
|
float a10, float a11, float a12,
|
||||||
|
float a20, float a21, float a22)
|
||||||
|
: m_matrix{a00, a10, 0.f, a20,
|
||||||
|
a01, a11, 0.f, a21,
|
||||||
|
0.f, 0.f, 1.f, 0.f,
|
||||||
|
a02, a12, 0.f, a22}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr const float* Transform::getMatrix() const
|
||||||
|
{
|
||||||
|
return m_matrix.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Transform Transform::getInverse() const
|
||||||
|
{
|
||||||
|
// clang-format off
|
||||||
|
// Compute the determinant
|
||||||
|
const float det = m_matrix[0] * (m_matrix[15] * m_matrix[5] - m_matrix[7] * m_matrix[13]) -
|
||||||
|
m_matrix[1] * (m_matrix[15] * m_matrix[4] - m_matrix[7] * m_matrix[12]) +
|
||||||
|
m_matrix[3] * (m_matrix[13] * m_matrix[4] - m_matrix[5] * m_matrix[12]);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
// Compute the inverse if the determinant is not zero
|
||||||
|
// (don't use an epsilon because the determinant may *really* be tiny)
|
||||||
|
if (det != 0.f)
|
||||||
|
{
|
||||||
|
// clang-format off
|
||||||
|
return {(m_matrix[15] * m_matrix[5] - m_matrix[7] * m_matrix[13]) / det,
|
||||||
|
-(m_matrix[15] * m_matrix[4] - m_matrix[7] * m_matrix[12]) / det,
|
||||||
|
(m_matrix[13] * m_matrix[4] - m_matrix[5] * m_matrix[12]) / det,
|
||||||
|
-(m_matrix[15] * m_matrix[1] - m_matrix[3] * m_matrix[13]) / det,
|
||||||
|
(m_matrix[15] * m_matrix[0] - m_matrix[3] * m_matrix[12]) / det,
|
||||||
|
-(m_matrix[13] * m_matrix[0] - m_matrix[1] * m_matrix[12]) / det,
|
||||||
|
(m_matrix[7] * m_matrix[1] - m_matrix[3] * m_matrix[5]) / det,
|
||||||
|
-(m_matrix[7] * m_matrix[0] - m_matrix[3] * m_matrix[4]) / det,
|
||||||
|
(m_matrix[5] * m_matrix[0] - m_matrix[1] * m_matrix[4]) / det};
|
||||||
|
// clang-format on
|
||||||
|
}
|
||||||
|
|
||||||
|
return Identity;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Vector2f Transform::transformPoint(Vector2f point) const
|
||||||
|
{
|
||||||
|
return {m_matrix[0] * point.x + m_matrix[4] * point.y + m_matrix[12],
|
||||||
|
m_matrix[1] * point.x + m_matrix[5] * point.y + m_matrix[13]};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr FloatRect Transform::transformRect(const FloatRect& rectangle) const
|
||||||
|
{
|
||||||
|
// Transform the 4 corners of the rectangle
|
||||||
|
const std::array points = {transformPoint(rectangle.position),
|
||||||
|
transformPoint(rectangle.position + Vector2f(0.f, rectangle.size.y)),
|
||||||
|
transformPoint(rectangle.position + Vector2f(rectangle.size.x, 0.f)),
|
||||||
|
transformPoint(rectangle.position + rectangle.size)};
|
||||||
|
|
||||||
|
// Compute the bounding rectangle of the transformed points
|
||||||
|
Vector2f pmin = points[0];
|
||||||
|
Vector2f pmax = points[0];
|
||||||
|
|
||||||
|
for (std::size_t i = 1; i < points.size(); ++i)
|
||||||
|
{
|
||||||
|
// clang-format off
|
||||||
|
if (points[i].x < pmin.x) pmin.x = points[i].x;
|
||||||
|
else if (points[i].x > pmax.x) pmax.x = points[i].x;
|
||||||
|
|
||||||
|
if (points[i].y < pmin.y) pmin.y = points[i].y;
|
||||||
|
else if (points[i].y > pmax.y) pmax.y = points[i].y;
|
||||||
|
// clang-format on
|
||||||
|
}
|
||||||
|
|
||||||
|
return {pmin, pmax - pmin};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Transform& Transform::combine(const Transform& transform)
|
||||||
|
{
|
||||||
|
const auto& a = m_matrix;
|
||||||
|
const auto& b = transform.m_matrix;
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
*this = Transform(a[0] * b[0] + a[4] * b[1] + a[12] * b[3],
|
||||||
|
a[0] * b[4] + a[4] * b[5] + a[12] * b[7],
|
||||||
|
a[0] * b[12] + a[4] * b[13] + a[12] * b[15],
|
||||||
|
a[1] * b[0] + a[5] * b[1] + a[13] * b[3],
|
||||||
|
a[1] * b[4] + a[5] * b[5] + a[13] * b[7],
|
||||||
|
a[1] * b[12] + a[5] * b[13] + a[13] * b[15],
|
||||||
|
a[3] * b[0] + a[7] * b[1] + a[15] * b[3],
|
||||||
|
a[3] * b[4] + a[7] * b[5] + a[15] * b[7],
|
||||||
|
a[3] * b[12] + a[7] * b[13] + a[15] * b[15]);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Transform& Transform::translate(Vector2f offset)
|
||||||
|
{
|
||||||
|
// clang-format off
|
||||||
|
const Transform translation(1, 0, offset.x,
|
||||||
|
0, 1, offset.y,
|
||||||
|
0, 0, 1);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
return combine(translation);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Transform& Transform::scale(Vector2f factors)
|
||||||
|
{
|
||||||
|
// clang-format off
|
||||||
|
const Transform scaling(factors.x, 0, 0,
|
||||||
|
0, factors.y, 0,
|
||||||
|
0, 0, 1);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
return combine(scaling);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Transform& Transform::scale(Vector2f factors, Vector2f center)
|
||||||
|
{
|
||||||
|
// clang-format off
|
||||||
|
const Transform scaling(factors.x, 0, center.x * (1 - factors.x),
|
||||||
|
0, factors.y, center.y * (1 - factors.y),
|
||||||
|
0, 0, 1);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
return combine(scaling);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Transform operator*(const Transform& left, const Transform& right)
|
||||||
|
{
|
||||||
|
return Transform(left).combine(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Transform& operator*=(Transform& left, const Transform& right)
|
||||||
|
{
|
||||||
|
return left.combine(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Vector2f operator*(const Transform& left, Vector2f right)
|
||||||
|
{
|
||||||
|
return left.transformPoint(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr bool operator==(const Transform& left, const Transform& right)
|
||||||
|
{
|
||||||
|
const float* a = left.getMatrix();
|
||||||
|
const float* b = right.getMatrix();
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
return ((a[0] == b[0]) && (a[1] == b[1]) && (a[3] == b[3]) &&
|
||||||
|
(a[4] == b[4]) && (a[5] == b[5]) && (a[7] == b[7]) &&
|
||||||
|
(a[12] == b[12]) && (a[13] == b[13]) && (a[15] == b[15]));
|
||||||
|
// clang-format on
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr bool operator!=(const Transform& left, const Transform& right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Static member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Note: the 'inline' keyword here is technically not required, but VS2019 fails
|
||||||
|
// to compile with a bogus "multiple definition" error if not explicitly used.
|
||||||
|
inline constexpr Transform Transform::Identity;
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
@ -0,0 +1,340 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Graphics/Transform.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/Angle.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Decomposed transform defined by a position, a rotation and a scale
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_GRAPHICS_API Transformable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Transformable() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Virtual destructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
virtual ~Transformable() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief set the position of the object
|
||||||
|
///
|
||||||
|
/// This function completely overwrites the previous position.
|
||||||
|
/// See the move function to apply an offset based on the previous position instead.
|
||||||
|
/// The default position of a transformable object is (0, 0).
|
||||||
|
///
|
||||||
|
/// \param position New position
|
||||||
|
///
|
||||||
|
/// \see `move`, `getPosition`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setPosition(Vector2f position);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief set the orientation of the object
|
||||||
|
///
|
||||||
|
/// This function completely overwrites the previous rotation.
|
||||||
|
/// See the rotate function to add an angle based on the previous rotation instead.
|
||||||
|
/// The default rotation of a transformable object is 0.
|
||||||
|
///
|
||||||
|
/// \param angle New rotation
|
||||||
|
///
|
||||||
|
/// \see `rotate`, `getRotation`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setRotation(Angle angle);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief set the scale factors of the object
|
||||||
|
///
|
||||||
|
/// This function completely overwrites the previous scale.
|
||||||
|
/// See the scale function to add a factor based on the previous scale instead.
|
||||||
|
/// The default scale of a transformable object is (1, 1).
|
||||||
|
///
|
||||||
|
/// \param factors New scale factors
|
||||||
|
///
|
||||||
|
/// \see `scale`, `getScale`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setScale(Vector2f factors);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief set the local origin of the object
|
||||||
|
///
|
||||||
|
/// The origin of an object defines the center point for
|
||||||
|
/// all transformations (position, scale, rotation).
|
||||||
|
/// The coordinates of this point must be relative to the
|
||||||
|
/// top-left corner of the object, and ignore all
|
||||||
|
/// transformations (position, scale, rotation).
|
||||||
|
/// The default origin of a transformable object is (0, 0).
|
||||||
|
///
|
||||||
|
/// \param origin New origin
|
||||||
|
///
|
||||||
|
/// \see `getOrigin`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setOrigin(Vector2f origin);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief get the position of the object
|
||||||
|
///
|
||||||
|
/// \return Current position
|
||||||
|
///
|
||||||
|
/// \see `setPosition`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Vector2f getPosition() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief get the orientation of the object
|
||||||
|
///
|
||||||
|
/// The rotation is always in the range [0, 360].
|
||||||
|
///
|
||||||
|
/// \return Current rotation
|
||||||
|
///
|
||||||
|
/// \see `setRotation`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Angle getRotation() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief get the current scale of the object
|
||||||
|
///
|
||||||
|
/// \return Current scale factors
|
||||||
|
///
|
||||||
|
/// \see `setScale`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Vector2f getScale() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief get the local origin of the object
|
||||||
|
///
|
||||||
|
/// \return Current origin
|
||||||
|
///
|
||||||
|
/// \see `setOrigin`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Vector2f getOrigin() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move the object by a given offset
|
||||||
|
///
|
||||||
|
/// This function adds to the current position of the object,
|
||||||
|
/// unlike `setPosition` which overwrites it.
|
||||||
|
/// Thus, it is equivalent to the following code:
|
||||||
|
/// \code
|
||||||
|
/// object.setPosition(object.getPosition() + offset);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \param offset Offset
|
||||||
|
///
|
||||||
|
/// \see `setPosition`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void move(Vector2f offset);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Rotate the object
|
||||||
|
///
|
||||||
|
/// This function adds to the current rotation of the object,
|
||||||
|
/// unlike `setRotation` which overwrites it.
|
||||||
|
/// Thus, it is equivalent to the following code:
|
||||||
|
/// \code
|
||||||
|
/// object.setRotation(object.getRotation() + angle);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \param angle Angle of rotation
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void rotate(Angle angle);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Scale the object
|
||||||
|
///
|
||||||
|
/// This function multiplies the current scale of the object,
|
||||||
|
/// unlike `setScale` which overwrites it.
|
||||||
|
/// Thus, it is equivalent to the following code:
|
||||||
|
/// \code
|
||||||
|
/// sf::Vector2f scale = object.getScale();
|
||||||
|
/// object.setScale(scale.x * factor.x, scale.y * factor.y);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \param factor Scale factors
|
||||||
|
///
|
||||||
|
/// \see `setScale`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void scale(Vector2f factor);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief get the combined transform of the object
|
||||||
|
///
|
||||||
|
/// \return Transform combining the position/rotation/scale/origin of the object
|
||||||
|
///
|
||||||
|
/// \see `getInverseTransform`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const Transform& getTransform() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief get the inverse of the combined transform of the object
|
||||||
|
///
|
||||||
|
/// \return Inverse of the combined transformations applied to the object
|
||||||
|
///
|
||||||
|
/// \see `getTransform`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const Transform& getInverseTransform() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Vector2f m_origin; //!< Origin of translation/rotation/scaling of the object
|
||||||
|
Vector2f m_position; //!< Position of the object in the 2D world
|
||||||
|
Angle m_rotation; //!< Orientation of the object
|
||||||
|
Vector2f m_scale{1, 1}; //!< Scale of the object
|
||||||
|
mutable Transform m_transform; //!< Combined transformation of the object
|
||||||
|
mutable Transform m_inverseTransform; //!< Combined transformation of the object
|
||||||
|
mutable bool m_transformNeedUpdate{true}; //!< Does the transform need to be recomputed?
|
||||||
|
mutable bool m_inverseTransformNeedUpdate{true}; //!< Does the transform need to be recomputed?
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::Transformable
|
||||||
|
/// \ingroup graphics
|
||||||
|
///
|
||||||
|
/// This class is provided for convenience, on top of `sf::Transform`.
|
||||||
|
///
|
||||||
|
/// `sf::Transform`, as a low-level class, offers a great level of
|
||||||
|
/// flexibility but it is not always convenient to manage. Indeed,
|
||||||
|
/// one can easily combine any kind of operation, such as a translation
|
||||||
|
/// followed by a rotation followed by a scaling, but once the result
|
||||||
|
/// transform is built, there's no way to go backward and, let's say,
|
||||||
|
/// change only the rotation without modifying the translation and scaling.
|
||||||
|
/// The entire transform must be recomputed, which means that you
|
||||||
|
/// need to retrieve the initial translation and scale factors as
|
||||||
|
/// well, and combine them the same way you did before updating the
|
||||||
|
/// rotation. This is a tedious operation, and it requires to store
|
||||||
|
/// all the individual components of the final transform.
|
||||||
|
///
|
||||||
|
/// That's exactly what `sf::Transformable` was written for: it hides
|
||||||
|
/// these variables and the composed transform behind an easy to use
|
||||||
|
/// interface. You can set or get any of the individual components
|
||||||
|
/// without worrying about the others. It also provides the composed
|
||||||
|
/// transform (as a `sf::Transform`), and keeps it up-to-date.
|
||||||
|
///
|
||||||
|
/// In addition to the position, rotation and scale, `sf::Transformable`
|
||||||
|
/// provides an "origin" component, which represents the local origin
|
||||||
|
/// of the three other components. Let's take an example with a 10x10
|
||||||
|
/// pixels sprite. By default, the sprite is positioned/rotated/scaled
|
||||||
|
/// relative to its top-left corner, because it is the local point
|
||||||
|
/// (0, 0). But if we change the origin to be (5, 5), the sprite will
|
||||||
|
/// be positioned/rotated/scaled around its center instead. And if
|
||||||
|
/// we set the origin to (10, 10), it will be transformed around its
|
||||||
|
/// bottom-right corner.
|
||||||
|
///
|
||||||
|
/// To keep the `sf::Transformable` class simple, there's only one
|
||||||
|
/// origin for all the components. You cannot position the sprite
|
||||||
|
/// relative to its top-left corner while rotating it around its
|
||||||
|
/// center, for example. To do such things, use `sf::Transform` directly.
|
||||||
|
///
|
||||||
|
/// `sf::Transformable` can be used as a base class. It is often
|
||||||
|
/// combined with `sf::Drawable` -- that's what SFML's sprites,
|
||||||
|
/// texts and shapes do.
|
||||||
|
/// \code
|
||||||
|
/// class MyEntity : public sf::Transformable, public sf::Drawable
|
||||||
|
/// {
|
||||||
|
/// void draw(sf::RenderTarget& target, sf::RenderStates states) const override
|
||||||
|
/// {
|
||||||
|
/// states.transform *= getTransform();
|
||||||
|
/// target.draw(..., states);
|
||||||
|
/// }
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// MyEntity entity;
|
||||||
|
/// entity.setPosition({10, 20});
|
||||||
|
/// entity.setRotation(sf::degrees(45));
|
||||||
|
/// window.draw(entity);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// It can also be used as a member, if you don't want to use
|
||||||
|
/// its API directly (because you don't need all its functions,
|
||||||
|
/// or you have different naming conventions for example).
|
||||||
|
/// \code
|
||||||
|
/// class MyEntity
|
||||||
|
/// {
|
||||||
|
/// public:
|
||||||
|
/// void SetPosition(const MyVector& v)
|
||||||
|
/// {
|
||||||
|
/// myTransform.setPosition(v.x(), v.y());
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// void Draw(sf::RenderTarget& target) const
|
||||||
|
/// {
|
||||||
|
/// target.draw(..., myTransform.getTransform());
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// private:
|
||||||
|
/// sf::Transformable myTransform;
|
||||||
|
/// };
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// A note on coordinates and undistorted rendering: \n
|
||||||
|
/// By default, SFML (or more exactly, OpenGL) may interpolate drawable objects
|
||||||
|
/// such as sprites or texts when rendering. While this allows transitions
|
||||||
|
/// like slow movements or rotations to appear smoothly, it can lead to
|
||||||
|
/// unwanted results in some cases, for example blurred or distorted objects.
|
||||||
|
/// In order to render a `sf::Drawable` object pixel-perfectly, make sure
|
||||||
|
/// the involved coordinates allow a 1:1 mapping of pixels in the window
|
||||||
|
/// to texels (pixels in the texture). More specifically, this means:
|
||||||
|
/// * The object's position, origin and scale have no fractional part
|
||||||
|
/// * The object's and the view's rotation are a multiple of 90 degrees
|
||||||
|
/// * The view's center and size have no fractional part
|
||||||
|
///
|
||||||
|
/// \see `sf::Transform`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,122 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Color.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/Vector2.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Point with color and texture coordinates
|
||||||
|
///
|
||||||
|
/// By default, the vertex color is white and texture coordinates are (0, 0).
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
struct Vertex
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Vector2f position; //!< 2D position of the vertex
|
||||||
|
Color color{Color::White}; //!< Color of the vertex
|
||||||
|
Vector2f texCoords{}; //!< Coordinates of the texture's pixel to map to the vertex NOLINT(readability-redundant-member-init)
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \struct sf::Vertex
|
||||||
|
/// \ingroup graphics
|
||||||
|
///
|
||||||
|
/// A vertex is an improved point. It has a position and other
|
||||||
|
/// extra attributes that will be used for drawing: in SFML,
|
||||||
|
/// vertices also have a color and a pair of texture coordinates.
|
||||||
|
///
|
||||||
|
/// The vertex is the building block of drawing. Everything which
|
||||||
|
/// is visible on screen is made of vertices. They are grouped
|
||||||
|
/// as 2D primitives (lines, triangles, ...), and these primitives
|
||||||
|
/// are grouped to create even more complex 2D entities such as
|
||||||
|
/// sprites, texts, etc.
|
||||||
|
///
|
||||||
|
/// If you use the graphical entities of SFML (sprite, text, shape)
|
||||||
|
/// you won't have to deal with vertices directly. But if you want
|
||||||
|
/// to define your own 2D entities, such as tiled maps or particle
|
||||||
|
/// systems, using vertices will allow you to get maximum performances.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// \code
|
||||||
|
/// // define a 100x100 square, red, with a 10x10 texture mapped on it
|
||||||
|
/// sf::Vertex vertices[]
|
||||||
|
/// {
|
||||||
|
/// {{ 0.0f, 0.0f}, sf::Color::Red, { 0.0f, 0.0f}},
|
||||||
|
/// {{ 0.0f, 100.0f}, sf::Color::Red, { 0.0f, 10.0f}},
|
||||||
|
/// {{100.0f, 100.0f}, sf::Color::Red, {10.0f, 10.0f}},
|
||||||
|
/// {{ 0.0f, 0.0f}, sf::Color::Red, { 0.0f, 0.0f}},
|
||||||
|
/// {{100.0f, 100.0f}, sf::Color::Red, {10.0f, 10.0f}},
|
||||||
|
/// {{100.0f, 0.0f}, sf::Color::Red, {10.0f, 0.0f}}
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// // draw it
|
||||||
|
/// window.draw(vertices, 6, sf::PrimitiveType::Triangles);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// It is recommended to use aggregate initialization to create vertex
|
||||||
|
/// objects, which initializes the members in order.
|
||||||
|
///
|
||||||
|
/// On a C++20-compliant compiler (or where supported as an extension)
|
||||||
|
/// it is possible to use "designated initializers" to only initialize
|
||||||
|
/// a subset of members, with the restriction of having to follow the
|
||||||
|
/// same order in which they are defined.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// \code
|
||||||
|
/// // C++17 and above
|
||||||
|
/// sf::Vertex v0{{5.0f, 5.0f}}; // explicit 'position', implicit 'color' and 'texCoords'
|
||||||
|
/// sf::Vertex v1{{5.0f, 5.0f}, sf::Color::Red}; // explicit 'position' and 'color', implicit 'texCoords'
|
||||||
|
/// sf::Vertex v2{{5.0f, 5.0f}, sf::Color::Red, {1.0f, 1.0f}}; // everything is explicitly specified
|
||||||
|
///
|
||||||
|
/// // C++20 and above (or compilers supporting "designated initializers" as an extension)
|
||||||
|
/// sf::Vertex v3{
|
||||||
|
/// .position{5.0f, 5.0f},
|
||||||
|
/// .texCoords{1.0f, 1.0f}
|
||||||
|
/// };
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// Note: Although texture coordinates are supposed to be an integer
|
||||||
|
/// amount of pixels, their type is float because of some buggy graphics
|
||||||
|
/// drivers that are not able to process integer coordinates correctly.
|
||||||
|
///
|
||||||
|
/// \see `sf::VertexArray`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,221 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Graphics/Drawable.hpp>
|
||||||
|
#include <SFML/Graphics/PrimitiveType.hpp>
|
||||||
|
#include <SFML/Graphics/Rect.hpp>
|
||||||
|
#include <SFML/Graphics/RenderStates.hpp>
|
||||||
|
#include <SFML/Graphics/Vertex.hpp>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class RenderTarget;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set of one or more 2D primitives
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_GRAPHICS_API VertexArray : public Drawable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// Creates an empty vertex array.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
VertexArray() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the vertex array with a type and an initial number of vertices
|
||||||
|
///
|
||||||
|
/// \param type Type of primitives
|
||||||
|
/// \param vertexCount Initial number of vertices in the array
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit VertexArray(PrimitiveType type, std::size_t vertexCount = 0);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Return the vertex count
|
||||||
|
///
|
||||||
|
/// \return Number of vertices in the array
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] std::size_t getVertexCount() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get a read-write access to a vertex by its index
|
||||||
|
///
|
||||||
|
/// This function doesn't check `index`, it must be in range
|
||||||
|
/// [0, `getVertexCount()` - 1]. The behavior is undefined
|
||||||
|
/// otherwise.
|
||||||
|
///
|
||||||
|
/// \param index Index of the vertex to get
|
||||||
|
///
|
||||||
|
/// \return Reference to the `index`-th vertex
|
||||||
|
///
|
||||||
|
/// \see `getVertexCount`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Vertex& operator[](std::size_t index);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get a read-only access to a vertex by its index
|
||||||
|
///
|
||||||
|
/// This function doesn't check `index`, it must be in range
|
||||||
|
/// [0, `getVertexCount()` - 1]. The behavior is undefined
|
||||||
|
/// otherwise.
|
||||||
|
///
|
||||||
|
/// \param index Index of the vertex to get
|
||||||
|
///
|
||||||
|
/// \return Const reference to the `index`-th vertex
|
||||||
|
///
|
||||||
|
/// \see `getVertexCount`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const Vertex& operator[](std::size_t index) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Clear the vertex array
|
||||||
|
///
|
||||||
|
/// This function removes all the vertices from the array.
|
||||||
|
/// It doesn't deallocate the corresponding memory, so that
|
||||||
|
/// adding new vertices after clearing doesn't involve
|
||||||
|
/// reallocating all the memory.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Resize the vertex array
|
||||||
|
///
|
||||||
|
/// If `vertexCount` is greater than the current size, the previous
|
||||||
|
/// vertices are kept and new (default-constructed) vertices are
|
||||||
|
/// added.
|
||||||
|
/// If `vertexCount` is less than the current size, existing vertices
|
||||||
|
/// are removed from the array.
|
||||||
|
///
|
||||||
|
/// \param vertexCount New size of the array (number of vertices)
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void resize(std::size_t vertexCount);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Add a vertex to the array
|
||||||
|
///
|
||||||
|
/// \param vertex Vertex to add
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void append(const Vertex& vertex);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the type of primitives to draw
|
||||||
|
///
|
||||||
|
/// This function defines how the vertices must be interpreted
|
||||||
|
/// when it's time to draw them:
|
||||||
|
/// \li As points
|
||||||
|
/// \li As lines
|
||||||
|
/// \li As triangles
|
||||||
|
/// The default primitive type is `sf::PrimitiveType::Points`.
|
||||||
|
///
|
||||||
|
/// \param type Type of primitive
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setPrimitiveType(PrimitiveType type);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the type of primitives drawn by the vertex array
|
||||||
|
///
|
||||||
|
/// \return Primitive type
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] PrimitiveType getPrimitiveType() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Compute the bounding rectangle of the vertex array
|
||||||
|
///
|
||||||
|
/// This function returns the minimal axis-aligned rectangle
|
||||||
|
/// that contains all the vertices of the array.
|
||||||
|
///
|
||||||
|
/// \return Bounding rectangle of the vertex array
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] FloatRect getBounds() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Draw the vertex array to a render target
|
||||||
|
///
|
||||||
|
/// \param target Render target to draw to
|
||||||
|
/// \param states Current render states
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void draw(RenderTarget& target, RenderStates states) const override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::vector<Vertex> m_vertices; //!< Vertices contained in the array
|
||||||
|
PrimitiveType m_primitiveType{PrimitiveType::Points}; //!< Type of primitives to draw
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::VertexArray
|
||||||
|
/// \ingroup graphics
|
||||||
|
///
|
||||||
|
/// `sf::VertexArray` is a very simple wrapper around a dynamic
|
||||||
|
/// array of vertices and a primitives type.
|
||||||
|
///
|
||||||
|
/// It inherits `sf::Drawable`, but unlike other drawables it
|
||||||
|
/// is not transformable.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// \code
|
||||||
|
/// sf::VertexArray lines(sf::PrimitiveType::LineStrip, 4);
|
||||||
|
/// lines[0].position = sf::Vector2f(10, 0);
|
||||||
|
/// lines[1].position = sf::Vector2f(20, 0);
|
||||||
|
/// lines[2].position = sf::Vector2f(30, 5);
|
||||||
|
/// lines[3].position = sf::Vector2f(40, 2);
|
||||||
|
///
|
||||||
|
/// window.draw(lines);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::Vertex`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,414 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Graphics/Drawable.hpp>
|
||||||
|
#include <SFML/Graphics/PrimitiveType.hpp>
|
||||||
|
#include <SFML/Graphics/RenderStates.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Window/GlResource.hpp>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class RenderTarget;
|
||||||
|
struct Vertex;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Vertex buffer storage for one or more 2D primitives
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_GRAPHICS_API VertexBuffer : public Drawable, private GlResource
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Usage specifiers
|
||||||
|
///
|
||||||
|
/// If data is going to be updated once or more every frame,
|
||||||
|
/// set the usage to Stream. If data is going to be set once
|
||||||
|
/// and used for a long time without being modified, set the
|
||||||
|
/// usage to Static. For everything else Dynamic should be a
|
||||||
|
/// good compromise.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
enum class Usage
|
||||||
|
{
|
||||||
|
Stream, //!< Constantly changing data
|
||||||
|
Dynamic, //!< Occasionally changing data
|
||||||
|
Static //!< Rarely changing data
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// Creates an empty vertex buffer.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
VertexBuffer() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct a `VertexBuffer` with a specific `PrimitiveType`
|
||||||
|
///
|
||||||
|
/// Creates an empty vertex buffer and sets its primitive type to \p type.
|
||||||
|
///
|
||||||
|
/// \param type Type of primitive
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit VertexBuffer(PrimitiveType type);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct a `VertexBuffer` with a specific usage specifier
|
||||||
|
///
|
||||||
|
/// Creates an empty vertex buffer and sets its usage to \p usage.
|
||||||
|
///
|
||||||
|
/// \param usage Usage specifier
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit VertexBuffer(Usage usage);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct a `VertexBuffer` with a specific `PrimitiveType` and usage specifier
|
||||||
|
///
|
||||||
|
/// Creates an empty vertex buffer and sets its primitive type
|
||||||
|
/// to \p type and usage to \p usage.
|
||||||
|
///
|
||||||
|
/// \param type Type of primitive
|
||||||
|
/// \param usage Usage specifier
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
VertexBuffer(PrimitiveType type, Usage usage);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Copy constructor
|
||||||
|
///
|
||||||
|
/// \param copy instance to copy
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
VertexBuffer(const VertexBuffer& copy);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Destructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
~VertexBuffer() override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Create the vertex buffer
|
||||||
|
///
|
||||||
|
/// Creates the vertex buffer and allocates enough graphics
|
||||||
|
/// memory to hold `vertexCount` vertices. Any previously
|
||||||
|
/// allocated memory is freed in the process.
|
||||||
|
///
|
||||||
|
/// In order to deallocate previously allocated memory pass 0
|
||||||
|
/// as `vertexCount`. Don't forget to recreate with a non-zero
|
||||||
|
/// value when graphics memory should be allocated again.
|
||||||
|
///
|
||||||
|
/// \param vertexCount Number of vertices worth of memory to allocate
|
||||||
|
///
|
||||||
|
/// \return `true` if creation was successful
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool create(std::size_t vertexCount);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Return the vertex count
|
||||||
|
///
|
||||||
|
/// \return Number of vertices in the vertex buffer
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] std::size_t getVertexCount() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Update the whole buffer from an array of vertices
|
||||||
|
///
|
||||||
|
/// The vertex array is assumed to have the same size as
|
||||||
|
/// the created buffer.
|
||||||
|
///
|
||||||
|
/// No additional check is performed on the size of the vertex
|
||||||
|
/// array. Passing invalid arguments will lead to undefined
|
||||||
|
/// behavior.
|
||||||
|
///
|
||||||
|
/// This function does nothing if `vertices` is null or if the
|
||||||
|
/// buffer was not previously created.
|
||||||
|
///
|
||||||
|
/// \param vertices Array of vertices to copy to the buffer
|
||||||
|
///
|
||||||
|
/// \return `true` if the update was successful
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool update(const Vertex* vertices);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Update a part of the buffer from an array of vertices
|
||||||
|
///
|
||||||
|
/// `offset` is specified as the number of vertices to skip
|
||||||
|
/// from the beginning of the buffer.
|
||||||
|
///
|
||||||
|
/// If `offset` is 0 and `vertexCount` is equal to the size of
|
||||||
|
/// the currently created buffer, its whole contents are replaced.
|
||||||
|
///
|
||||||
|
/// If `offset` is 0 and `vertexCount` is greater than the
|
||||||
|
/// size of the currently created buffer, a new buffer is created
|
||||||
|
/// containing the vertex data.
|
||||||
|
///
|
||||||
|
/// If `offset` is 0 and `vertexCount` is less than the size of
|
||||||
|
/// the currently created buffer, only the corresponding region
|
||||||
|
/// is updated.
|
||||||
|
///
|
||||||
|
/// If `offset` is not 0 and `offset` + `vertexCount` is greater
|
||||||
|
/// than the size of the currently created buffer, the update fails.
|
||||||
|
///
|
||||||
|
/// No additional check is performed on the size of the vertex
|
||||||
|
/// array. Passing invalid arguments will lead to undefined
|
||||||
|
/// behavior.
|
||||||
|
///
|
||||||
|
/// \param vertices Array of vertices to copy to the buffer
|
||||||
|
/// \param vertexCount Number of vertices to copy
|
||||||
|
/// \param offset Offset in the buffer to copy to
|
||||||
|
///
|
||||||
|
/// \return `true` if the update was successful
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool update(const Vertex* vertices, std::size_t vertexCount, unsigned int offset);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Copy the contents of another buffer into this buffer
|
||||||
|
///
|
||||||
|
/// \param vertexBuffer Vertex buffer whose contents to copy into this vertex buffer
|
||||||
|
///
|
||||||
|
/// \return `true` if the copy was successful
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool update(const VertexBuffer& vertexBuffer);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Overload of assignment operator
|
||||||
|
///
|
||||||
|
/// \param right Instance to assign
|
||||||
|
///
|
||||||
|
/// \return Reference to self
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
VertexBuffer& operator=(const VertexBuffer& right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Swap the contents of this vertex buffer with those of another
|
||||||
|
///
|
||||||
|
/// \param right Instance to swap with
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void swap(VertexBuffer& right) noexcept;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the underlying OpenGL handle of the vertex buffer.
|
||||||
|
///
|
||||||
|
/// You shouldn't need to use this function, unless you have
|
||||||
|
/// very specific stuff to implement that SFML doesn't support,
|
||||||
|
/// or implement a temporary workaround until a bug is fixed.
|
||||||
|
///
|
||||||
|
/// \return OpenGL handle of the vertex buffer or 0 if not yet created
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] unsigned int getNativeHandle() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the type of primitives to draw
|
||||||
|
///
|
||||||
|
/// This function defines how the vertices must be interpreted
|
||||||
|
/// when it's time to draw them.
|
||||||
|
///
|
||||||
|
/// The default primitive type is `sf::PrimitiveType::Points`.
|
||||||
|
///
|
||||||
|
/// \param type Type of primitive
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setPrimitiveType(PrimitiveType type);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the type of primitives drawn by the vertex buffer
|
||||||
|
///
|
||||||
|
/// \return Primitive type
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] PrimitiveType getPrimitiveType() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the usage specifier of this vertex buffer
|
||||||
|
///
|
||||||
|
/// This function provides a hint about how this vertex buffer is
|
||||||
|
/// going to be used in terms of data update frequency.
|
||||||
|
///
|
||||||
|
/// After changing the usage specifier, the vertex buffer has
|
||||||
|
/// to be updated with new data for the usage specifier to
|
||||||
|
/// take effect.
|
||||||
|
///
|
||||||
|
/// The default usage type is `sf::VertexBuffer::Usage::Stream`.
|
||||||
|
///
|
||||||
|
/// \param usage Usage specifier
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setUsage(Usage usage);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the usage specifier of this vertex buffer
|
||||||
|
///
|
||||||
|
/// \return Usage specifier
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Usage getUsage() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Bind a vertex buffer for rendering
|
||||||
|
///
|
||||||
|
/// This function is not part of the graphics API, it mustn't be
|
||||||
|
/// used when drawing SFML entities. It must be used only if you
|
||||||
|
/// mix `sf::VertexBuffer` with OpenGL code.
|
||||||
|
///
|
||||||
|
/// \code
|
||||||
|
/// sf::VertexBuffer vb1, vb2;
|
||||||
|
/// ...
|
||||||
|
/// sf::VertexBuffer::bind(&vb1);
|
||||||
|
/// // draw OpenGL stuff that use vb1...
|
||||||
|
/// sf::VertexBuffer::bind(&vb2);
|
||||||
|
/// // draw OpenGL stuff that use vb2...
|
||||||
|
/// sf::VertexBuffer::bind(nullptr);
|
||||||
|
/// // draw OpenGL stuff that use no vertex buffer...
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \param vertexBuffer Pointer to the vertex buffer to bind, can be null to use no vertex buffer
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
static void bind(const VertexBuffer* vertexBuffer);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Tell whether or not the system supports vertex buffers
|
||||||
|
///
|
||||||
|
/// This function should always be called before using
|
||||||
|
/// the vertex buffer features. If it returns `false`, then
|
||||||
|
/// any attempt to use `sf::VertexBuffer` will fail.
|
||||||
|
///
|
||||||
|
/// \return `true` if vertex buffers are supported, `false` otherwise
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] static bool isAvailable();
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Draw the vertex buffer to a render target
|
||||||
|
///
|
||||||
|
/// \param target Render target to draw to
|
||||||
|
/// \param states Current render states
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void draw(RenderTarget& target, RenderStates states) const override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
unsigned int m_buffer{}; //!< Internal buffer identifier
|
||||||
|
std::size_t m_size{}; //!< Size in Vertices of the currently allocated buffer
|
||||||
|
PrimitiveType m_primitiveType{PrimitiveType::Points}; //!< Type of primitives to draw
|
||||||
|
Usage m_usage{Usage::Stream}; //!< How this vertex buffer is to be used
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Swap the contents of one vertex buffer with those of another
|
||||||
|
///
|
||||||
|
/// \param left First instance to swap
|
||||||
|
/// \param right Second instance to swap
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_GRAPHICS_API void swap(VertexBuffer& left, VertexBuffer& right) noexcept;
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::VertexBuffer
|
||||||
|
/// \ingroup graphics
|
||||||
|
///
|
||||||
|
/// `sf::VertexBuffer` is a simple wrapper around a dynamic
|
||||||
|
/// buffer of vertices and a primitives type.
|
||||||
|
///
|
||||||
|
/// Unlike `sf::VertexArray`, the vertex data is stored in
|
||||||
|
/// graphics memory.
|
||||||
|
///
|
||||||
|
/// In situations where a large amount of vertex data would
|
||||||
|
/// have to be transferred from system memory to graphics memory
|
||||||
|
/// every frame, using `sf::VertexBuffer` can help. By using a
|
||||||
|
/// `sf::VertexBuffer`, data that has not been changed between frames
|
||||||
|
/// does not have to be re-transferred from system to graphics
|
||||||
|
/// memory as would be the case with `sf::VertexArray`. If data transfer
|
||||||
|
/// is a bottleneck, this can lead to performance gains.
|
||||||
|
///
|
||||||
|
/// Using `sf::VertexBuffer`, the user also has the ability to only modify
|
||||||
|
/// a portion of the buffer in graphics memory. This way, a large buffer
|
||||||
|
/// can be allocated at the start of the application and only the
|
||||||
|
/// applicable portions of it need to be updated during the course of
|
||||||
|
/// the application. This allows the user to take full control of data
|
||||||
|
/// transfers between system and graphics memory if they need to.
|
||||||
|
///
|
||||||
|
/// In special cases, the user can make use of multiple threads to update
|
||||||
|
/// vertex data in multiple distinct regions of the buffer simultaneously.
|
||||||
|
/// This might make sense when e.g. the position of multiple objects has to
|
||||||
|
/// be recalculated very frequently. The computation load can be spread
|
||||||
|
/// across multiple threads as long as there are no other data dependencies.
|
||||||
|
///
|
||||||
|
/// Simultaneous updates to the vertex buffer are not guaranteed to be
|
||||||
|
/// carried out by the driver in any specific order. Updating the same
|
||||||
|
/// region of the buffer from multiple threads will not cause undefined
|
||||||
|
/// behavior, however the final state of the buffer will be unpredictable.
|
||||||
|
///
|
||||||
|
/// Simultaneous updates of distinct non-overlapping regions of the buffer
|
||||||
|
/// are also not guaranteed to complete in a specific order. However, in
|
||||||
|
/// this case the user can make sure to synchronize the writer threads at
|
||||||
|
/// well-defined points in their code. The driver will make sure that all
|
||||||
|
/// pending data transfers complete before the vertex buffer is sourced
|
||||||
|
/// by the rendering pipeline.
|
||||||
|
///
|
||||||
|
/// It inherits `sf::Drawable`, but unlike other drawables it
|
||||||
|
/// is not transformable.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// \code
|
||||||
|
/// std::array<sf::Vertex, 15> vertices;
|
||||||
|
/// ...
|
||||||
|
/// sf::VertexBuffer triangles(sf::PrimitiveType::Triangles);
|
||||||
|
/// triangles.create(vertices.size());
|
||||||
|
/// triangles.update(vertices.data());
|
||||||
|
/// ...
|
||||||
|
/// window.draw(triangles);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::Vertex`, `sf::VertexArray`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,357 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Graphics/Rect.hpp>
|
||||||
|
#include <SFML/Graphics/Transform.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/Angle.hpp>
|
||||||
|
#include <SFML/System/Vector2.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief 2D camera that defines what region is shown on screen
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_GRAPHICS_API View
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// This constructor creates a default view of (0, 0, 1000, 1000)
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
View() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the view from a rectangle
|
||||||
|
///
|
||||||
|
/// \param rectangle Rectangle defining the zone to display
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit View(const FloatRect& rectangle);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the view from its center and size
|
||||||
|
///
|
||||||
|
/// \param center Center of the zone to display
|
||||||
|
/// \param size Size of zone to display
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
View(Vector2f center, Vector2f size);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the center of the view
|
||||||
|
///
|
||||||
|
/// \param center New center
|
||||||
|
///
|
||||||
|
/// \see `setSize`, `getCenter`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setCenter(Vector2f center);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the size of the view
|
||||||
|
///
|
||||||
|
/// \param size New size
|
||||||
|
///
|
||||||
|
/// \see `setCenter`, `getCenter`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setSize(Vector2f size);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the orientation of the view
|
||||||
|
///
|
||||||
|
/// The default rotation of a view is 0 degree.
|
||||||
|
///
|
||||||
|
/// \param angle New angle
|
||||||
|
///
|
||||||
|
/// \see `getRotation`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setRotation(Angle angle);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the target viewport
|
||||||
|
///
|
||||||
|
/// The viewport is the rectangle into which the contents of the
|
||||||
|
/// view are displayed, expressed as a factor (between 0 and 1)
|
||||||
|
/// of the size of the RenderTarget to which the view is applied.
|
||||||
|
/// For example, a view which takes the left side of the target would
|
||||||
|
/// be defined with `view.setViewport(sf::FloatRect({0.f, 0.f}, {0.5f, 1.f}))`.
|
||||||
|
/// By default, a view has a viewport which covers the entire target.
|
||||||
|
///
|
||||||
|
/// \param viewport New viewport rectangle
|
||||||
|
///
|
||||||
|
/// \see `getViewport`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setViewport(const FloatRect& viewport);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the target scissor rectangle
|
||||||
|
///
|
||||||
|
/// The scissor rectangle, expressed as a factor (between 0 and 1) of
|
||||||
|
/// the RenderTarget, specifies the region of the RenderTarget whose
|
||||||
|
/// pixels are able to be modified by draw or clear operations.
|
||||||
|
/// Any pixels which lie outside of the scissor rectangle will
|
||||||
|
/// not be modified by draw or clear operations.
|
||||||
|
/// For example, a scissor rectangle which only allows modifications
|
||||||
|
/// to the right side of the target would be defined
|
||||||
|
/// with `view.setScissor(sf::FloatRect({0.5f, 0.f}, {0.5f, 1.f}))`.
|
||||||
|
/// By default, a view has a scissor rectangle which allows
|
||||||
|
/// modifications to the entire target. This is equivalent to
|
||||||
|
/// disabling the scissor test entirely. Passing the default
|
||||||
|
/// scissor rectangle to this function will also disable
|
||||||
|
/// scissor testing.
|
||||||
|
///
|
||||||
|
/// \param scissor New scissor rectangle
|
||||||
|
///
|
||||||
|
/// \see `getScissor`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setScissor(const FloatRect& scissor);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the center of the view
|
||||||
|
///
|
||||||
|
/// \return Center of the view
|
||||||
|
///
|
||||||
|
/// \see `getSize`, `setCenter`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Vector2f getCenter() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the size of the view
|
||||||
|
///
|
||||||
|
/// \return Size of the view
|
||||||
|
///
|
||||||
|
/// \see `getCenter`, `setSize`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Vector2f getSize() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the current orientation of the view
|
||||||
|
///
|
||||||
|
/// \return Rotation angle of the view
|
||||||
|
///
|
||||||
|
/// \see `setRotation`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Angle getRotation() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the target viewport rectangle of the view
|
||||||
|
///
|
||||||
|
/// \return Viewport rectangle, expressed as a factor of the target size
|
||||||
|
///
|
||||||
|
/// \see `setViewport`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const FloatRect& getViewport() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the scissor rectangle of the view
|
||||||
|
///
|
||||||
|
/// \return Scissor rectangle, expressed as a factor of the target size
|
||||||
|
///
|
||||||
|
/// \see `setScissor`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const FloatRect& getScissor() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move the view relative to its current position
|
||||||
|
///
|
||||||
|
/// \param offset Move offset
|
||||||
|
///
|
||||||
|
/// \see `setCenter`, `rotate`, `zoom`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void move(Vector2f offset);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Rotate the view relative to its current orientation
|
||||||
|
///
|
||||||
|
/// \param angle Angle to rotate
|
||||||
|
///
|
||||||
|
/// \see `setRotation`, `move`, `zoom`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void rotate(Angle angle);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Resize the view rectangle relative to its current size
|
||||||
|
///
|
||||||
|
/// Resizing the view simulates a zoom, as the zone displayed on
|
||||||
|
/// screen grows or shrinks.
|
||||||
|
/// \a factor is a multiplier:
|
||||||
|
/// \li 1 keeps the size unchanged
|
||||||
|
/// \li > 1 makes the view bigger (objects appear smaller)
|
||||||
|
/// \li < 1 makes the view smaller (objects appear bigger)
|
||||||
|
///
|
||||||
|
/// \param factor Zoom factor to apply
|
||||||
|
///
|
||||||
|
/// \see `setSize`, `move`, `rotate`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void zoom(float factor);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the projection transform of the view
|
||||||
|
///
|
||||||
|
/// This function is meant for internal use only.
|
||||||
|
///
|
||||||
|
/// \return Projection transform defining the view
|
||||||
|
///
|
||||||
|
/// \see `getInverseTransform`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const Transform& getTransform() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the inverse projection transform of the view
|
||||||
|
///
|
||||||
|
/// This function is meant for internal use only.
|
||||||
|
///
|
||||||
|
/// \return Inverse of the projection transform defining the view
|
||||||
|
///
|
||||||
|
/// \see `getTransform`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const Transform& getInverseTransform() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Vector2f m_center{500, 500}; //!< Center of the view, in scene coordinates
|
||||||
|
Vector2f m_size{1000, 1000}; //!< Size of the view, in scene coordinates
|
||||||
|
Angle m_rotation; //!< Angle of rotation of the view rectangle
|
||||||
|
FloatRect m_viewport{{0, 0}, {1, 1}}; //!< Viewport rectangle, expressed as a factor of the render-target's size
|
||||||
|
FloatRect m_scissor{{0, 0}, {1, 1}}; //!< Scissor rectangle, expressed as a factor of the render-target's size
|
||||||
|
mutable Transform m_transform; //!< Precomputed projection transform corresponding to the view
|
||||||
|
mutable Transform m_inverseTransform; //!< Precomputed inverse projection transform corresponding to the view
|
||||||
|
mutable bool m_transformUpdated{}; //!< Internal state telling if the transform needs to be updated
|
||||||
|
mutable bool m_invTransformUpdated{}; //!< Internal state telling if the inverse transform needs to be updated
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::View
|
||||||
|
/// \ingroup graphics
|
||||||
|
///
|
||||||
|
/// `sf::View` defines a camera in the 2D scene. This is a
|
||||||
|
/// very powerful concept: you can scroll, rotate or zoom
|
||||||
|
/// the entire scene without altering the way that your
|
||||||
|
/// drawable objects are drawn.
|
||||||
|
///
|
||||||
|
/// A view is composed of a source rectangle, which defines
|
||||||
|
/// what part of the 2D scene is shown, and a target viewport,
|
||||||
|
/// which defines where the contents of the source rectangle
|
||||||
|
/// will be displayed on the render target (window or texture).
|
||||||
|
///
|
||||||
|
/// The viewport allows to map the scene to a custom part
|
||||||
|
/// of the render target, and can be used for split-screen
|
||||||
|
/// or for displaying a minimap, for example. If the source
|
||||||
|
/// rectangle doesn't have the same size as the viewport, its
|
||||||
|
/// contents will be stretched to fit in.
|
||||||
|
///
|
||||||
|
/// The scissor rectangle allows for specifying regions of the
|
||||||
|
/// render target to which modifications can be made by draw
|
||||||
|
/// and clear operations. Only pixels that are within the region
|
||||||
|
/// will be able to be modified. Pixels outside of the region will
|
||||||
|
/// not be modified by draw or clear operations.
|
||||||
|
///
|
||||||
|
/// Certain effects can be created by either using the viewport or
|
||||||
|
/// scissor rectangle. While the results appear identical, there
|
||||||
|
/// can be times where one method should be preferred over the other.
|
||||||
|
/// Viewport transformations are applied during the vertex processing
|
||||||
|
/// stage of the graphics pipeline, before the primitives are
|
||||||
|
/// rasterized into fragments for fragment processing. Since
|
||||||
|
/// viewport processing has to be performed and cannot be disabled,
|
||||||
|
/// effects that are performed using the viewport transform are
|
||||||
|
/// basically free performance-wise. Scissor testing is performed in
|
||||||
|
/// the per-sample processing stage of the graphics pipeline, after
|
||||||
|
/// fragment processing has been performed. Because per-sample
|
||||||
|
/// processing is performed at the last stage of the pipeline,
|
||||||
|
/// fragments that are discarded at this stage will cause the
|
||||||
|
/// highest waste of GPU resources compared to any method that
|
||||||
|
/// would have discarded vertices or fragments earlier in the
|
||||||
|
/// pipeline. There are situations in which scissor testing has
|
||||||
|
/// to be used to control whether fragments are discarded or not.
|
||||||
|
/// An example of such a situation is when performing the viewport
|
||||||
|
/// transform on vertices is necessary but a subset of the generated
|
||||||
|
/// fragments should not have an effect on the stencil buffer or
|
||||||
|
/// blend with the color buffer.
|
||||||
|
//
|
||||||
|
/// To apply a view, you have to assign it to the render target.
|
||||||
|
/// Then, objects drawn in this render target will be
|
||||||
|
/// affected by the view until you use another view.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// sf::RenderWindow window;
|
||||||
|
///
|
||||||
|
/// // Initialize the view to a rectangle located at (100, 100) and with a size of 400x200
|
||||||
|
/// sf::View view(sf::FloatRect({100, 100}, {400, 200}));
|
||||||
|
///
|
||||||
|
/// // Rotate it by 45 degrees
|
||||||
|
/// view.rotate(sf::degrees(45));
|
||||||
|
///
|
||||||
|
/// // Set its target viewport to be half of the window
|
||||||
|
/// view.setViewport(sf::FloatRect({0.f, 0.f}, {0.5f, 1.f}));
|
||||||
|
///
|
||||||
|
/// // Apply it
|
||||||
|
/// window.setView(view);
|
||||||
|
///
|
||||||
|
/// // Render stuff
|
||||||
|
/// window.draw(someSprite);
|
||||||
|
///
|
||||||
|
/// // Set the default view back
|
||||||
|
/// window.setView(window.getDefaultView());
|
||||||
|
///
|
||||||
|
/// // Render stuff not affected by the view
|
||||||
|
/// window.draw(someText);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// See also the note on coordinates and undistorted rendering in `sf::Transformable`.
|
||||||
|
///
|
||||||
|
/// \see `sf::RenderWindow`, `sf::RenderTexture`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Config.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(SFML_SYSTEM_IOS)
|
||||||
|
|
||||||
|
// On iOS, we have no choice but to have our own main,
|
||||||
|
// so we need to rename the user one and call it later
|
||||||
|
#define main sfmlMain
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <SFML/Network/Ftp.hpp>
|
||||||
|
#include <SFML/Network/Http.hpp>
|
||||||
|
#include <SFML/Network/IpAddress.hpp>
|
||||||
|
#include <SFML/Network/Packet.hpp>
|
||||||
|
#include <SFML/Network/Socket.hpp>
|
||||||
|
#include <SFML/Network/SocketHandle.hpp>
|
||||||
|
#include <SFML/Network/SocketSelector.hpp>
|
||||||
|
#include <SFML/Network/TcpListener.hpp>
|
||||||
|
#include <SFML/Network/TcpSocket.hpp>
|
||||||
|
#include <SFML/Network/UdpSocket.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \defgroup network Network module
|
||||||
|
///
|
||||||
|
/// Socket-based communication, utilities and higher-level
|
||||||
|
/// network protocols (HTTP, FTP).
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Config.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Portable import / export macros
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#if defined(SFML_NETWORK_EXPORTS)
|
||||||
|
|
||||||
|
#define SFML_NETWORK_API SFML_API_EXPORT
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define SFML_NETWORK_API SFML_API_IMPORT
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,629 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Network/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Network/TcpSocket.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/Time.hpp>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class IpAddress;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief A FTP client
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_NETWORK_API Ftp
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Enumeration of transfer modes
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
enum class TransferMode
|
||||||
|
{
|
||||||
|
Binary, //!< Binary mode (file is transferred as a sequence of bytes)
|
||||||
|
Ascii, //!< Text mode using ASCII encoding
|
||||||
|
Ebcdic //!< Text mode using EBCDIC encoding
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief FTP response
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_NETWORK_API Response
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Status codes possibly returned by a FTP response
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
enum class Status
|
||||||
|
{
|
||||||
|
// 1xx: the requested action is being initiated,
|
||||||
|
// expect another reply before proceeding with a new command
|
||||||
|
RestartMarkerReply = 110, //!< Restart marker reply
|
||||||
|
ServiceReadySoon = 120, //!< Service ready in N minutes
|
||||||
|
DataConnectionAlreadyOpened = 125, //!< Data connection already opened, transfer starting
|
||||||
|
OpeningDataConnection = 150, //!< File status ok, about to open data connection
|
||||||
|
|
||||||
|
// 2xx: the requested action has been successfully completed
|
||||||
|
Ok = 200, //!< Command ok
|
||||||
|
PointlessCommand = 202, //!< Command not implemented
|
||||||
|
SystemStatus = 211, //!< System status, or system help reply
|
||||||
|
DirectoryStatus = 212, //!< Directory status
|
||||||
|
FileStatus = 213, //!< File status
|
||||||
|
HelpMessage = 214, //!< Help message
|
||||||
|
SystemType = 215, //!< NAME system type, where NAME is an official system name from the list in the Assigned Numbers document
|
||||||
|
ServiceReady = 220, //!< Service ready for new user
|
||||||
|
ClosingConnection = 221, //!< Service closing control connection
|
||||||
|
DataConnectionOpened = 225, //!< Data connection open, no transfer in progress
|
||||||
|
ClosingDataConnection = 226, //!< Closing data connection, requested file action successful
|
||||||
|
EnteringPassiveMode = 227, //!< Entering passive mode
|
||||||
|
LoggedIn = 230, //!< User logged in, proceed. Logged out if appropriate
|
||||||
|
FileActionOk = 250, //!< Requested file action ok
|
||||||
|
DirectoryOk = 257, //!< PATHNAME created
|
||||||
|
|
||||||
|
// 3xx: the command has been accepted, but the requested action
|
||||||
|
// is dormant, pending receipt of further information
|
||||||
|
NeedPassword = 331, //!< User name ok, need password
|
||||||
|
NeedAccountToLogIn = 332, //!< Need account for login
|
||||||
|
NeedInformation = 350, //!< Requested file action pending further information
|
||||||
|
|
||||||
|
// 4xx: the command was not accepted and the requested action did not take place,
|
||||||
|
// but the error condition is temporary and the action may be requested again
|
||||||
|
ServiceUnavailable = 421, //!< Service not available, closing control connection
|
||||||
|
DataConnectionUnavailable = 425, //!< Can't open data connection
|
||||||
|
TransferAborted = 426, //!< Connection closed, transfer aborted
|
||||||
|
FileActionAborted = 450, //!< Requested file action not taken
|
||||||
|
LocalError = 451, //!< Requested action aborted, local error in processing
|
||||||
|
InsufficientStorageSpace = 452, //!< Requested action not taken; insufficient storage space in system, file unavailable
|
||||||
|
|
||||||
|
// 5xx: the command was not accepted and
|
||||||
|
// the requested action did not take place
|
||||||
|
CommandUnknown = 500, //!< Syntax error, command unrecognized
|
||||||
|
ParametersUnknown = 501, //!< Syntax error in parameters or arguments
|
||||||
|
CommandNotImplemented = 502, //!< Command not implemented
|
||||||
|
BadCommandSequence = 503, //!< Bad sequence of commands
|
||||||
|
ParameterNotImplemented = 504, //!< Command not implemented for that parameter
|
||||||
|
NotLoggedIn = 530, //!< Not logged in
|
||||||
|
NeedAccountToStore = 532, //!< Need account for storing files
|
||||||
|
FileUnavailable = 550, //!< Requested action not taken, file unavailable
|
||||||
|
PageTypeUnknown = 551, //!< Requested action aborted, page type unknown
|
||||||
|
NotEnoughMemory = 552, //!< Requested file action aborted, exceeded storage allocation
|
||||||
|
FilenameNotAllowed = 553, //!< Requested action not taken, file name not allowed
|
||||||
|
|
||||||
|
// 10xx: SFML custom codes
|
||||||
|
InvalidResponse = 1000, //!< Not part of the FTP standard, generated by SFML when a received response cannot be parsed
|
||||||
|
ConnectionFailed = 1001, //!< Not part of the FTP standard, generated by SFML when the low-level socket connection with the server fails
|
||||||
|
ConnectionClosed = 1002, //!< Not part of the FTP standard, generated by SFML when the low-level socket connection is unexpectedly closed
|
||||||
|
InvalidFile = 1003 //!< Not part of the FTP standard, generated by SFML when a local file cannot be read or written
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// This constructor is used by the FTP client to build
|
||||||
|
/// the response.
|
||||||
|
///
|
||||||
|
/// \param code Response status code
|
||||||
|
/// \param message Response message
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit Response(Status code = Status::InvalidResponse, std::string message = "");
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Check if the status code means a success
|
||||||
|
///
|
||||||
|
/// This function is defined for convenience, it is
|
||||||
|
/// equivalent to testing if the status code is < 400.
|
||||||
|
///
|
||||||
|
/// \return `true` if the status is a success, `false` if it is a failure
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool isOk() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the status code of the response
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Status getStatus() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the full message contained in the response
|
||||||
|
///
|
||||||
|
/// \return The response message
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const std::string& getMessage() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Status m_status; //!< Status code returned from the server
|
||||||
|
std::string m_message; //!< Last message received from the server
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Specialization of FTP response returning a directory
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_NETWORK_API DirectoryResponse : public Response
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// \param response Source response
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
DirectoryResponse(const Response& response);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the directory returned in the response
|
||||||
|
///
|
||||||
|
/// \return Directory name
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const std::filesystem::path& getDirectory() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::filesystem::path m_directory; //!< Directory extracted from the response message
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Specialization of FTP response returning a
|
||||||
|
/// file name listing
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_NETWORK_API ListingResponse : public Response
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// \param response Source response
|
||||||
|
/// \param data Data containing the raw listing
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
ListingResponse(const Response& response, const std::string& data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Return the array of directory/file names
|
||||||
|
///
|
||||||
|
/// \return Array containing the requested listing
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const std::vector<std::string>& getListing() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::vector<std::string> m_listing; //!< Directory/file names extracted from the data
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Ftp() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Destructor
|
||||||
|
///
|
||||||
|
/// Automatically closes the connection with the server if
|
||||||
|
/// it is still opened.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
~Ftp();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Deleted copy constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Ftp(const Ftp&) = delete;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Deleted copy assignment
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Ftp& operator=(const Ftp&) = delete;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Connect to the specified FTP server
|
||||||
|
///
|
||||||
|
/// The port has a default value of 21, which is the standard
|
||||||
|
/// port used by the FTP protocol. You shouldn't use a different
|
||||||
|
/// value, unless you really know what you do.
|
||||||
|
/// This function tries to connect to the server so it may take
|
||||||
|
/// a while to complete, especially if the server is not
|
||||||
|
/// reachable. To avoid blocking your application for too long,
|
||||||
|
/// you can use a timeout. The default value, `Time::Zero`, means that the
|
||||||
|
/// system timeout will be used (which is usually pretty long).
|
||||||
|
///
|
||||||
|
/// \param server Name or address of the FTP server to connect to
|
||||||
|
/// \param port Port used for the connection
|
||||||
|
/// \param timeout Maximum time to wait
|
||||||
|
///
|
||||||
|
/// \return Server response to the request
|
||||||
|
///
|
||||||
|
/// \see `disconnect`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Response connect(IpAddress server, unsigned short port = 21, Time timeout = Time::Zero);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Close the connection with the server
|
||||||
|
///
|
||||||
|
/// \return Server response to the request
|
||||||
|
///
|
||||||
|
/// \see `connect`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Response disconnect();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Log in using an anonymous account
|
||||||
|
///
|
||||||
|
/// Logging in is mandatory after connecting to the server.
|
||||||
|
/// Users that are not logged in cannot perform any operation.
|
||||||
|
///
|
||||||
|
/// \return Server response to the request
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Response login();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Log in using a username and a password
|
||||||
|
///
|
||||||
|
/// Logging in is mandatory after connecting to the server.
|
||||||
|
/// Users that are not logged in cannot perform any operation.
|
||||||
|
///
|
||||||
|
/// \param name User name
|
||||||
|
/// \param password Password
|
||||||
|
///
|
||||||
|
/// \return Server response to the request
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Response login(const std::string& name, const std::string& password);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Send a null command to keep the connection alive
|
||||||
|
///
|
||||||
|
/// This command is useful because the server may close the
|
||||||
|
/// connection automatically if no command is sent.
|
||||||
|
///
|
||||||
|
/// \return Server response to the request
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Response keepAlive();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the current working directory
|
||||||
|
///
|
||||||
|
/// The working directory is the root path for subsequent
|
||||||
|
/// operations involving directories and/or filenames.
|
||||||
|
///
|
||||||
|
/// \return Server response to the request
|
||||||
|
///
|
||||||
|
/// \see `getDirectoryListing`, `changeDirectory`, `parentDirectory`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] DirectoryResponse getWorkingDirectory();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the contents of the given directory
|
||||||
|
///
|
||||||
|
/// This function retrieves the sub-directories and files
|
||||||
|
/// contained in the given directory. It is not recursive.
|
||||||
|
/// The `directory` parameter is relative to the current
|
||||||
|
/// working directory.
|
||||||
|
///
|
||||||
|
/// \param directory Directory to list
|
||||||
|
///
|
||||||
|
/// \return Server response to the request
|
||||||
|
///
|
||||||
|
/// \see `getWorkingDirectory`, `changeDirectory`, `parentDirectory`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] ListingResponse getDirectoryListing(const std::string& directory = "");
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Change the current working directory
|
||||||
|
///
|
||||||
|
/// The new directory must be relative to the current one.
|
||||||
|
///
|
||||||
|
/// \param directory New working directory
|
||||||
|
///
|
||||||
|
/// \return Server response to the request
|
||||||
|
///
|
||||||
|
/// \see `getWorkingDirectory`, `getDirectoryListing`, `parentDirectory`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Response changeDirectory(const std::string& directory);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Go to the parent directory of the current one
|
||||||
|
///
|
||||||
|
/// \return Server response to the request
|
||||||
|
///
|
||||||
|
/// \see `getWorkingDirectory`, `getDirectoryListing`, `changeDirectory`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Response parentDirectory();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Create a new directory
|
||||||
|
///
|
||||||
|
/// The new directory is created as a child of the current
|
||||||
|
/// working directory.
|
||||||
|
///
|
||||||
|
/// \param name Name of the directory to create
|
||||||
|
///
|
||||||
|
/// \return Server response to the request
|
||||||
|
///
|
||||||
|
/// \see `deleteDirectory`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Response createDirectory(const std::string& name);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Remove an existing directory
|
||||||
|
///
|
||||||
|
/// The directory to remove must be relative to the
|
||||||
|
/// current working directory.
|
||||||
|
/// Use this function with caution, the directory will
|
||||||
|
/// be removed permanently!
|
||||||
|
///
|
||||||
|
/// \param name Name of the directory to remove
|
||||||
|
///
|
||||||
|
/// \return Server response to the request
|
||||||
|
///
|
||||||
|
/// \see `createDirectory`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Response deleteDirectory(const std::string& name);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Rename an existing file
|
||||||
|
///
|
||||||
|
/// The file names must be relative to the current working
|
||||||
|
/// directory.
|
||||||
|
///
|
||||||
|
/// \param file File to rename
|
||||||
|
/// \param newName New name of the file
|
||||||
|
///
|
||||||
|
/// \return Server response to the request
|
||||||
|
///
|
||||||
|
/// \see `deleteFile`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Response renameFile(const std::filesystem::path& file, const std::filesystem::path& newName);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Remove an existing file
|
||||||
|
///
|
||||||
|
/// The file name must be relative to the current working
|
||||||
|
/// directory.
|
||||||
|
/// Use this function with caution, the file will be
|
||||||
|
/// removed permanently!
|
||||||
|
///
|
||||||
|
/// \param name File to remove
|
||||||
|
///
|
||||||
|
/// \return Server response to the request
|
||||||
|
///
|
||||||
|
/// \see `renameFile`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Response deleteFile(const std::filesystem::path& name);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Download a file from the server
|
||||||
|
///
|
||||||
|
/// The file name of the distant file is relative to the
|
||||||
|
/// current working directory of the server, and the local
|
||||||
|
/// destination path is relative to the current directory
|
||||||
|
/// of your application.
|
||||||
|
/// If a file with the same file name as the distant file
|
||||||
|
/// already exists in the local destination path, it will
|
||||||
|
/// be overwritten.
|
||||||
|
///
|
||||||
|
/// \param remoteFile File name of the distant file to download
|
||||||
|
/// \param localPath The directory in which to put the file on the local computer
|
||||||
|
/// \param mode Transfer mode
|
||||||
|
///
|
||||||
|
/// \return Server response to the request
|
||||||
|
///
|
||||||
|
/// \see `upload`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Response download(const std::filesystem::path& remoteFile,
|
||||||
|
const std::filesystem::path& localPath,
|
||||||
|
TransferMode mode = TransferMode::Binary);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Upload a file to the server
|
||||||
|
///
|
||||||
|
/// The name of the local file is relative to the current
|
||||||
|
/// working directory of your application, and the
|
||||||
|
/// remote path is relative to the current directory of the
|
||||||
|
/// FTP server.
|
||||||
|
///
|
||||||
|
/// The append parameter controls whether the remote file is
|
||||||
|
/// appended to or overwritten if it already exists.
|
||||||
|
///
|
||||||
|
/// \param localFile Path of the local file to upload
|
||||||
|
/// \param remotePath The directory in which to put the file on the server
|
||||||
|
/// \param mode Transfer mode
|
||||||
|
/// \param append Pass `true` to append to or `false` to overwrite the remote file if it already exists
|
||||||
|
///
|
||||||
|
/// \return Server response to the request
|
||||||
|
///
|
||||||
|
/// \see `download`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Response upload(const std::filesystem::path& localFile,
|
||||||
|
const std::filesystem::path& remotePath,
|
||||||
|
TransferMode mode = TransferMode::Binary,
|
||||||
|
bool append = false);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Send a command to the FTP server
|
||||||
|
///
|
||||||
|
/// While the most often used commands are provided as member
|
||||||
|
/// functions in the `sf::Ftp` class, this method can be used
|
||||||
|
/// to send any FTP command to the server. If the command
|
||||||
|
/// requires one or more parameters, they can be specified
|
||||||
|
/// in `parameter`. If the server returns information, you
|
||||||
|
/// can extract it from the response using `Response::getMessage()`.
|
||||||
|
///
|
||||||
|
/// \param command Command to send
|
||||||
|
/// \param parameter Command parameter
|
||||||
|
///
|
||||||
|
/// \return Server response to the request
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Response sendCommand(const std::string& command, const std::string& parameter = "");
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Receive a response from the server
|
||||||
|
///
|
||||||
|
/// This function must be called after each call to
|
||||||
|
/// `sendCommand` that expects a response.
|
||||||
|
///
|
||||||
|
/// \return Server response to the request
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Response getResponse();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Utility class for exchanging data with the server
|
||||||
|
/// on the data channel
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class DataChannel;
|
||||||
|
|
||||||
|
friend class DataChannel;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
TcpSocket m_commandSocket; //!< Socket holding the control connection with the server
|
||||||
|
std::string m_receiveBuffer; //!< Received command data that is yet to be processed
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::Ftp
|
||||||
|
/// \ingroup network
|
||||||
|
///
|
||||||
|
/// `sf::Ftp` is a very simple FTP client that allows you
|
||||||
|
/// to communicate with a FTP server. The FTP protocol allows
|
||||||
|
/// you to manipulate a remote file system (list files,
|
||||||
|
/// upload, download, create, remove, ...).
|
||||||
|
///
|
||||||
|
/// Using the FTP client consists of 4 parts:
|
||||||
|
/// \li Connecting to the FTP server
|
||||||
|
/// \li Logging in (either as a registered user or anonymously)
|
||||||
|
/// \li Sending commands to the server
|
||||||
|
/// \li Disconnecting (this part can be done implicitly by the destructor)
|
||||||
|
///
|
||||||
|
/// Every command returns a FTP response, which contains the
|
||||||
|
/// status code as well as a message from the server. Some
|
||||||
|
/// commands such as `getWorkingDirectory()` and `getDirectoryListing()`
|
||||||
|
/// return additional data, and use a class derived from
|
||||||
|
/// `sf::Ftp::Response` to provide this data. The most often used
|
||||||
|
/// commands are directly provided as member functions, but it is
|
||||||
|
/// also possible to use specific commands with the `sendCommand()` function.
|
||||||
|
///
|
||||||
|
/// Note that response statuses >= 1000 are not part of the FTP standard,
|
||||||
|
/// they are generated by SFML when an internal error occurs.
|
||||||
|
///
|
||||||
|
/// All commands, especially upload and download, may take some
|
||||||
|
/// time to complete. This is important to know if you don't want
|
||||||
|
/// to block your application while the server is completing
|
||||||
|
/// the task.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// // Create a new FTP client
|
||||||
|
/// sf::Ftp ftp;
|
||||||
|
///
|
||||||
|
/// // Connect to the server
|
||||||
|
/// sf::Ftp::Response response = ftp.connect("ftp://ftp.myserver.com");
|
||||||
|
/// if (response.isOk())
|
||||||
|
/// std::cout << "Connected" << std::endl;
|
||||||
|
///
|
||||||
|
/// // Log in
|
||||||
|
/// response = ftp.login("laurent", "dF6Zm89D");
|
||||||
|
/// if (response.isOk())
|
||||||
|
/// std::cout << "Logged in" << std::endl;
|
||||||
|
///
|
||||||
|
/// // Print the working directory
|
||||||
|
/// sf::Ftp::DirectoryResponse directory = ftp.getWorkingDirectory();
|
||||||
|
/// if (directory.isOk())
|
||||||
|
/// std::cout << "Working directory: " << directory.getDirectory() << std::endl;
|
||||||
|
///
|
||||||
|
/// // Create a new directory
|
||||||
|
/// response = ftp.createDirectory("files");
|
||||||
|
/// if (response.isOk())
|
||||||
|
/// std::cout << "Created new directory" << std::endl;
|
||||||
|
///
|
||||||
|
/// // Upload a file to this new directory
|
||||||
|
/// response = ftp.upload("local-path/file.txt", "files", sf::Ftp::TransferMode::Ascii);
|
||||||
|
/// if (response.isOk())
|
||||||
|
/// std::cout << "File uploaded" << std::endl;
|
||||||
|
///
|
||||||
|
/// // Send specific commands (here: FEAT to list supported FTP features)
|
||||||
|
/// response = ftp.sendCommand("FEAT");
|
||||||
|
/// if (response.isOk())
|
||||||
|
/// std::cout << "Feature list:\n" << response.getMessage() << std::endl;
|
||||||
|
///
|
||||||
|
/// // Disconnect from the server (optional)
|
||||||
|
/// ftp.disconnect();
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,480 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Network/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Network/IpAddress.hpp>
|
||||||
|
#include <SFML/Network/TcpSocket.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/Time.hpp>
|
||||||
|
|
||||||
|
#include <iosfwd>
|
||||||
|
#include <map>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief A HTTP client
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_NETWORK_API Http
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief HTTP request
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_NETWORK_API Request
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Enumerate the available HTTP methods for a request
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
enum class Method
|
||||||
|
{
|
||||||
|
Get, //!< Request in get mode, standard method to retrieve a page
|
||||||
|
Post, //!< Request in post mode, usually to send data to a page
|
||||||
|
Head, //!< Request a page's header only
|
||||||
|
Put, //!< Request in put mode, useful for a REST API
|
||||||
|
Delete //!< Request in delete mode, useful for a REST API
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// This constructor creates a GET request, with the root
|
||||||
|
/// URI ("/") and an empty body.
|
||||||
|
///
|
||||||
|
/// \param uri Target URI
|
||||||
|
/// \param method Method to use for the request
|
||||||
|
/// \param body Content of the request's body
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Request(const std::string& uri = "/", Method method = Method::Get, const std::string& body = "");
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the value of a field
|
||||||
|
///
|
||||||
|
/// The field is created if it doesn't exist. The name of
|
||||||
|
/// the field is case-insensitive.
|
||||||
|
/// By default, a request doesn't contain any field (but the
|
||||||
|
/// mandatory fields are added later by the HTTP client when
|
||||||
|
/// sending the request).
|
||||||
|
///
|
||||||
|
/// \param field Name of the field to set
|
||||||
|
/// \param value Value of the field
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setField(const std::string& field, const std::string& value);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the request method
|
||||||
|
///
|
||||||
|
/// See the Method enumeration for a complete list of all
|
||||||
|
/// the available methods.
|
||||||
|
/// The method is `Http::Request::Method::Get` by default.
|
||||||
|
///
|
||||||
|
/// \param method Method to use for the request
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setMethod(Method method);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the requested URI
|
||||||
|
///
|
||||||
|
/// The URI is the resource (usually a web page or a file)
|
||||||
|
/// that you want to get or post.
|
||||||
|
/// The URI is "/" (the root page) by default.
|
||||||
|
///
|
||||||
|
/// \param uri URI to request, relative to the host
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setUri(const std::string& uri);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the HTTP version for the request
|
||||||
|
///
|
||||||
|
/// The HTTP version is 1.0 by default.
|
||||||
|
///
|
||||||
|
/// \param major Major HTTP version number
|
||||||
|
/// \param minor Minor HTTP version number
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setHttpVersion(unsigned int major, unsigned int minor);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the body of the request
|
||||||
|
///
|
||||||
|
/// The body of a request is optional and only makes sense
|
||||||
|
/// for POST requests. It is ignored for all other methods.
|
||||||
|
/// The body is empty by default.
|
||||||
|
///
|
||||||
|
/// \param body Content of the body
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setBody(const std::string& body);
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class Http;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Prepare the final request to send to the server
|
||||||
|
///
|
||||||
|
/// This is used internally by Http before sending the
|
||||||
|
/// request to the web server.
|
||||||
|
///
|
||||||
|
/// \return String containing the request, ready to be sent
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] std::string prepare() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Check if the request defines a field
|
||||||
|
///
|
||||||
|
/// This function uses case-insensitive comparisons.
|
||||||
|
///
|
||||||
|
/// \param field Name of the field to test
|
||||||
|
///
|
||||||
|
/// \return `true` if the field exists, `false` otherwise
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool hasField(const std::string& field) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Types
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
using FieldTable = std::map<std::string, std::string>; // Use an ordered map for predictable payloads
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
FieldTable m_fields; //!< Fields of the header associated to their value
|
||||||
|
Method m_method; //!< Method to use for the request
|
||||||
|
std::string m_uri; //!< Target URI of the request
|
||||||
|
unsigned int m_majorVersion{1}; //!< Major HTTP version
|
||||||
|
unsigned int m_minorVersion{}; //!< Minor HTTP version
|
||||||
|
std::string m_body; //!< Body of the request
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief HTTP response
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_NETWORK_API Response
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Enumerate all the valid status codes for a response
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
enum class Status
|
||||||
|
{
|
||||||
|
// 2xx: success
|
||||||
|
Ok = 200, //!< Most common code returned when operation was successful
|
||||||
|
Created = 201, //!< The resource has successfully been created
|
||||||
|
Accepted = 202, //!< The request has been accepted, but will be processed later by the server
|
||||||
|
NoContent = 204, //!< The server didn't send any data in return
|
||||||
|
ResetContent = 205, //!< The server informs the client that it should clear the view (form) that caused the request to be sent
|
||||||
|
PartialContent = 206, //!< The server has sent a part of the resource, as a response to a partial GET request
|
||||||
|
|
||||||
|
// 3xx: redirection
|
||||||
|
MultipleChoices = 300, //!< The requested page can be accessed from several locations
|
||||||
|
MovedPermanently = 301, //!< The requested page has permanently moved to a new location
|
||||||
|
MovedTemporarily = 302, //!< The requested page has temporarily moved to a new location
|
||||||
|
NotModified = 304, //!< For conditional requests, means the requested page hasn't changed and doesn't need to be refreshed
|
||||||
|
|
||||||
|
// 4xx: client error
|
||||||
|
BadRequest = 400, //!< The server couldn't understand the request (syntax error)
|
||||||
|
Unauthorized = 401, //!< The requested page needs an authentication to be accessed
|
||||||
|
Forbidden = 403, //!< The requested page cannot be accessed at all, even with authentication
|
||||||
|
NotFound = 404, //!< The requested page doesn't exist
|
||||||
|
RangeNotSatisfiable = 407, //!< The server can't satisfy the partial GET request (with a "Range" header field)
|
||||||
|
|
||||||
|
// 5xx: server error
|
||||||
|
InternalServerError = 500, //!< The server encountered an unexpected error
|
||||||
|
NotImplemented = 501, //!< The server doesn't implement a requested feature
|
||||||
|
BadGateway = 502, //!< The gateway server has received an error from the source server
|
||||||
|
ServiceNotAvailable = 503, //!< The server is temporarily unavailable (overloaded, in maintenance, ...)
|
||||||
|
GatewayTimeout = 504, //!< The gateway server couldn't receive a response from the source server
|
||||||
|
VersionNotSupported = 505, //!< The server doesn't support the requested HTTP version
|
||||||
|
|
||||||
|
// 10xx: SFML custom codes
|
||||||
|
InvalidResponse = 1000, //!< Response is not a valid HTTP one
|
||||||
|
ConnectionFailed = 1001 //!< Connection with server failed
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the value of a field
|
||||||
|
///
|
||||||
|
/// If the field `field` is not found in the response header,
|
||||||
|
/// the empty string is returned. This function uses
|
||||||
|
/// case-insensitive comparisons.
|
||||||
|
///
|
||||||
|
/// \param field Name of the field to get
|
||||||
|
///
|
||||||
|
/// \return Value of the field, or empty string if not found
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const std::string& getField(const std::string& field) const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the response status code
|
||||||
|
///
|
||||||
|
/// The status code should be the first thing to be checked
|
||||||
|
/// after receiving a response, it defines whether it is a
|
||||||
|
/// success, a failure or anything else (see the Status
|
||||||
|
/// enumeration).
|
||||||
|
///
|
||||||
|
/// \return Status code of the response
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Status getStatus() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the major HTTP version number of the response
|
||||||
|
///
|
||||||
|
/// \return Major HTTP version number
|
||||||
|
///
|
||||||
|
/// \see `getMinorHttpVersion`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] unsigned int getMajorHttpVersion() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the minor HTTP version number of the response
|
||||||
|
///
|
||||||
|
/// \return Minor HTTP version number
|
||||||
|
///
|
||||||
|
/// \see `getMajorHttpVersion`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] unsigned int getMinorHttpVersion() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the body of the response
|
||||||
|
///
|
||||||
|
/// The body of a response may contain:
|
||||||
|
/// \li the requested page (for GET requests)
|
||||||
|
/// \li a response from the server (for POST requests)
|
||||||
|
/// \li nothing (for HEAD requests)
|
||||||
|
/// \li an error message (in case of an error)
|
||||||
|
///
|
||||||
|
/// \return The response body
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const std::string& getBody() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class Http;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the header from a response string
|
||||||
|
///
|
||||||
|
/// This function is used by `Http` to build the response
|
||||||
|
/// of a request.
|
||||||
|
///
|
||||||
|
/// \param data Content of the response to parse
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void parse(const std::string& data);
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Read values passed in the answer header
|
||||||
|
///
|
||||||
|
/// This function is used by `Http` to extract values passed
|
||||||
|
/// in the response.
|
||||||
|
///
|
||||||
|
/// \param in String stream containing the header values
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void parseFields(std::istream& in);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Types
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
using FieldTable = std::map<std::string, std::string>; // Use an ordered map for predictable payloads
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
FieldTable m_fields; //!< Fields of the header
|
||||||
|
Status m_status{Status::ConnectionFailed}; //!< Status code
|
||||||
|
unsigned int m_majorVersion{}; //!< Major HTTP version
|
||||||
|
unsigned int m_minorVersion{}; //!< Minor HTTP version
|
||||||
|
std::string m_body; //!< Body of the response
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Http() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the HTTP client with the target host
|
||||||
|
///
|
||||||
|
/// This is equivalent to calling `setHost(host, port)`.
|
||||||
|
/// The port has a default value of 0, which means that the
|
||||||
|
/// HTTP client will use the right port according to the
|
||||||
|
/// protocol used (80 for HTTP). You should leave it like
|
||||||
|
/// this unless you really need a port other than the
|
||||||
|
/// standard one, or use an unknown protocol.
|
||||||
|
///
|
||||||
|
/// \param host Web server to connect to
|
||||||
|
/// \param port Port to use for connection
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Http(const std::string& host, unsigned short port = 0);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Deleted copy constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Http(const Http&) = delete;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Deleted copy assignment
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Http& operator=(const Http&) = delete;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the target host
|
||||||
|
///
|
||||||
|
/// This function just stores the host address and port, it
|
||||||
|
/// doesn't actually connect to it until you send a request.
|
||||||
|
/// The port has a default value of 0, which means that the
|
||||||
|
/// HTTP client will use the right port according to the
|
||||||
|
/// protocol used (80 for HTTP). You should leave it like
|
||||||
|
/// this unless you really need a port other than the
|
||||||
|
/// standard one, or use an unknown protocol.
|
||||||
|
///
|
||||||
|
/// \param host Web server to connect to
|
||||||
|
/// \param port Port to use for connection
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setHost(const std::string& host, unsigned short port = 0);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Send a HTTP request and return the server's response.
|
||||||
|
///
|
||||||
|
/// You must have a valid host before sending a request (see `setHost`).
|
||||||
|
/// Any missing mandatory header field in the request will be added
|
||||||
|
/// with an appropriate value.
|
||||||
|
/// Warning: this function waits for the server's response and may
|
||||||
|
/// not return instantly; use a thread if you don't want to block your
|
||||||
|
/// application, or use a timeout to limit the time to wait. A value
|
||||||
|
/// of `Time::Zero` means that the client will use the system default timeout
|
||||||
|
/// (which is usually pretty long).
|
||||||
|
///
|
||||||
|
/// \param request Request to send
|
||||||
|
/// \param timeout Maximum time to wait
|
||||||
|
///
|
||||||
|
/// \return Server's response
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Response sendRequest(const Request& request, Time timeout = Time::Zero);
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
TcpSocket m_connection; //!< Connection to the host
|
||||||
|
std::optional<IpAddress> m_host; //!< Web host address
|
||||||
|
std::string m_hostName; //!< Web host name
|
||||||
|
unsigned short m_port{}; //!< Port used for connection with host
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::Http
|
||||||
|
/// \ingroup network
|
||||||
|
///
|
||||||
|
/// `sf::Http` is a very simple HTTP client that allows you
|
||||||
|
/// to communicate with a web server. You can retrieve
|
||||||
|
/// web pages, send data to an interactive resource,
|
||||||
|
/// download a remote file, etc. The HTTPS protocol is
|
||||||
|
/// not supported.
|
||||||
|
///
|
||||||
|
/// The HTTP client is split into 3 classes:
|
||||||
|
/// \li `sf::Http::Request`
|
||||||
|
/// \li `sf::Http::Response`
|
||||||
|
/// \li `sf::Http`
|
||||||
|
///
|
||||||
|
/// `sf::Http::Request` builds the request that will be
|
||||||
|
/// sent to the server. A request is made of:
|
||||||
|
/// \li a method (what you want to do)
|
||||||
|
/// \li a target URI (usually the name of the web page or file)
|
||||||
|
/// \li one or more header fields (options that you can pass to the server)
|
||||||
|
/// \li an optional body (for POST requests)
|
||||||
|
///
|
||||||
|
/// `sf::Http::Response` parse the response from the web server
|
||||||
|
/// and provides getters to read them. The response contains:
|
||||||
|
/// \li a status code
|
||||||
|
/// \li header fields (that may be answers to the ones that you requested)
|
||||||
|
/// \li a body, which contains the contents of the requested resource
|
||||||
|
///
|
||||||
|
/// `sf::Http` provides a simple function, SendRequest, to send a
|
||||||
|
/// `sf::Http::Request` and return the corresponding `sf::Http::Response`
|
||||||
|
/// from the server.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// // Create a new HTTP client
|
||||||
|
/// sf::Http http;
|
||||||
|
///
|
||||||
|
/// // We'll work on http://www.sfml-dev.org
|
||||||
|
/// http.setHost("http://www.sfml-dev.org");
|
||||||
|
///
|
||||||
|
/// // Prepare a request to get the 'features.php' page
|
||||||
|
/// sf::Http::Request request("features.php");
|
||||||
|
///
|
||||||
|
/// // Send the request
|
||||||
|
/// sf::Http::Response response = http.sendRequest(request);
|
||||||
|
///
|
||||||
|
/// // Check the status code and display the result
|
||||||
|
/// sf::Http::Response::Status status = response.getStatus();
|
||||||
|
/// if (status == sf::Http::Response::Status::Ok)
|
||||||
|
/// {
|
||||||
|
/// std::cout << response.getBody() << std::endl;
|
||||||
|
/// }
|
||||||
|
/// else
|
||||||
|
/// {
|
||||||
|
/// std::cout << "Error " << status << std::endl;
|
||||||
|
/// }
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,297 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Network/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/Time.hpp>
|
||||||
|
|
||||||
|
#include <iosfwd>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Encapsulate an IPv4 network address
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_NETWORK_API IpAddress
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the address from a null-terminated string view
|
||||||
|
///
|
||||||
|
/// Here \a address can be either a decimal address
|
||||||
|
/// (ex: "192.168.1.56") or a network name (ex: "localhost").
|
||||||
|
///
|
||||||
|
/// \param address IP address or network name
|
||||||
|
///
|
||||||
|
/// \return Address if provided argument was valid, otherwise `std::nullopt`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] static std::optional<IpAddress> resolve(std::string_view address);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the address from 4 bytes
|
||||||
|
///
|
||||||
|
/// Calling `IpAddress(a, b, c, d)` is equivalent to calling
|
||||||
|
/// `IpAddress::resolve("a.b.c.d")`, but safer as it doesn't
|
||||||
|
/// have to parse a string to get the address components.
|
||||||
|
///
|
||||||
|
/// \param byte0 First byte of the address
|
||||||
|
/// \param byte1 Second byte of the address
|
||||||
|
/// \param byte2 Third byte of the address
|
||||||
|
/// \param byte3 Fourth byte of the address
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
IpAddress(std::uint8_t byte0, std::uint8_t byte1, std::uint8_t byte2, std::uint8_t byte3);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the address from a 32-bits integer
|
||||||
|
///
|
||||||
|
/// This constructor uses the internal representation of
|
||||||
|
/// the address directly. It should be used for optimization
|
||||||
|
/// purposes, and only if you got that representation from
|
||||||
|
/// `IpAddress::toInteger()`.
|
||||||
|
///
|
||||||
|
/// \param address 4 bytes of the address packed into a 32-bits integer
|
||||||
|
///
|
||||||
|
/// \see `toInteger`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit IpAddress(std::uint32_t address);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get a string representation of the address
|
||||||
|
///
|
||||||
|
/// The returned string is the decimal representation of the
|
||||||
|
/// IP address (like "192.168.1.56"), even if it was constructed
|
||||||
|
/// from a host name.
|
||||||
|
///
|
||||||
|
/// \return String representation of the address
|
||||||
|
///
|
||||||
|
/// \see `toInteger`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] std::string toString() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get an integer representation of the address
|
||||||
|
///
|
||||||
|
/// The returned number is the internal representation of the
|
||||||
|
/// address, and should be used for optimization purposes only
|
||||||
|
/// (like sending the address through a socket).
|
||||||
|
/// The integer produced by this function can then be converted
|
||||||
|
/// back to a `sf::IpAddress` with the proper constructor.
|
||||||
|
///
|
||||||
|
/// \return 32-bits unsigned integer representation of the address
|
||||||
|
///
|
||||||
|
/// \see `toString`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] std::uint32_t toInteger() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the computer's local address
|
||||||
|
///
|
||||||
|
/// The local address is the address of the computer from the
|
||||||
|
/// LAN point of view, i.e. something like 192.168.1.56. It is
|
||||||
|
/// meaningful only for communications over the local network.
|
||||||
|
/// Unlike getPublicAddress, this function is fast and may be
|
||||||
|
/// used safely anywhere.
|
||||||
|
///
|
||||||
|
/// \return Local IP address of the computer on success, `std::nullopt` otherwise
|
||||||
|
///
|
||||||
|
/// \see `getPublicAddress`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] static std::optional<IpAddress> getLocalAddress();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the computer's public address
|
||||||
|
///
|
||||||
|
/// The public address is the address of the computer from the
|
||||||
|
/// internet point of view, i.e. something like 89.54.1.169.
|
||||||
|
/// It is necessary for communications over the world wide web.
|
||||||
|
/// The only way to get a public address is to ask it to a
|
||||||
|
/// distant website; as a consequence, this function depends on
|
||||||
|
/// both your network connection and the server, and may be
|
||||||
|
/// very slow. You should use it as few as possible. Because
|
||||||
|
/// this function depends on the network connection and on a distant
|
||||||
|
/// server, you may use a time limit if you don't want your program
|
||||||
|
/// to be possibly stuck waiting in case there is a problem; this
|
||||||
|
/// limit is deactivated by default.
|
||||||
|
///
|
||||||
|
/// \param timeout Maximum time to wait
|
||||||
|
///
|
||||||
|
/// \return Public IP address of the computer on success, `std::nullopt` otherwise
|
||||||
|
///
|
||||||
|
/// \see `getLocalAddress`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] static std::optional<IpAddress> getPublicAddress(Time timeout = Time::Zero);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Static member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// NOLINTBEGIN(readability-identifier-naming)
|
||||||
|
static const IpAddress Any; //!< Value representing any address (0.0.0.0)
|
||||||
|
static const IpAddress LocalHost; //!< The "localhost" address (for connecting a computer to itself locally)
|
||||||
|
static const IpAddress Broadcast; //!< The "broadcast" address (for sending UDP messages to everyone on a local network)
|
||||||
|
// NOLINTEND(readability-identifier-naming)
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend SFML_NETWORK_API bool operator<(IpAddress left, IpAddress right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::uint32_t m_address; //!< Address stored as an unsigned 32 bit integer
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Overload of `operator==` to compare two IP addresses
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a IP address)
|
||||||
|
/// \param right Right operand (a IP address)
|
||||||
|
///
|
||||||
|
/// \return `true` if both addresses are equal
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] SFML_NETWORK_API bool operator==(IpAddress left, IpAddress right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Overload of `operator!=` to compare two IP addresses
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a IP address)
|
||||||
|
/// \param right Right operand (a IP address)
|
||||||
|
///
|
||||||
|
/// \return `true` if both addresses are different
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] SFML_NETWORK_API bool operator!=(IpAddress left, IpAddress right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Overload of `operator<` to compare two IP addresses
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a IP address)
|
||||||
|
/// \param right Right operand (a IP address)
|
||||||
|
///
|
||||||
|
/// \return `true` if `left` is lesser than `right`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] SFML_NETWORK_API bool operator<(IpAddress left, IpAddress right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Overload of `operator>` to compare two IP addresses
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a IP address)
|
||||||
|
/// \param right Right operand (a IP address)
|
||||||
|
///
|
||||||
|
/// \return `true` if `left` is greater than `right`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] SFML_NETWORK_API bool operator>(IpAddress left, IpAddress right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Overload of `operator<=` to compare two IP addresses
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a IP address)
|
||||||
|
/// \param right Right operand (a IP address)
|
||||||
|
///
|
||||||
|
/// \return `true` if \a left is lesser or equal than \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] SFML_NETWORK_API bool operator<=(IpAddress left, IpAddress right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Overload of `operator>=` to compare two IP addresses
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a IP address)
|
||||||
|
/// \param right Right operand (a IP address)
|
||||||
|
///
|
||||||
|
/// \return `true` if `left` is greater or equal than `right`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] SFML_NETWORK_API bool operator>=(IpAddress left, IpAddress right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Overload of `operator>>` to extract an IP address from an input stream
|
||||||
|
///
|
||||||
|
/// \param stream Input stream
|
||||||
|
/// \param address IP address to extract
|
||||||
|
///
|
||||||
|
/// \return Reference to the input stream
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_NETWORK_API std::istream& operator>>(std::istream& stream, std::optional<IpAddress>& address);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Overload of `operator<<` to print an IP address to an output stream
|
||||||
|
///
|
||||||
|
/// \param stream Output stream
|
||||||
|
/// \param address IP address to print
|
||||||
|
///
|
||||||
|
/// \return Reference to the output stream
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SFML_NETWORK_API std::ostream& operator<<(std::ostream& stream, IpAddress address);
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::IpAddress
|
||||||
|
/// \ingroup network
|
||||||
|
///
|
||||||
|
/// `sf::IpAddress` is a utility class for manipulating network
|
||||||
|
/// addresses. It provides a set a implicit constructors and
|
||||||
|
/// conversion functions to easily build or transform an IP
|
||||||
|
/// address from/to various representations.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// auto a2 = sf::IpAddress::resolve("127.0.0.1"); // the local host address
|
||||||
|
/// auto a3 = sf::IpAddress::Broadcast; // the broadcast address
|
||||||
|
/// sf::IpAddress a4(192, 168, 1, 56); // a local address
|
||||||
|
/// auto a5 = sf::IpAddress::resolve("my_computer"); // a local address created from a network name
|
||||||
|
/// auto a6 = sf::IpAddress::resolve("89.54.1.169"); // a distant address
|
||||||
|
/// auto a7 = sf::IpAddress::resolve("www.google.com"); // a distant address created from a network name
|
||||||
|
/// auto a8 = sf::IpAddress::getLocalAddress(); // my address on the local network
|
||||||
|
/// auto a9 = sf::IpAddress::getPublicAddress(); // my address on the internet
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// Note that `sf::IpAddress` currently doesn't support IPv6
|
||||||
|
/// nor other types of network addresses.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,552 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Network/Export.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class String;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Utility class to build blocks of data to transfer
|
||||||
|
/// over the network
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_NETWORK_API Packet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// Creates an empty packet.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Virtual destructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
virtual ~Packet() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Copy constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet(const Packet&) = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Copy assignment
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator=(const Packet&) = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet(Packet&&) noexcept = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move assignment
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator=(Packet&&) noexcept = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Append data to the end of the packet
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the sequence of bytes to append
|
||||||
|
/// \param sizeInBytes Number of bytes to append
|
||||||
|
///
|
||||||
|
/// \see `clear`
|
||||||
|
/// \see `getReadPosition`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void append(const void* data, std::size_t sizeInBytes);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the current reading position in the packet
|
||||||
|
///
|
||||||
|
/// The next read operation will read data from this position
|
||||||
|
///
|
||||||
|
/// \return The byte offset of the current read position
|
||||||
|
///
|
||||||
|
/// \see `append`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] std::size_t getReadPosition() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Clear the packet
|
||||||
|
///
|
||||||
|
/// After calling Clear, the packet is empty.
|
||||||
|
///
|
||||||
|
/// \see `append`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get a pointer to the data contained in the packet
|
||||||
|
///
|
||||||
|
/// Warning: the returned pointer may become invalid after
|
||||||
|
/// you append data to the packet, therefore it should never
|
||||||
|
/// be stored.
|
||||||
|
/// The return pointer is a `nullptr` if the packet is empty.
|
||||||
|
///
|
||||||
|
/// \return Pointer to the data
|
||||||
|
///
|
||||||
|
/// \see `getDataSize`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] const void* getData() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the size of the data contained in the packet
|
||||||
|
///
|
||||||
|
/// This function returns the number of bytes pointed to by
|
||||||
|
/// what `getData` returns.
|
||||||
|
///
|
||||||
|
/// \return Data size, in bytes
|
||||||
|
///
|
||||||
|
/// \see `getData`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] std::size_t getDataSize() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Tell if the reading position has reached the
|
||||||
|
/// end of the packet
|
||||||
|
///
|
||||||
|
/// This function is useful to know if there is some data
|
||||||
|
/// left to be read, without actually reading it.
|
||||||
|
///
|
||||||
|
/// \return `true` if all data was read, `false` otherwise
|
||||||
|
///
|
||||||
|
/// \see `operator` bool
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool endOfPacket() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Test the validity of the packet, for reading
|
||||||
|
///
|
||||||
|
/// This operator allows to test the packet as a boolean
|
||||||
|
/// variable, to check if a reading operation was successful.
|
||||||
|
///
|
||||||
|
/// A packet will be in an invalid state if it has no more
|
||||||
|
/// data to read.
|
||||||
|
///
|
||||||
|
/// This behavior is the same as standard C++ streams.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// float x;
|
||||||
|
/// packet >> x;
|
||||||
|
/// if (packet)
|
||||||
|
/// {
|
||||||
|
/// // ok, x was extracted successfully
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // -- or --
|
||||||
|
///
|
||||||
|
/// float x;
|
||||||
|
/// if (packet >> x)
|
||||||
|
/// {
|
||||||
|
/// // ok, x was extracted successfully
|
||||||
|
/// }
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// Don't focus on the return type, it's equivalent to bool but
|
||||||
|
/// it disallows unwanted implicit conversions to integer or
|
||||||
|
/// pointer types.
|
||||||
|
///
|
||||||
|
/// \return `true` if last data extraction from packet was successful
|
||||||
|
///
|
||||||
|
/// \see `endOfPacket`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit operator bool() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// Overload of `operator>>` to read data from the packet
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator>>(bool& data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator>>(std::int8_t& data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator>>(std::uint8_t& data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator>>(std::int16_t& data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator>>(std::uint16_t& data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator>>(std::int32_t& data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator>>(std::uint32_t& data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator>>(std::int64_t& data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator>>(std::uint64_t& data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator>>(float& data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator>>(double& data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator>>(char* data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator>>(std::string& data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator>>(wchar_t* data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator>>(std::wstring& data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator>>(String& data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// Overload of `operator<<` to write data into the packet
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator<<(bool data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator<<(std::int8_t data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator<<(std::uint8_t data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator<<(std::int16_t data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator<<(std::uint16_t data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator<<(std::int32_t data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator<<(std::uint32_t data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator<<(std::int64_t data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator<<(std::uint64_t data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator<<(float data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator<<(double data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator<<(const char* data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator<<(const std::string& data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator<<(const wchar_t* data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator<<(const std::wstring& data);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \overload
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Packet& operator<<(const String& data);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
friend class TcpSocket;
|
||||||
|
friend class UdpSocket;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Called before the packet is sent over the network
|
||||||
|
///
|
||||||
|
/// This function can be defined by derived classes to
|
||||||
|
/// transform the data before it is sent; this can be
|
||||||
|
/// used for compression, encryption, etc.
|
||||||
|
/// The function must return a pointer to the modified data,
|
||||||
|
/// as well as the number of bytes pointed.
|
||||||
|
/// The default implementation provides the packet's data
|
||||||
|
/// without transforming it.
|
||||||
|
///
|
||||||
|
/// \param size Variable to fill with the size of data to send
|
||||||
|
///
|
||||||
|
/// \return Pointer to the array of bytes to send
|
||||||
|
///
|
||||||
|
/// \see `onReceive`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
virtual const void* onSend(std::size_t& size);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Called after the packet is received over the network
|
||||||
|
///
|
||||||
|
/// This function can be defined by derived classes to
|
||||||
|
/// transform the data after it is received; this can be
|
||||||
|
/// used for decompression, decryption, etc.
|
||||||
|
/// The function receives a pointer to the received data,
|
||||||
|
/// and must fill the packet with the transformed bytes.
|
||||||
|
/// The default implementation fills the packet directly
|
||||||
|
/// without transforming the data.
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the received bytes
|
||||||
|
/// \param size Number of bytes
|
||||||
|
///
|
||||||
|
/// \see `onSend`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
virtual void onReceive(const void* data, std::size_t size);
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Check if the packet can extract a given number of bytes
|
||||||
|
///
|
||||||
|
/// This function updates accordingly the state of the packet.
|
||||||
|
///
|
||||||
|
/// \param size Size to check
|
||||||
|
///
|
||||||
|
/// \return `true` if \a size bytes can be read from the packet
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
bool checkSize(std::size_t size);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::vector<std::byte> m_data; //!< Data stored in the packet
|
||||||
|
std::size_t m_readPos{}; //!< Current reading position in the packet
|
||||||
|
std::size_t m_sendPos{}; //!< Current send position in the packet (for handling partial sends)
|
||||||
|
bool m_isValid{true}; //!< Reading state of the packet
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::Packet
|
||||||
|
/// \ingroup network
|
||||||
|
///
|
||||||
|
/// Packets provide a safe and easy way to serialize data,
|
||||||
|
/// in order to send it over the network using sockets
|
||||||
|
/// (`sf::TcpSocket`, `sf::UdpSocket`).
|
||||||
|
///
|
||||||
|
/// Packets solve 2 fundamental problems that arise when
|
||||||
|
/// transferring data over the network:
|
||||||
|
/// \li data is interpreted correctly according to the endianness
|
||||||
|
/// \li the bounds of the packet are preserved (one send == one receive)
|
||||||
|
///
|
||||||
|
/// The `sf::Packet` class provides both input and output modes.
|
||||||
|
/// It is designed to follow the behavior of standard C++ streams,
|
||||||
|
/// using operators >> and << to extract and insert data.
|
||||||
|
///
|
||||||
|
/// It is recommended to use only fixed-size types (like `std::int32_t`, etc.),
|
||||||
|
/// to avoid possible differences between the sender and the receiver.
|
||||||
|
/// Indeed, the native C++ types may have different sizes on two platforms
|
||||||
|
/// and your data may be corrupted if that happens.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// std::uint32_t x = 24;
|
||||||
|
/// std::string s = "hello";
|
||||||
|
/// double d = 5.89;
|
||||||
|
///
|
||||||
|
/// // Group the variables to send into a packet
|
||||||
|
/// sf::Packet packet;
|
||||||
|
/// packet << x << s << d;
|
||||||
|
///
|
||||||
|
/// // Send it over the network (socket is a valid sf::TcpSocket)
|
||||||
|
/// socket.send(packet);
|
||||||
|
///
|
||||||
|
/// -----------------------------------------------------------------
|
||||||
|
///
|
||||||
|
/// // Receive the packet at the other end
|
||||||
|
/// sf::Packet packet;
|
||||||
|
/// socket.receive(packet);
|
||||||
|
///
|
||||||
|
/// // Extract the variables contained in the packet
|
||||||
|
/// std::uint32_t x;
|
||||||
|
/// std::string s;
|
||||||
|
/// double d;
|
||||||
|
/// if (packet >> x >> s >> d)
|
||||||
|
/// {
|
||||||
|
/// // Data extracted successfully...
|
||||||
|
/// }
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// Packets have built-in `operator>>` and << overloads for
|
||||||
|
/// standard types:
|
||||||
|
/// \li `bool`
|
||||||
|
/// \li fixed-size integer types (`int[8|16|32]_t`, `uint[8|16|32]_t`)
|
||||||
|
/// \li floating point numbers (`float`, `double`)
|
||||||
|
/// \li string types (`char*`, `wchar_t*`, `std::string`, `std::wstring`, `sf::String`)
|
||||||
|
///
|
||||||
|
/// Like standard streams, it is also possible to define your own
|
||||||
|
/// overloads of operators >> and << in order to handle your
|
||||||
|
/// custom types.
|
||||||
|
///
|
||||||
|
/// \code
|
||||||
|
/// struct MyStruct
|
||||||
|
/// {
|
||||||
|
/// float number{};
|
||||||
|
/// std::int8_t integer{};
|
||||||
|
/// std::string str;
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// sf::Packet& operator <<(sf::Packet& packet, const MyStruct& m)
|
||||||
|
/// {
|
||||||
|
/// return packet << m.number << m.integer << m.str;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// sf::Packet& operator >>(sf::Packet& packet, MyStruct& m)
|
||||||
|
/// {
|
||||||
|
/// return packet >> m.number >> m.integer >> m.str;
|
||||||
|
/// }
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// Packets also provide an extra feature that allows to apply
|
||||||
|
/// custom transformations to the data before it is sent,
|
||||||
|
/// and after it is received. This is typically used to
|
||||||
|
/// handle automatic compression or encryption of the data.
|
||||||
|
/// This is achieved by inheriting from `sf::Packet`, and overriding
|
||||||
|
/// the onSend and onReceive functions.
|
||||||
|
///
|
||||||
|
/// Here is an example:
|
||||||
|
/// \code
|
||||||
|
/// class ZipPacket : public sf::Packet
|
||||||
|
/// {
|
||||||
|
/// const void* onSend(std::size_t& size) override
|
||||||
|
/// {
|
||||||
|
/// const void* srcData = getData();
|
||||||
|
/// std::size_t srcSize = getDataSize();
|
||||||
|
///
|
||||||
|
/// return MySuperZipFunction(srcData, srcSize, &size);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// void onReceive(const void* data, std::size_t size) override
|
||||||
|
/// {
|
||||||
|
/// std::size_t dstSize;
|
||||||
|
/// const void* dstData = MySuperUnzipFunction(data, size, &dstSize);
|
||||||
|
///
|
||||||
|
/// append(dstData, dstSize);
|
||||||
|
/// }
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// // Use like regular packets:
|
||||||
|
/// ZipPacket packet;
|
||||||
|
/// packet << x << s << d;
|
||||||
|
/// ...
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::TcpSocket`, `sf::UdpSocket`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,229 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Network/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Network/SocketHandle.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Base class for all the socket types
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_NETWORK_API Socket
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Status codes that may be returned by socket functions
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
enum class Status
|
||||||
|
{
|
||||||
|
Done, //!< The socket has sent / received the data
|
||||||
|
NotReady, //!< The socket is not ready to send / receive data yet
|
||||||
|
Partial, //!< The socket sent a part of the data
|
||||||
|
Disconnected, //!< The TCP socket has been disconnected
|
||||||
|
Error //!< An unexpected error happened
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Some special values used by sockets
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||||
|
static constexpr unsigned short AnyPort{0}; //!< Special value that tells the system to pick any available port
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Destructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
virtual ~Socket();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Deleted copy constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Socket(const Socket&) = delete;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Deleted copy assignment
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Socket& operator=(const Socket&) = delete;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Socket(Socket&& socket) noexcept;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move assignment
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Socket& operator=(Socket&& socket) noexcept;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Set the blocking state of the socket
|
||||||
|
///
|
||||||
|
/// In blocking mode, calls will not return until they have
|
||||||
|
/// completed their task. For example, a call to Receive in
|
||||||
|
/// blocking mode won't return until some data was actually
|
||||||
|
/// received.
|
||||||
|
/// In non-blocking mode, calls will always return immediately,
|
||||||
|
/// using the return code to signal whether there was data
|
||||||
|
/// available or not.
|
||||||
|
/// By default, all sockets are blocking.
|
||||||
|
///
|
||||||
|
/// \param blocking `true` to set the socket as blocking, `false` for non-blocking
|
||||||
|
///
|
||||||
|
/// \see `isBlocking`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void setBlocking(bool blocking);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Tell whether the socket is in blocking or non-blocking mode
|
||||||
|
///
|
||||||
|
/// \return `true` if the socket is blocking, `false` otherwise
|
||||||
|
///
|
||||||
|
/// \see `setBlocking`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool isBlocking() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Types of protocols that the socket can use
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
enum class Type
|
||||||
|
{
|
||||||
|
Tcp, //!< TCP protocol
|
||||||
|
Udp //!< UDP protocol
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// This constructor can only be accessed by derived classes.
|
||||||
|
///
|
||||||
|
/// \param type Type of the socket (TCP or UDP)
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit Socket(Type type);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Return the internal handle of the socket
|
||||||
|
///
|
||||||
|
/// The returned handle may be invalid if the socket
|
||||||
|
/// was not created yet (or already destroyed).
|
||||||
|
/// This function can only be accessed by derived classes.
|
||||||
|
///
|
||||||
|
/// \return The internal (OS-specific) handle of the socket
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] SocketHandle getNativeHandle() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Create the internal representation of the socket
|
||||||
|
///
|
||||||
|
/// This function can only be accessed by derived classes.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void create();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Create the internal representation of the socket
|
||||||
|
/// from a socket handle
|
||||||
|
///
|
||||||
|
/// This function can only be accessed by derived classes.
|
||||||
|
///
|
||||||
|
/// \param handle OS-specific handle of the socket to wrap
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void create(SocketHandle handle);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Close the socket gracefully
|
||||||
|
///
|
||||||
|
/// This function can only be accessed by derived classes.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void close();
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class SocketSelector;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Type m_type; //!< Type of the socket (TCP or UDP)
|
||||||
|
SocketHandle m_socket; //!< Socket descriptor
|
||||||
|
bool m_isBlocking{true}; //!< Current blocking mode of the socket
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::Socket
|
||||||
|
/// \ingroup network
|
||||||
|
///
|
||||||
|
/// This class mainly defines internal stuff to be used by
|
||||||
|
/// derived classes.
|
||||||
|
///
|
||||||
|
/// The only public features that it defines, and which
|
||||||
|
/// is therefore common to all the socket classes, is the
|
||||||
|
/// blocking state. All sockets can be set as blocking or
|
||||||
|
/// non-blocking.
|
||||||
|
///
|
||||||
|
/// In blocking mode, socket functions will hang until
|
||||||
|
/// the operation completes, which means that the entire
|
||||||
|
/// program (well, in fact the current thread if you use
|
||||||
|
/// multiple ones) will be stuck waiting for your socket
|
||||||
|
/// operation to complete.
|
||||||
|
///
|
||||||
|
/// In non-blocking mode, all the socket functions will
|
||||||
|
/// return immediately. If the socket is not ready to complete
|
||||||
|
/// the requested operation, the function simply returns
|
||||||
|
/// the proper status code (`Socket::Status::NotReady`).
|
||||||
|
///
|
||||||
|
/// The default mode, which is blocking, is the one that is
|
||||||
|
/// generally used, in combination with threads or selectors.
|
||||||
|
/// The non-blocking mode is rather used in real-time
|
||||||
|
/// applications that run an endless loop that can poll
|
||||||
|
/// the socket often enough, and cannot afford blocking
|
||||||
|
/// this loop.
|
||||||
|
///
|
||||||
|
/// \see `sf::TcpListener`, `sf::TcpSocket`, `sf::UdpSocket`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Config.hpp>
|
||||||
|
|
||||||
|
#if defined(SFML_SYSTEM_WINDOWS)
|
||||||
|
#include <basetsd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Low-level socket handle type, specific to each platform
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#if defined(SFML_SYSTEM_WINDOWS)
|
||||||
|
|
||||||
|
using SocketHandle = UINT_PTR;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
using SocketHandle = int;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
@ -0,0 +1,273 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Network/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/Time.hpp>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class Socket;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Multiplexer that allows to read from multiple sockets
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_NETWORK_API SocketSelector
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SocketSelector();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Destructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
~SocketSelector();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Copy constructor
|
||||||
|
///
|
||||||
|
/// \param copy Instance to copy
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SocketSelector(const SocketSelector& copy);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Overload of assignment operator
|
||||||
|
///
|
||||||
|
/// \param right Instance to assign
|
||||||
|
///
|
||||||
|
/// \return Reference to self
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SocketSelector& operator=(const SocketSelector& right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SocketSelector(SocketSelector&&) noexcept;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move assignment
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
SocketSelector& operator=(SocketSelector&&) noexcept;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Add a new socket to the selector
|
||||||
|
///
|
||||||
|
/// This function keeps a weak reference to the socket,
|
||||||
|
/// so you have to make sure that the socket is not destroyed
|
||||||
|
/// while it is stored in the selector.
|
||||||
|
/// This function does nothing if the socket is not valid.
|
||||||
|
///
|
||||||
|
/// \param socket Reference to the socket to add
|
||||||
|
///
|
||||||
|
/// \see `remove`, `clear`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void add(Socket& socket);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Remove a socket from the selector
|
||||||
|
///
|
||||||
|
/// This function doesn't destroy the socket, it simply
|
||||||
|
/// removes the reference that the selector has to it.
|
||||||
|
///
|
||||||
|
/// \param socket Reference to the socket to remove
|
||||||
|
///
|
||||||
|
/// \see `add`, `clear`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void remove(Socket& socket);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Remove all the sockets stored in the selector
|
||||||
|
///
|
||||||
|
/// This function doesn't destroy any instance, it simply
|
||||||
|
/// removes all the references that the selector has to
|
||||||
|
/// external sockets.
|
||||||
|
///
|
||||||
|
/// \see `add`, `remove`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Wait until one or more sockets are ready to receive
|
||||||
|
///
|
||||||
|
/// This function returns as soon as at least one socket has
|
||||||
|
/// some data available to be received. To know which sockets are
|
||||||
|
/// ready, use the `isReady` function.
|
||||||
|
/// If you use a timeout and no socket is ready before the timeout
|
||||||
|
/// is over, the function returns `false`.
|
||||||
|
///
|
||||||
|
/// \param timeout Maximum time to wait, (use Time::Zero for infinity)
|
||||||
|
///
|
||||||
|
/// \return `true` if there are sockets ready, `false` otherwise
|
||||||
|
///
|
||||||
|
/// \see `isReady`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool wait(Time timeout = Time::Zero);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Test a socket to know if it is ready to receive data
|
||||||
|
///
|
||||||
|
/// This function must be used after a call to Wait, to know
|
||||||
|
/// which sockets are ready to receive data. If a socket is
|
||||||
|
/// ready, a call to receive will never block because we know
|
||||||
|
/// that there is data available to read.
|
||||||
|
/// Note that if this function returns `true` for a TcpListener,
|
||||||
|
/// this means that it is ready to accept a new connection.
|
||||||
|
///
|
||||||
|
/// \param socket Socket to test
|
||||||
|
///
|
||||||
|
/// \return `true` if the socket is ready to read, `false` otherwise
|
||||||
|
///
|
||||||
|
/// \see `isReady`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool isReady(Socket& socket) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct SocketSelectorImpl;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::unique_ptr<SocketSelectorImpl> m_impl; //!< Opaque pointer to the implementation (which requires OS-specific types)
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::SocketSelector
|
||||||
|
/// \ingroup network
|
||||||
|
///
|
||||||
|
/// Socket selectors provide a way to wait until some data is
|
||||||
|
/// available on a set of sockets, instead of just one. This
|
||||||
|
/// is convenient when you have multiple sockets that may
|
||||||
|
/// possibly receive data, but you don't know which one will
|
||||||
|
/// be ready first. In particular, it avoids to use a thread
|
||||||
|
/// for each socket; with selectors, a single thread can handle
|
||||||
|
/// all the sockets.
|
||||||
|
///
|
||||||
|
/// All types of sockets can be used in a selector:
|
||||||
|
/// \li `sf::TcpListener`
|
||||||
|
/// \li `sf::TcpSocket`
|
||||||
|
/// \li `sf::UdpSocket`
|
||||||
|
///
|
||||||
|
/// A selector doesn't store its own copies of the sockets
|
||||||
|
/// (socket classes are not copyable anyway), it simply keeps
|
||||||
|
/// a reference to the original sockets that you pass to the
|
||||||
|
/// "add" function. Therefore, you can't use the selector as a
|
||||||
|
/// socket container, you must store them outside and make sure
|
||||||
|
/// that they are alive as long as they are used in the selector.
|
||||||
|
///
|
||||||
|
/// Using a selector is simple:
|
||||||
|
/// \li populate the selector with all the sockets that you want to observe
|
||||||
|
/// \li make it wait until there is data available on any of the sockets
|
||||||
|
/// \li test each socket to find out which ones are ready
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// // Create a socket to listen to new connections
|
||||||
|
/// sf::TcpListener listener;
|
||||||
|
/// if (listener.listen(55001) != sf::Socket::Status::Done)
|
||||||
|
/// {
|
||||||
|
/// // Handle error...
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // Create a list to store the future clients
|
||||||
|
/// std::vector<sf::TcpSocket> clients;
|
||||||
|
///
|
||||||
|
/// // Create a selector
|
||||||
|
/// sf::SocketSelector selector;
|
||||||
|
///
|
||||||
|
/// // Add the listener to the selector
|
||||||
|
/// selector.add(listener);
|
||||||
|
///
|
||||||
|
/// // Endless loop that waits for new connections
|
||||||
|
/// while (running)
|
||||||
|
/// {
|
||||||
|
/// // Make the selector wait for data on any socket
|
||||||
|
/// if (selector.wait())
|
||||||
|
/// {
|
||||||
|
/// // Test the listener
|
||||||
|
/// if (selector.isReady(listener))
|
||||||
|
/// {
|
||||||
|
/// // The listener is ready: there is a pending connection
|
||||||
|
/// sf::TcpSocket client;
|
||||||
|
/// if (listener.accept(client) == sf::Socket::Status::Done)
|
||||||
|
/// {
|
||||||
|
/// // Add the new client to the selector so that we will
|
||||||
|
/// // be notified when they send something
|
||||||
|
/// selector.add(client);
|
||||||
|
///
|
||||||
|
/// // Add the new client to the clients list
|
||||||
|
/// clients.push_back(std::move(client));
|
||||||
|
/// }
|
||||||
|
/// else
|
||||||
|
/// {
|
||||||
|
/// // Handle error...
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// else
|
||||||
|
/// {
|
||||||
|
/// // The listener socket is not ready, test all other sockets (the clients)
|
||||||
|
/// for (sf::TcpSocket& client : clients)
|
||||||
|
/// {
|
||||||
|
/// if (selector.isReady(client))
|
||||||
|
/// {
|
||||||
|
/// // The client has sent some data, we can receive it
|
||||||
|
/// sf::Packet packet;
|
||||||
|
/// if (client.receive(packet) == sf::Socket::Status::Done)
|
||||||
|
/// {
|
||||||
|
/// ...
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::Socket`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,166 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Network/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Network/IpAddress.hpp>
|
||||||
|
#include <SFML/Network/Socket.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class TcpSocket;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Socket that listens to new TCP connections
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_NETWORK_API TcpListener : public Socket
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
TcpListener();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the port to which the socket is bound locally
|
||||||
|
///
|
||||||
|
/// If the socket is not listening to a port, this function
|
||||||
|
/// returns 0.
|
||||||
|
///
|
||||||
|
/// \return Port to which the socket is bound
|
||||||
|
///
|
||||||
|
/// \see `listen`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] unsigned short getLocalPort() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Start listening for incoming connection attempts
|
||||||
|
///
|
||||||
|
/// This function makes the socket start listening on the
|
||||||
|
/// specified port, waiting for incoming connection attempts.
|
||||||
|
///
|
||||||
|
/// If the socket is already listening on a port when this
|
||||||
|
/// function is called, it will stop listening on the old
|
||||||
|
/// port before starting to listen on the new port.
|
||||||
|
///
|
||||||
|
/// When providing `sf::Socket::AnyPort` as port, the listener
|
||||||
|
/// will request an available port from the system.
|
||||||
|
/// The chosen port can be retrieved by calling `getLocalPort()`.
|
||||||
|
///
|
||||||
|
/// \param port Port to listen on for incoming connection attempts
|
||||||
|
/// \param address Address of the interface to listen on
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
/// \see `accept`, `close`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Status listen(unsigned short port, IpAddress address = IpAddress::Any);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Stop listening and close the socket
|
||||||
|
///
|
||||||
|
/// This function gracefully stops the listener. If the
|
||||||
|
/// socket is not listening, this function has no effect.
|
||||||
|
///
|
||||||
|
/// \see `listen`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void close();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Accept a new connection
|
||||||
|
///
|
||||||
|
/// If the socket is in blocking mode, this function will
|
||||||
|
/// not return until a connection is actually received.
|
||||||
|
///
|
||||||
|
/// \param socket Socket that will hold the new connection
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
/// \see `listen`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Status accept(TcpSocket& socket);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::TcpListener
|
||||||
|
/// \ingroup network
|
||||||
|
///
|
||||||
|
/// A listener socket is a special type of socket that listens to
|
||||||
|
/// a given port and waits for connections on that port.
|
||||||
|
/// This is all it can do.
|
||||||
|
///
|
||||||
|
/// When a new connection is received, you must call accept and
|
||||||
|
/// the listener returns a new instance of `sf::TcpSocket` that
|
||||||
|
/// is properly initialized and can be used to communicate with
|
||||||
|
/// the new client.
|
||||||
|
///
|
||||||
|
/// Listener sockets are specific to the TCP protocol,
|
||||||
|
/// UDP sockets are connectionless and can therefore communicate
|
||||||
|
/// directly. As a consequence, a listener socket will always
|
||||||
|
/// return the new connections as `sf::TcpSocket` instances.
|
||||||
|
///
|
||||||
|
/// A listener is automatically closed on destruction, like all
|
||||||
|
/// other types of socket. However if you want to stop listening
|
||||||
|
/// before the socket is destroyed, you can call its `close()`
|
||||||
|
/// function.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// // Create a listener socket and make it wait for new
|
||||||
|
/// // connections on port 55001
|
||||||
|
/// sf::TcpListener listener;
|
||||||
|
/// listener.listen(55001);
|
||||||
|
///
|
||||||
|
/// // Endless loop that waits for new connections
|
||||||
|
/// while (running)
|
||||||
|
/// {
|
||||||
|
/// sf::TcpSocket client;
|
||||||
|
/// if (listener.accept(client) == sf::Socket::Done)
|
||||||
|
/// {
|
||||||
|
/// // A new client just connected!
|
||||||
|
/// std::cout << "New connection received from " << client.getRemoteAddress().value() << std::endl;
|
||||||
|
/// doSomethingWith(client);
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::TcpSocket`, `sf::Socket`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,317 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Network/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Network/Socket.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/Time.hpp>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class TcpListener;
|
||||||
|
class IpAddress;
|
||||||
|
class Packet;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Specialized socket using the TCP protocol
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_NETWORK_API TcpSocket : public Socket
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
TcpSocket();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the port to which the socket is bound locally
|
||||||
|
///
|
||||||
|
/// If the socket is not connected, this function returns 0.
|
||||||
|
///
|
||||||
|
/// \return Port to which the socket is bound
|
||||||
|
///
|
||||||
|
/// \see `connect`, `getRemotePort`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] unsigned short getLocalPort() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the address of the connected peer
|
||||||
|
///
|
||||||
|
/// If the socket is not connected, this function returns
|
||||||
|
/// an unset optional.
|
||||||
|
///
|
||||||
|
/// \return Address of the remote peer
|
||||||
|
///
|
||||||
|
/// \see `getRemotePort`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] std::optional<IpAddress> getRemoteAddress() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the port of the connected peer to which
|
||||||
|
/// the socket is connected
|
||||||
|
///
|
||||||
|
/// If the socket is not connected, this function returns 0.
|
||||||
|
///
|
||||||
|
/// \return Remote port to which the socket is connected
|
||||||
|
///
|
||||||
|
/// \see `getRemoteAddress`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] unsigned short getRemotePort() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Connect the socket to a remote peer
|
||||||
|
///
|
||||||
|
/// In blocking mode, this function may take a while, especially
|
||||||
|
/// if the remote peer is not reachable. The last parameter allows
|
||||||
|
/// you to stop trying to connect after a given timeout.
|
||||||
|
/// If the socket is already connected, the connection is
|
||||||
|
/// forcibly disconnected before attempting to connect again.
|
||||||
|
///
|
||||||
|
/// \param remoteAddress Address of the remote peer
|
||||||
|
/// \param remotePort Port of the remote peer
|
||||||
|
/// \param timeout Optional maximum time to wait
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
/// \see `disconnect`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Status connect(IpAddress remoteAddress, unsigned short remotePort, Time timeout = Time::Zero);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Disconnect the socket from its remote peer
|
||||||
|
///
|
||||||
|
/// This function gracefully closes the connection. If the
|
||||||
|
/// socket is not connected, this function has no effect.
|
||||||
|
///
|
||||||
|
/// \see `connect`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void disconnect();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Send raw data to the remote peer
|
||||||
|
///
|
||||||
|
/// To be able to handle partial sends over non-blocking
|
||||||
|
/// sockets, use the `send(const void*, std::size_t, std::size_t&)`
|
||||||
|
/// overload instead.
|
||||||
|
/// This function will fail if the socket is not connected.
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the sequence of bytes to send
|
||||||
|
/// \param size Number of bytes to send
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
/// \see `receive`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Status send(const void* data, std::size_t size);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Send raw data to the remote peer
|
||||||
|
///
|
||||||
|
/// This function will fail if the socket is not connected.
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the sequence of bytes to send
|
||||||
|
/// \param size Number of bytes to send
|
||||||
|
/// \param sent The number of bytes sent will be written here
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
/// \see `receive`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Status send(const void* data, std::size_t size, std::size_t& sent);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Receive raw data from the remote peer
|
||||||
|
///
|
||||||
|
/// In blocking mode, this function will wait until some
|
||||||
|
/// bytes are actually received.
|
||||||
|
/// This function will fail if the socket is not connected.
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the array to fill with the received bytes
|
||||||
|
/// \param size Maximum number of bytes that can be received
|
||||||
|
/// \param received This variable is filled with the actual number of bytes received
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
/// \see `send`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Status receive(void* data, std::size_t size, std::size_t& received);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Send a formatted packet of data to the remote peer
|
||||||
|
///
|
||||||
|
/// In non-blocking mode, if this function returns `sf::Socket::Status::Partial`,
|
||||||
|
/// you \em must retry sending the same unmodified packet before sending
|
||||||
|
/// anything else in order to guarantee the packet arrives at the remote
|
||||||
|
/// peer uncorrupted.
|
||||||
|
/// This function will fail if the socket is not connected.
|
||||||
|
///
|
||||||
|
/// \param packet Packet to send
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
/// \see `receive`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Status send(Packet& packet);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Receive a formatted packet of data from the remote peer
|
||||||
|
///
|
||||||
|
/// In blocking mode, this function will wait until the whole packet
|
||||||
|
/// has been received.
|
||||||
|
/// This function will fail if the socket is not connected.
|
||||||
|
///
|
||||||
|
/// \param packet Packet to fill with the received data
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
/// \see `send`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Status receive(Packet& packet);
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class TcpListener;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Structure holding the data of a pending packet
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
struct PendingPacket
|
||||||
|
{
|
||||||
|
std::uint32_t size{}; //!< Data of packet size
|
||||||
|
std::size_t sizeReceived{}; //!< Number of size bytes received so far
|
||||||
|
std::vector<std::byte> data; //!< Data of the packet
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
PendingPacket m_pendingPacket; //!< Temporary data of the packet currently being received
|
||||||
|
std::vector<std::byte> m_blockToSendBuffer; //!< Buffer used to prepare data being sent from the socket
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::TcpSocket
|
||||||
|
/// \ingroup network
|
||||||
|
///
|
||||||
|
/// TCP is a connected protocol, which means that a TCP
|
||||||
|
/// socket can only communicate with the host it is connected
|
||||||
|
/// to. It can't send or receive anything if it is not connected.
|
||||||
|
///
|
||||||
|
/// The TCP protocol is reliable but adds a slight overhead.
|
||||||
|
/// It ensures that your data will always be received in order
|
||||||
|
/// and without errors (no data corrupted, lost or duplicated).
|
||||||
|
///
|
||||||
|
/// When a socket is connected to a remote host, you can
|
||||||
|
/// retrieve information about this host with the
|
||||||
|
/// `getRemoteAddress` and `getRemotePort` functions. You can
|
||||||
|
/// also get the local port to which the socket is bound
|
||||||
|
/// (which is automatically chosen when the socket is connected),
|
||||||
|
/// with the getLocalPort function.
|
||||||
|
///
|
||||||
|
/// Sending and receiving data can use either the low-level
|
||||||
|
/// or the high-level functions. The low-level functions
|
||||||
|
/// process a raw sequence of bytes, and cannot ensure that
|
||||||
|
/// one call to Send will exactly match one call to Receive
|
||||||
|
/// at the other end of the socket.
|
||||||
|
///
|
||||||
|
/// The high-level interface uses packets (see `sf::Packet`),
|
||||||
|
/// which are easier to use and provide more safety regarding
|
||||||
|
/// the data that is exchanged. You can look at the `sf::Packet`
|
||||||
|
/// class to get more details about how they work.
|
||||||
|
///
|
||||||
|
/// The socket is automatically disconnected when it is destroyed,
|
||||||
|
/// but if you want to explicitly close the connection while
|
||||||
|
/// the socket instance is still alive, you can call disconnect.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// // ----- The client -----
|
||||||
|
///
|
||||||
|
/// // Create a socket and connect it to 192.168.1.50 on port 55001
|
||||||
|
/// sf::TcpSocket socket;
|
||||||
|
/// socket.connect("192.168.1.50", 55001);
|
||||||
|
///
|
||||||
|
/// // Send a message to the connected host
|
||||||
|
/// std::string message = "Hi, I am a client";
|
||||||
|
/// socket.send(message.c_str(), message.size() + 1);
|
||||||
|
///
|
||||||
|
/// // Receive an answer from the server
|
||||||
|
/// std::array<char, 1024> buffer;
|
||||||
|
/// std::size_t received = 0;
|
||||||
|
/// socket.receive(buffer.data(), buffer.size(), received);
|
||||||
|
/// std::cout << "The server said: " << buffer.data() << std::endl;
|
||||||
|
///
|
||||||
|
/// // ----- The server -----
|
||||||
|
///
|
||||||
|
/// // Create a listener to wait for incoming connections on port 55001
|
||||||
|
/// sf::TcpListener listener;
|
||||||
|
/// listener.listen(55001);
|
||||||
|
///
|
||||||
|
/// // Wait for a connection
|
||||||
|
/// sf::TcpSocket socket;
|
||||||
|
/// listener.accept(socket);
|
||||||
|
/// std::cout << "New client connected: " << socket.getRemoteAddress().value() << std::endl;
|
||||||
|
///
|
||||||
|
/// // Receive a message from the client
|
||||||
|
/// std::array<char, 1024> buffer;
|
||||||
|
/// std::size_t received = 0;
|
||||||
|
/// socket.receive(buffer.data(), buffer.size(), received);
|
||||||
|
/// std::cout << "The client said: " << buffer.data() << std::endl;
|
||||||
|
///
|
||||||
|
/// // Send an answer
|
||||||
|
/// std::string message = "Welcome, client";
|
||||||
|
/// socket.send(message.c_str(), message.size() + 1);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::Socket`, `sf::UdpSocket`, `sf::Packet`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,293 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Network/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/Network/IpAddress.hpp>
|
||||||
|
#include <SFML/Network/Socket.hpp>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
class Packet;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Specialized socket using the UDP protocol
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_NETWORK_API UdpSocket : public Socket
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Constants
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||||
|
static constexpr std::size_t MaxDatagramSize{65507}; //!< The maximum number of bytes that can be sent in a single UDP datagram
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
UdpSocket();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the port to which the socket is bound locally
|
||||||
|
///
|
||||||
|
/// If the socket is not bound to a port, this function
|
||||||
|
/// returns 0.
|
||||||
|
///
|
||||||
|
/// \return Port to which the socket is bound
|
||||||
|
///
|
||||||
|
/// \see `bind`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] unsigned short getLocalPort() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Bind the socket to a specific port
|
||||||
|
///
|
||||||
|
/// Binding the socket to a port is necessary for being
|
||||||
|
/// able to receive data on that port.
|
||||||
|
///
|
||||||
|
/// When providing `sf::Socket::AnyPort` as port, the listener
|
||||||
|
/// will request an available port from the system.
|
||||||
|
/// The chosen port can be retrieved by calling `getLocalPort()`.
|
||||||
|
///
|
||||||
|
/// Since the socket can only be bound to a single port at
|
||||||
|
/// any given moment, if it is already bound when this
|
||||||
|
/// function is called, it will be unbound from the previous
|
||||||
|
/// port before being bound to the new one.
|
||||||
|
///
|
||||||
|
/// \param port Port to bind the socket to
|
||||||
|
/// \param address Address of the interface to bind to
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
/// \see `unbind`, `getLocalPort`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Status bind(unsigned short port, IpAddress address = IpAddress::Any);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Unbind the socket from the local port to which it is bound
|
||||||
|
///
|
||||||
|
/// The port that the socket was previously bound to is immediately
|
||||||
|
/// made available to the operating system after this function is called.
|
||||||
|
/// This means that a subsequent call to `bind()` will be able to re-bind
|
||||||
|
/// the port if no other process has done so in the mean time.
|
||||||
|
/// If the socket is not bound to a port, this function has no effect.
|
||||||
|
///
|
||||||
|
/// \see `bind`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void unbind();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Send raw data to a remote peer
|
||||||
|
///
|
||||||
|
/// Make sure that `size` is not greater than
|
||||||
|
/// `UdpSocket::MaxDatagramSize`, otherwise this function will
|
||||||
|
/// fail and no data will be sent.
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the sequence of bytes to send
|
||||||
|
/// \param size Number of bytes to send
|
||||||
|
/// \param remoteAddress Address of the receiver
|
||||||
|
/// \param remotePort Port of the receiver to send the data to
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
/// \see `receive`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Status send(const void* data, std::size_t size, IpAddress remoteAddress, unsigned short remotePort);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Receive raw data from a remote peer
|
||||||
|
///
|
||||||
|
/// In blocking mode, this function will wait until some
|
||||||
|
/// bytes are actually received.
|
||||||
|
/// Be careful to use a buffer which is large enough for
|
||||||
|
/// the data that you intend to receive, if it is too small
|
||||||
|
/// then an error will be returned and *all* the data will
|
||||||
|
/// be lost.
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the array to fill with the received bytes
|
||||||
|
/// \param size Maximum number of bytes that can be received
|
||||||
|
/// \param received This variable is filled with the actual number of bytes received
|
||||||
|
/// \param remoteAddress Address of the peer that sent the data
|
||||||
|
/// \param remotePort Port of the peer that sent the data
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
/// \see `send`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Status receive(void* data,
|
||||||
|
std::size_t size,
|
||||||
|
std::size_t& received,
|
||||||
|
std::optional<IpAddress>& remoteAddress,
|
||||||
|
unsigned short& remotePort);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Send a formatted packet of data to a remote peer
|
||||||
|
///
|
||||||
|
/// Make sure that the packet size is not greater than
|
||||||
|
/// `UdpSocket::MaxDatagramSize`, otherwise this function will
|
||||||
|
/// fail and no data will be sent.
|
||||||
|
///
|
||||||
|
/// \param packet Packet to send
|
||||||
|
/// \param remoteAddress Address of the receiver
|
||||||
|
/// \param remotePort Port of the receiver to send the data to
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
/// \see `receive`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Status send(Packet& packet, IpAddress remoteAddress, unsigned short remotePort);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Receive a formatted packet of data from a remote peer
|
||||||
|
///
|
||||||
|
/// In blocking mode, this function will wait until the whole packet
|
||||||
|
/// has been received.
|
||||||
|
///
|
||||||
|
/// \param packet Packet to fill with the received data
|
||||||
|
/// \param remoteAddress Address of the peer that sent the data
|
||||||
|
/// \param remotePort Port of the peer that sent the data
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
/// \see `send`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Status receive(Packet& packet, std::optional<IpAddress>& remoteAddress, unsigned short& remotePort);
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::vector<std::byte> m_buffer{MaxDatagramSize}; //!< Temporary buffer holding the received data in Receive(Packet)
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::UdpSocket
|
||||||
|
/// \ingroup network
|
||||||
|
///
|
||||||
|
/// A UDP socket is a connectionless socket. Instead of
|
||||||
|
/// connecting once to a remote host, like TCP sockets,
|
||||||
|
/// it can send to and receive from any host at any time.
|
||||||
|
///
|
||||||
|
/// It is a datagram protocol: bounded blocks of data (datagrams)
|
||||||
|
/// are transferred over the network rather than a continuous
|
||||||
|
/// stream of data (TCP). Therefore, one call to send will always
|
||||||
|
/// match one call to receive (if the datagram is not lost),
|
||||||
|
/// with the same data that was sent.
|
||||||
|
///
|
||||||
|
/// The UDP protocol is lightweight but unreliable. Unreliable
|
||||||
|
/// means that datagrams may be duplicated, be lost or
|
||||||
|
/// arrive reordered. However, if a datagram arrives, its
|
||||||
|
/// data is guaranteed to be valid.
|
||||||
|
///
|
||||||
|
/// UDP is generally used for real-time communication
|
||||||
|
/// (audio or video streaming, real-time games, etc.) where
|
||||||
|
/// speed is crucial and lost data doesn't matter much.
|
||||||
|
///
|
||||||
|
/// Sending and receiving data can use either the low-level
|
||||||
|
/// or the high-level functions. The low-level functions
|
||||||
|
/// process a raw sequence of bytes, whereas the high-level
|
||||||
|
/// interface uses packets (see `sf::Packet`), which are easier
|
||||||
|
/// to use and provide more safety regarding the data that is
|
||||||
|
/// exchanged. You can look at the `sf::Packet` class to get
|
||||||
|
/// more details about how they work.
|
||||||
|
///
|
||||||
|
/// It is important to note that `UdpSocket` is unable to send
|
||||||
|
/// datagrams bigger than `MaxDatagramSize`. In this case, it
|
||||||
|
/// returns an error and doesn't send anything. This applies
|
||||||
|
/// to both raw data and packets. Indeed, even packets are
|
||||||
|
/// unable to split and recompose data, due to the unreliability
|
||||||
|
/// of the protocol (dropped, mixed or duplicated datagrams may
|
||||||
|
/// lead to a big mess when trying to recompose a packet).
|
||||||
|
///
|
||||||
|
/// If the socket is bound to a port, it is automatically
|
||||||
|
/// unbound from it when the socket is destroyed. However,
|
||||||
|
/// you can unbind the socket explicitly with the Unbind
|
||||||
|
/// function if necessary, to stop receiving messages or
|
||||||
|
/// make the port available for other sockets.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// // ----- The client -----
|
||||||
|
///
|
||||||
|
/// // Create a socket and bind it to the port 55001
|
||||||
|
/// sf::UdpSocket socket;
|
||||||
|
/// socket.bind(55001);
|
||||||
|
///
|
||||||
|
/// // Send a message to 192.168.1.50 on port 55002
|
||||||
|
/// std::string message = "Hi, I am " + sf::IpAddress::getLocalAddress().toString();
|
||||||
|
/// socket.send(message.c_str(), message.size() + 1, "192.168.1.50", 55002);
|
||||||
|
///
|
||||||
|
/// // Receive an answer (most likely from 192.168.1.50, but could be anyone else)
|
||||||
|
/// std::array<char, 1024> buffer;
|
||||||
|
/// std::size_t received = 0;
|
||||||
|
/// std::optional<sf::IpAddress> sender;
|
||||||
|
/// unsigned short port;
|
||||||
|
/// if (socket.receive(buffer.data(), buffer.size(), received, sender, port) == sf::Socket::Status::Done)
|
||||||
|
/// std::cout << sender->toString() << " said: " << buffer.data() << std::endl;
|
||||||
|
///
|
||||||
|
/// // ----- The server -----
|
||||||
|
///
|
||||||
|
/// // Create a socket and bind it to the port 55002
|
||||||
|
/// sf::UdpSocket socket;
|
||||||
|
/// socket.bind(55002);
|
||||||
|
///
|
||||||
|
/// // Receive a message from anyone
|
||||||
|
/// std::array<char, 1024> buffer;
|
||||||
|
/// std::size_t received = 0;
|
||||||
|
/// std::optional<sf::IpAddress> sender;
|
||||||
|
/// unsigned short port;
|
||||||
|
/// if (socket.receive(buffer.data(), buffer.size(), received, sender, port) == sf::Socket::Status::Done)
|
||||||
|
/// std::cout << sender->toString() << " said: " << buffer.data() << std::endl;
|
||||||
|
///
|
||||||
|
/// // Send an answer
|
||||||
|
/// std::string message = "Welcome " + sender.toString();
|
||||||
|
/// socket.send(message.c_str(), message.size() + 1, sender, port);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `sf::Socket`, `sf::TcpSocket`, `sf::Packet`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Config.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// This file just includes the OpenGL headers,
|
||||||
|
/// which have actually different paths on each system
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#if defined(SFML_SYSTEM_WINDOWS)
|
||||||
|
|
||||||
|
// The Visual C++ version of gl.h uses WINGDIAPI and APIENTRY but doesn't define them
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <GL/gl.h>
|
||||||
|
|
||||||
|
#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) || \
|
||||||
|
defined(SFML_SYSTEM_NETBSD)
|
||||||
|
|
||||||
|
#if defined(SFML_OPENGL_ES)
|
||||||
|
#include <GLES/gl.h>
|
||||||
|
#include <GLES/glext.h>
|
||||||
|
#else
|
||||||
|
#include <GL/gl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(SFML_SYSTEM_MACOS)
|
||||||
|
|
||||||
|
#include <OpenGL/gl.h>
|
||||||
|
|
||||||
|
#elif defined(SFML_SYSTEM_IOS)
|
||||||
|
|
||||||
|
#include <OpenGLES/ES1/gl.h>
|
||||||
|
#include <OpenGLES/ES1/glext.h>
|
||||||
|
|
||||||
|
#elif defined(SFML_SYSTEM_ANDROID)
|
||||||
|
|
||||||
|
#include <GLES/gl.h>
|
||||||
|
#include <GLES/glext.h>
|
||||||
|
|
||||||
|
// We're not using OpenGL ES 2+ yet, but we can use the sRGB extension
|
||||||
|
#include <GLES2/gl2ext.h>
|
||||||
|
#include <GLES2/gl2platform.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <SFML/Config.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/Angle.hpp>
|
||||||
|
#include <SFML/System/Clock.hpp>
|
||||||
|
#include <SFML/System/Err.hpp>
|
||||||
|
#include <SFML/System/Exception.hpp>
|
||||||
|
#include <SFML/System/FileInputStream.hpp>
|
||||||
|
#include <SFML/System/InputStream.hpp>
|
||||||
|
#include <SFML/System/MemoryInputStream.hpp>
|
||||||
|
#include <SFML/System/Sleep.hpp>
|
||||||
|
#include <SFML/System/String.hpp>
|
||||||
|
#include <SFML/System/Time.hpp>
|
||||||
|
#include <SFML/System/Utf.hpp>
|
||||||
|
#include <SFML/System/Vector2.hpp>
|
||||||
|
#include <SFML/System/Vector3.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \defgroup system System module
|
||||||
|
///
|
||||||
|
/// Base module of SFML, defining various utilities. It provides
|
||||||
|
/// vector classes, Unicode strings and conversion functions,
|
||||||
|
/// threads and mutexes, timing classes.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,511 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Represents an angle value.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class Angle
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// Sets the angle value to zero.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Return the angle's value in degrees
|
||||||
|
///
|
||||||
|
/// \return Angle in degrees
|
||||||
|
///
|
||||||
|
/// \see `asRadians`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr float asDegrees() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Return the angle's value in radians
|
||||||
|
///
|
||||||
|
/// \return Angle in radians
|
||||||
|
///
|
||||||
|
/// \see `asDegrees`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr float asRadians() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Wrap to a range such that -180° <= angle < 180°
|
||||||
|
///
|
||||||
|
/// Similar to a modulo operation, this returns a copy of the angle
|
||||||
|
/// constrained to the range [-180°, 180°) == [-Pi, Pi).
|
||||||
|
/// The resulting angle represents a rotation which is equivalent to `*this`.
|
||||||
|
///
|
||||||
|
/// The name "signed" originates from the similarity to signed integers:
|
||||||
|
/// <table>
|
||||||
|
/// <tr>
|
||||||
|
/// <th></th>
|
||||||
|
/// <th>signed</th>
|
||||||
|
/// <th>unsigned</th>
|
||||||
|
/// </tr>
|
||||||
|
/// <tr>
|
||||||
|
/// <td>char</td>
|
||||||
|
/// <td>[-128, 128)</td>
|
||||||
|
/// <td>[0, 256)</td>
|
||||||
|
/// </tr>
|
||||||
|
/// <tr>
|
||||||
|
/// <td>Angle</td>
|
||||||
|
/// <td>[-180°, 180°)</td>
|
||||||
|
/// <td>[0°, 360°)</td>
|
||||||
|
/// </tr>
|
||||||
|
/// </table>
|
||||||
|
///
|
||||||
|
/// \return Signed angle, wrapped to [-180°, 180°)
|
||||||
|
///
|
||||||
|
/// \see `wrapUnsigned`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr Angle wrapSigned() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Wrap to a range such that 0° <= angle < 360°
|
||||||
|
///
|
||||||
|
/// Similar to a modulo operation, this returns a copy of the angle
|
||||||
|
/// constrained to the range [0°, 360°) == [0, Tau) == [0, 2*Pi).
|
||||||
|
/// The resulting angle represents a rotation which is equivalent to `*this`.
|
||||||
|
///
|
||||||
|
/// The name "unsigned" originates from the similarity to unsigned integers:
|
||||||
|
/// <table>
|
||||||
|
/// <tr>
|
||||||
|
/// <th></th>
|
||||||
|
/// <th>signed</th>
|
||||||
|
/// <th>unsigned</th>
|
||||||
|
/// </tr>
|
||||||
|
/// <tr>
|
||||||
|
/// <td>char</td>
|
||||||
|
/// <td>[-128, 128)</td>
|
||||||
|
/// <td>[0, 256)</td>
|
||||||
|
/// </tr>
|
||||||
|
/// <tr>
|
||||||
|
/// <td>Angle</td>
|
||||||
|
/// <td>[-180°, 180°)</td>
|
||||||
|
/// <td>[0°, 360°)</td>
|
||||||
|
/// </tr>
|
||||||
|
/// </table>
|
||||||
|
///
|
||||||
|
/// \return Unsigned angle, wrapped to [0°, 360°)
|
||||||
|
///
|
||||||
|
/// \see `wrapSigned`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr Angle wrapUnsigned() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Static member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||||
|
static const Angle Zero; //!< Predefined 0 degree angle value
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend constexpr Angle degrees(float angle);
|
||||||
|
friend constexpr Angle radians(float angle);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct from a number of radians
|
||||||
|
///
|
||||||
|
/// This function is internal. To construct angle values,
|
||||||
|
/// use `sf::radians` or `sf::degrees` instead.
|
||||||
|
///
|
||||||
|
/// \param radians Angle in radians
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr explicit Angle(float radians);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
float m_radians{}; //!< Angle value stored as radians
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct an angle value from a number of degrees
|
||||||
|
///
|
||||||
|
/// \param angle Number of degrees
|
||||||
|
///
|
||||||
|
/// \return Angle value constructed from the number of degrees
|
||||||
|
///
|
||||||
|
/// \see `radians`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr Angle degrees(float angle);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct an angle value from a number of radians
|
||||||
|
///
|
||||||
|
/// \param angle Number of radians
|
||||||
|
///
|
||||||
|
/// \return Angle value constructed from the number of radians
|
||||||
|
///
|
||||||
|
/// \see `degrees`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr Angle radians(float angle);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Angle
|
||||||
|
/// \brief Overload of `operator==` to compare two angle values
|
||||||
|
/// \note Does not automatically wrap the angle value
|
||||||
|
///
|
||||||
|
/// \param left Left operand (an angle)
|
||||||
|
/// \param right Right operand (an angle)
|
||||||
|
///
|
||||||
|
/// \return `true` if both angle values are equal
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr bool operator==(Angle left, Angle right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Angle
|
||||||
|
/// \brief Overload of `operator!=` to compare two angle values
|
||||||
|
/// \note Does not automatically wrap the angle value
|
||||||
|
///
|
||||||
|
/// \param left Left operand (an angle)
|
||||||
|
/// \param right Right operand (an angle)
|
||||||
|
///
|
||||||
|
/// \return `true` if both angle values are different
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr bool operator!=(Angle left, Angle right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Angle
|
||||||
|
/// \brief Overload of `operator<` to compare two angle values
|
||||||
|
/// \note Does not automatically wrap the angle value
|
||||||
|
///
|
||||||
|
/// \param left Left operand (an angle)
|
||||||
|
/// \param right Right operand (an angle)
|
||||||
|
///
|
||||||
|
/// \return `true` if \a left is less than \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr bool operator<(Angle left, Angle right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Angle
|
||||||
|
/// \brief Overload of `operator>` to compare two angle values
|
||||||
|
/// \note Does not automatically wrap the angle value
|
||||||
|
///
|
||||||
|
/// \param left Left operand (an angle)
|
||||||
|
/// \param right Right operand (an angle)
|
||||||
|
///
|
||||||
|
/// \return `true` if \a left is greater than \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr bool operator>(Angle left, Angle right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Angle
|
||||||
|
/// \brief Overload of `operator<=` to compare two angle values
|
||||||
|
/// \note Does not automatically wrap the angle value
|
||||||
|
///
|
||||||
|
/// \param left Left operand (an angle)
|
||||||
|
/// \param right Right operand (an angle)
|
||||||
|
///
|
||||||
|
/// \return `true` if \a left is less than or equal to \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr bool operator<=(Angle left, Angle right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Angle
|
||||||
|
/// \brief Overload of `operator>=` to compare two angle values
|
||||||
|
/// \note Does not automatically wrap the angle value
|
||||||
|
///
|
||||||
|
/// \param left Left operand (an angle)
|
||||||
|
/// \param right Right operand (an angle)
|
||||||
|
///
|
||||||
|
/// \return `true` if \a left is greater than or equal to \a right
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr bool operator>=(Angle left, Angle right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Angle
|
||||||
|
/// \brief Overload of unary `operator-` to negate an angle value.
|
||||||
|
///
|
||||||
|
/// Represents a rotation in the opposite direction.
|
||||||
|
///
|
||||||
|
/// \param right Right operand (an angle)
|
||||||
|
///
|
||||||
|
/// \return Negative of the angle value
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr Angle operator-(Angle right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Angle
|
||||||
|
/// \brief Overload of binary `operator+` to add two angle values
|
||||||
|
///
|
||||||
|
/// \param left Left operand (an angle)
|
||||||
|
/// \param right Right operand (an angle)
|
||||||
|
///
|
||||||
|
/// \return Sum of the two angle values
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr Angle operator+(Angle left, Angle right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Angle
|
||||||
|
/// \brief Overload of binary `operator+=` to add/assign two angle values
|
||||||
|
///
|
||||||
|
/// \param left Left operand (an angle)
|
||||||
|
/// \param right Right operand (an angle)
|
||||||
|
///
|
||||||
|
/// \return Sum of the two angle values
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle& operator+=(Angle& left, Angle right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Angle
|
||||||
|
/// \brief Overload of binary `operator-` to subtract two angle values
|
||||||
|
///
|
||||||
|
/// \param left Left operand (an angle)
|
||||||
|
/// \param right Right operand (an angle)
|
||||||
|
///
|
||||||
|
/// \return Difference of the two angle values
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr Angle operator-(Angle left, Angle right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Angle
|
||||||
|
/// \brief Overload of binary `operator-=` to subtract/assign two angle values
|
||||||
|
///
|
||||||
|
/// \param left Left operand (an angle)
|
||||||
|
/// \param right Right operand (an angle)
|
||||||
|
///
|
||||||
|
/// \return Difference of the two angle values
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle& operator-=(Angle& left, Angle right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Angle
|
||||||
|
/// \brief Overload of binary `operator*` to scale an angle value
|
||||||
|
///
|
||||||
|
/// \param left Left operand (an angle)
|
||||||
|
/// \param right Right operand (a number)
|
||||||
|
///
|
||||||
|
/// \return `left` multiplied by `right`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr Angle operator*(Angle left, float right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Angle
|
||||||
|
/// \brief Overload of binary `operator*` to scale an angle value
|
||||||
|
///
|
||||||
|
/// \param left Left operand (a number)
|
||||||
|
/// \param right Right operand (an angle)
|
||||||
|
///
|
||||||
|
/// \return `left` multiplied by `right`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr Angle operator*(float left, Angle right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Angle
|
||||||
|
/// \brief Overload of binary `operator*=` to scale/assign an angle value
|
||||||
|
///
|
||||||
|
/// \param left Left operand (an angle)
|
||||||
|
/// \param right Right operand (a number)
|
||||||
|
///
|
||||||
|
/// \return `left` multiplied by `right`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle& operator*=(Angle& left, float right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Angle
|
||||||
|
/// \brief Overload of binary `operator/` to scale an angle value
|
||||||
|
///
|
||||||
|
/// \param left Left operand (an angle)
|
||||||
|
/// \param right Right operand (a number)
|
||||||
|
///
|
||||||
|
/// \return `left` divided by `right`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr Angle operator/(Angle left, float right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Angle
|
||||||
|
/// \brief Overload of binary `operator/=` to scale/assign an angle value
|
||||||
|
///
|
||||||
|
/// \param left Left operand (an angle)
|
||||||
|
/// \param right Right operand (a number)
|
||||||
|
///
|
||||||
|
/// \return `left` divided by `right`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle& operator/=(Angle& left, float right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Angle
|
||||||
|
/// \brief Overload of binary `operator/` to compute the ratio of two angle values
|
||||||
|
///
|
||||||
|
/// \param left Left operand (an angle)
|
||||||
|
/// \param right Right operand (an angle)
|
||||||
|
///
|
||||||
|
/// \return `left` divided by `right`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr float operator/(Angle left, Angle right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Angle
|
||||||
|
/// \brief Overload of binary `operator%` to compute modulo of an angle value.
|
||||||
|
///
|
||||||
|
/// Right hand angle must be greater than zero.
|
||||||
|
///
|
||||||
|
/// Examples:
|
||||||
|
/// \code
|
||||||
|
/// sf::degrees(90) % sf::degrees(40) // 10 degrees
|
||||||
|
/// sf::degrees(-90) % sf::degrees(40) // 30 degrees (not -10)
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \param left Left operand (an angle)
|
||||||
|
/// \param right Right operand (an angle)
|
||||||
|
///
|
||||||
|
/// \return `left` modulo `right`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr Angle operator%(Angle left, Angle right);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates Angle
|
||||||
|
/// \brief Overload of binary `operator%=` to compute/assign remainder of an angle value
|
||||||
|
///
|
||||||
|
/// \param left Left operand (an angle)
|
||||||
|
/// \param right Right operand (an angle)
|
||||||
|
///
|
||||||
|
/// \return `left` modulo `right`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle& operator%=(Angle& left, Angle right);
|
||||||
|
|
||||||
|
namespace Literals
|
||||||
|
{
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates sf::Angle
|
||||||
|
/// \brief User defined literal for angles in degrees, e.g.\ `10.5_deg`
|
||||||
|
///
|
||||||
|
/// \param angle Angle in degrees
|
||||||
|
///
|
||||||
|
/// \return Angle
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr Angle operator""_deg(long double angle);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates sf::Angle
|
||||||
|
/// \brief User defined literal for angles in degrees, e.g.\ `90_deg`
|
||||||
|
///
|
||||||
|
/// \param angle Angle in degrees
|
||||||
|
///
|
||||||
|
/// \return Angle
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr Angle operator""_deg(unsigned long long int angle);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates sf::Angle
|
||||||
|
/// \brief User defined literal for angles in radians, e.g.\ `0.1_rad`
|
||||||
|
///
|
||||||
|
/// \param angle Angle in radians
|
||||||
|
///
|
||||||
|
/// \return Angle
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr Angle operator""_rad(long double angle);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \relates sf::Angle
|
||||||
|
/// \brief User defined literal for angles in radians, e.g.\ `2_rad`
|
||||||
|
///
|
||||||
|
/// \param angle Angle in radians
|
||||||
|
///
|
||||||
|
/// \return Angle
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] constexpr Angle operator""_rad(unsigned long long int angle);
|
||||||
|
|
||||||
|
} // namespace Literals
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
#include <SFML/System/Angle.inl>
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::Angle
|
||||||
|
/// \ingroup system
|
||||||
|
///
|
||||||
|
/// `sf::Angle` encapsulates an angle value in a flexible way.
|
||||||
|
/// It allows for defining an angle value either as a number
|
||||||
|
/// of degrees or radians. It also works the other way
|
||||||
|
/// around. You can read an angle value as either a number
|
||||||
|
/// of degrees or radians.
|
||||||
|
///
|
||||||
|
/// By using such a flexible interface, the API doesn't
|
||||||
|
/// impose any fixed type or unit for angle values and lets
|
||||||
|
/// the user choose their own preferred representation.
|
||||||
|
///
|
||||||
|
/// Angle values support the usual mathematical operations.
|
||||||
|
/// You can add or subtract two angles, multiply or divide
|
||||||
|
/// an angle by a number, compare two angles, etc.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// sf::Angle a1 = sf::degrees(90);
|
||||||
|
/// float radians = a1.asRadians(); // 1.5708f
|
||||||
|
///
|
||||||
|
/// sf::Angle a2 = sf::radians(3.141592654f);
|
||||||
|
/// float degrees = a2.asDegrees(); // 180.0f
|
||||||
|
///
|
||||||
|
/// using namespace sf::Literals;
|
||||||
|
/// sf::Angle a3 = 10_deg; // 10 degrees
|
||||||
|
/// sf::Angle a4 = 1.5_deg; // 1.5 degrees
|
||||||
|
/// sf::Angle a5 = 1_rad; // 1 radians
|
||||||
|
/// sf::Angle a6 = 3.14_rad; // 3.14 radians
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,274 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/System/Angle.hpp> // NOLINT(misc-header-include-cycle)
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
namespace priv
|
||||||
|
{
|
||||||
|
inline constexpr float pi = 3.141592654f;
|
||||||
|
inline constexpr float tau = pi * 2.f;
|
||||||
|
|
||||||
|
constexpr float positiveRemainder(float a, float b)
|
||||||
|
{
|
||||||
|
assert(b > 0.f && "Cannot calculate remainder with non-positive divisor");
|
||||||
|
const float val = a - static_cast<float>(static_cast<int>(a / b)) * b;
|
||||||
|
return val >= 0.f ? val : val + b;
|
||||||
|
}
|
||||||
|
} // namespace priv
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr float Angle::asDegrees() const
|
||||||
|
{
|
||||||
|
return m_radians * (180.f / priv::pi);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr float Angle::asRadians() const
|
||||||
|
{
|
||||||
|
return m_radians;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle Angle::wrapSigned() const
|
||||||
|
{
|
||||||
|
return radians(priv::positiveRemainder(m_radians + priv::pi, priv::tau) - priv::pi);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle Angle::wrapUnsigned() const
|
||||||
|
{
|
||||||
|
return radians(priv::positiveRemainder(m_radians, priv::tau));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle::Angle(float radians) : m_radians(radians)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle degrees(float angle)
|
||||||
|
{
|
||||||
|
return Angle(angle * (priv::pi / 180.f));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle radians(float angle)
|
||||||
|
{
|
||||||
|
return Angle(angle);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr bool operator==(Angle left, Angle right)
|
||||||
|
{
|
||||||
|
return left.asRadians() == right.asRadians();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr bool operator!=(Angle left, Angle right)
|
||||||
|
{
|
||||||
|
return left.asRadians() != right.asRadians();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr bool operator<(Angle left, Angle right)
|
||||||
|
{
|
||||||
|
return left.asRadians() < right.asRadians();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr bool operator>(Angle left, Angle right)
|
||||||
|
{
|
||||||
|
return left.asRadians() > right.asRadians();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr bool operator<=(Angle left, Angle right)
|
||||||
|
{
|
||||||
|
return left.asRadians() <= right.asRadians();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr bool operator>=(Angle left, Angle right)
|
||||||
|
{
|
||||||
|
return left.asRadians() >= right.asRadians();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle operator-(Angle right)
|
||||||
|
{
|
||||||
|
return radians(-right.asRadians());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle operator+(Angle left, Angle right)
|
||||||
|
{
|
||||||
|
return radians(left.asRadians() + right.asRadians());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle& operator+=(Angle& left, Angle right)
|
||||||
|
{
|
||||||
|
return left = left + right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle operator-(Angle left, Angle right)
|
||||||
|
{
|
||||||
|
return radians(left.asRadians() - right.asRadians());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle& operator-=(Angle& left, Angle right)
|
||||||
|
{
|
||||||
|
return left = left - right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle operator*(Angle left, float right)
|
||||||
|
{
|
||||||
|
return radians(left.asRadians() * right);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle operator*(float left, Angle right)
|
||||||
|
{
|
||||||
|
return right * left;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle& operator*=(Angle& left, float right)
|
||||||
|
{
|
||||||
|
return left = left * right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle operator/(Angle left, float right)
|
||||||
|
{
|
||||||
|
assert(right != 0.f && "Angle::operator/ cannot divide by 0");
|
||||||
|
return radians(left.asRadians() / right);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle& operator/=(Angle& left, float right)
|
||||||
|
{
|
||||||
|
assert(right != 0.f && "Angle::operator/= cannot divide by 0");
|
||||||
|
return left = left / right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr float operator/(Angle left, Angle right)
|
||||||
|
{
|
||||||
|
assert(right.asRadians() != 0.f && "Angle::operator/ cannot divide by 0");
|
||||||
|
return left.asRadians() / right.asRadians();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle operator%(Angle left, Angle right)
|
||||||
|
{
|
||||||
|
assert(right.asRadians() != 0.f && "Angle::operator% cannot modulus by 0");
|
||||||
|
return radians(priv::positiveRemainder(left.asRadians(), right.asRadians()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle& operator%=(Angle& left, Angle right)
|
||||||
|
{
|
||||||
|
assert(right.asRadians() != 0.f && "Angle::operator%= cannot modulus by 0");
|
||||||
|
return left = left % right;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Literals
|
||||||
|
{
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle operator""_deg(long double angle)
|
||||||
|
{
|
||||||
|
return degrees(static_cast<float>(angle));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle operator""_deg(unsigned long long angle)
|
||||||
|
{
|
||||||
|
return degrees(static_cast<float>(angle));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle operator""_rad(long double angle)
|
||||||
|
{
|
||||||
|
return radians(static_cast<float>(angle));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
constexpr Angle operator""_rad(unsigned long long angle)
|
||||||
|
{
|
||||||
|
return radians(static_cast<float>(angle));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Literals
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Static member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Note: the 'inline' keyword here is technically not required, but VS2019 fails
|
||||||
|
// to compile with a bogus "multiple definition" error if not explicitly used.
|
||||||
|
inline constexpr Angle Angle::Zero;
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
@ -0,0 +1,196 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/System/Export.hpp>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <ratio>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#ifdef SFML_SYSTEM_ANDROID
|
||||||
|
#include <SFML/System/SuspendAwareClock.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
namespace priv
|
||||||
|
{
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Chooses a monotonic clock of highest resolution
|
||||||
|
///
|
||||||
|
/// The `high_resolution_clock` is usually an alias for other
|
||||||
|
/// clocks: `steady_clock` or `system_clock`, whichever has a
|
||||||
|
/// higher precision.
|
||||||
|
///
|
||||||
|
/// `sf::Clock`, however, is aimed towards monotonic time
|
||||||
|
/// measurements and so `system_clock` could never be a choice
|
||||||
|
/// as its subject to discontinuous jumps in the system time
|
||||||
|
/// (e.g., if the system administrator manually changes
|
||||||
|
/// the clock), and by the incremental adjustments performed
|
||||||
|
/// by `adjtime` and Network Time Protocol. On the other
|
||||||
|
/// hand, monotonic clocks are unaffected by this behavior.
|
||||||
|
///
|
||||||
|
/// Note: Linux implementation of a monotonic clock that
|
||||||
|
/// takes sleep time into account is represented by
|
||||||
|
/// `CLOCK_BOOTTIME`. Android devices can define the macro:
|
||||||
|
/// `SFML_ANDROID_USE_SUSPEND_AWARE_CLOCK` to use a separate
|
||||||
|
/// implementation of that clock, instead.
|
||||||
|
///
|
||||||
|
/// For more information on Linux clocks visit:
|
||||||
|
/// https://linux.die.net/man/2/clock_gettime
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#if defined(SFML_SYSTEM_ANDROID) && defined(SFML_ANDROID_USE_SUSPEND_AWARE_CLOCK)
|
||||||
|
using ClockImpl = SuspendAwareClock;
|
||||||
|
#else
|
||||||
|
using ClockImpl = std::conditional_t<std::chrono::high_resolution_clock::is_steady, std::chrono::high_resolution_clock, std::chrono::steady_clock>;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static_assert(ClockImpl::is_steady, "Provided implementation is not a monotonic clock");
|
||||||
|
static_assert(std::ratio_less_equal_v<ClockImpl::period, std::micro>,
|
||||||
|
"Clock resolution is too low. Expecting at least a microsecond precision");
|
||||||
|
|
||||||
|
} // namespace priv
|
||||||
|
|
||||||
|
class Time;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Utility class that measures the elapsed time
|
||||||
|
///
|
||||||
|
/// The clock starts automatically after being constructed.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_SYSTEM_API Clock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the elapsed time
|
||||||
|
///
|
||||||
|
/// This function returns the time elapsed since the last call
|
||||||
|
/// to `restart()` (or the construction of the instance if `restart()`
|
||||||
|
/// has not been called).
|
||||||
|
///
|
||||||
|
/// \return Time elapsed
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] Time getElapsedTime() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Check whether the clock is running
|
||||||
|
///
|
||||||
|
/// \return `true` if the clock is running, `false` otherwise
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool isRunning() const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Start the clock
|
||||||
|
///
|
||||||
|
/// \see `stop`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void start();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Stop the clock
|
||||||
|
///
|
||||||
|
/// \see `start`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Restart the clock
|
||||||
|
///
|
||||||
|
/// This function puts the time counter back to zero, returns
|
||||||
|
/// the elapsed time, and leaves the clock in a running state.
|
||||||
|
///
|
||||||
|
/// \return Time elapsed
|
||||||
|
///
|
||||||
|
/// \see `reset`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Time restart();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Reset the clock
|
||||||
|
///
|
||||||
|
/// This function puts the time counter back to zero, returns
|
||||||
|
/// the elapsed time, and leaves the clock in a paused state.
|
||||||
|
///
|
||||||
|
/// \return Time elapsed
|
||||||
|
///
|
||||||
|
/// \see `restart`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Time reset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
priv::ClockImpl::time_point m_refPoint{priv::ClockImpl::now()}; //!< Time of last reset
|
||||||
|
priv::ClockImpl::time_point m_stopPoint; //!< Time of last stop
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::Clock
|
||||||
|
/// \ingroup system
|
||||||
|
///
|
||||||
|
/// `sf::Clock` is a lightweight class for measuring time.
|
||||||
|
///
|
||||||
|
/// It provides the most precise time that the underlying
|
||||||
|
/// OS can achieve (generally microseconds or nanoseconds).
|
||||||
|
/// It also ensures monotonicity, which means that the returned
|
||||||
|
/// time can never go backward, even if the system time is
|
||||||
|
/// changed.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// sf::Clock clock;
|
||||||
|
/// ...
|
||||||
|
/// Time time1 = clock.getElapsedTime();
|
||||||
|
/// ...
|
||||||
|
/// Time time2 = clock.restart();
|
||||||
|
/// ...
|
||||||
|
/// Time time3 = clock.reset();
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// The `sf::Time` value returned by the clock can then be
|
||||||
|
/// converted to a number of seconds, milliseconds or even
|
||||||
|
/// microseconds.
|
||||||
|
///
|
||||||
|
/// \see `sf::Time`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/System/Export.hpp>
|
||||||
|
|
||||||
|
#include <iosfwd>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Standard stream used by SFML to output warnings and errors
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] SFML_SYSTEM_API std::ostream& err();
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \fn sf::err
|
||||||
|
/// \ingroup system
|
||||||
|
///
|
||||||
|
/// By default, `sf::err()` outputs to the same location as `std::cerr`,
|
||||||
|
/// (-> the stderr descriptor) which is the console if there's
|
||||||
|
/// one available.
|
||||||
|
///
|
||||||
|
/// It is a standard `std::ostream` instance, so it supports all the
|
||||||
|
/// insertion operations defined by the STL
|
||||||
|
/// (`operator<<`, manipulators, etc.).
|
||||||
|
///
|
||||||
|
/// `sf::err()` can be redirected to write to another output, independently
|
||||||
|
/// of `std::cerr`, by using the `rdbuf()` function provided by the
|
||||||
|
/// `std::ostream` class.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// \code
|
||||||
|
/// // Redirect to a file
|
||||||
|
/// std::ofstream file("sfml-log.txt");
|
||||||
|
/// std::streambuf* previous = sf::err().rdbuf(file.rdbuf());
|
||||||
|
///
|
||||||
|
/// // Redirect to nothing
|
||||||
|
/// sf::err().rdbuf(nullptr);
|
||||||
|
///
|
||||||
|
/// // Restore the original output
|
||||||
|
/// sf::err().rdbuf(previous);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \return Reference to `std::ostream` representing the SFML error stream
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/System/Export.hpp>
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Library-specific exception type
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_SYSTEM_API Exception : public std::runtime_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using std::runtime_error::runtime_error;
|
||||||
|
};
|
||||||
|
} // namespace sf
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Config.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Portable import / export macros
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#if defined(SFML_SYSTEM_EXPORTS)
|
||||||
|
|
||||||
|
#define SFML_SYSTEM_API SFML_API_EXPORT
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define SFML_SYSTEM_API SFML_API_IMPORT
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,212 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Config.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/Export.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/InputStream.hpp>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
#ifdef SFML_SYSTEM_ANDROID
|
||||||
|
namespace sf::priv
|
||||||
|
{
|
||||||
|
class SFML_SYSTEM_API ResourceStream;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Implementation of input stream based on a file
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_SYSTEM_API FileInputStream : public InputStream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// Construct a file input stream that is not associated
|
||||||
|
/// with a file to read.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
FileInputStream();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default destructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
~FileInputStream() override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Deleted copy constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
FileInputStream(const FileInputStream&) = delete;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Deleted copy assignment
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
FileInputStream& operator=(const FileInputStream&) = delete;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
FileInputStream(FileInputStream&&) noexcept;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Move assignment
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
FileInputStream& operator=(FileInputStream&&) noexcept;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Construct the stream from a file path
|
||||||
|
///
|
||||||
|
/// \param filename Name of the file to open
|
||||||
|
///
|
||||||
|
/// \throws sf::Exception on error
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
explicit FileInputStream(const std::filesystem::path& filename);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Open the stream from a file path
|
||||||
|
///
|
||||||
|
/// \param filename Name of the file to open
|
||||||
|
///
|
||||||
|
/// \return `true` on success, `false` on error
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] bool open(const std::filesystem::path& filename);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Read data from the stream
|
||||||
|
///
|
||||||
|
/// After reading, the stream's reading position must be
|
||||||
|
/// advanced by the amount of bytes read.
|
||||||
|
///
|
||||||
|
/// \param data Buffer where to copy the read data
|
||||||
|
/// \param size Desired number of bytes to read
|
||||||
|
///
|
||||||
|
/// \return The number of bytes actually read, or `std::nullopt` on error
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] std::optional<std::size_t> read(void* data, std::size_t size) override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Change the current reading position
|
||||||
|
///
|
||||||
|
/// \param position The position to seek to, from the beginning
|
||||||
|
///
|
||||||
|
/// \return The position actually sought to, or `std::nullopt` on error
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] std::optional<std::size_t> seek(std::size_t position) override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the current reading position in the stream
|
||||||
|
///
|
||||||
|
/// \return The current position, or `std::nullopt` on error.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] std::optional<std::size_t> tell() override;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Return the size of the stream
|
||||||
|
///
|
||||||
|
/// \return The total number of bytes available in the stream, or `std::nullopt` on error
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
std::optional<std::size_t> getSize() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Deleter for stdio file stream that closes the file stream
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
struct FileCloser
|
||||||
|
{
|
||||||
|
void operator()(std::FILE* file);
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#ifdef SFML_SYSTEM_ANDROID
|
||||||
|
std::unique_ptr<priv::ResourceStream> m_androidFile;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::unique_ptr<std::FILE, FileCloser> m_file; //!< stdio file stream
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::FileInputStream
|
||||||
|
/// \ingroup system
|
||||||
|
///
|
||||||
|
/// This class is a specialization of `InputStream` that
|
||||||
|
/// reads from a file on disk.
|
||||||
|
///
|
||||||
|
/// It wraps a file in the common `InputStream` interface
|
||||||
|
/// and therefore allows to use generic classes or functions
|
||||||
|
/// that accept such a stream, with a file on disk as the data
|
||||||
|
/// source.
|
||||||
|
///
|
||||||
|
/// In addition to the virtual functions inherited from
|
||||||
|
/// `InputStream`, `FileInputStream` adds a function to
|
||||||
|
/// specify the file to open.
|
||||||
|
///
|
||||||
|
/// SFML resource classes can usually be loaded directly from
|
||||||
|
/// a filename, so this class shouldn't be useful to you unless
|
||||||
|
/// you create your own algorithms that operate on an InputStream.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// void process(InputStream& stream);
|
||||||
|
///
|
||||||
|
/// std::optional stream = sf::FileInputStream::open("some_file.dat");
|
||||||
|
/// if (stream)
|
||||||
|
/// process(*stream);
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `InputStream`, `MemoryInputStream`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
@ -0,0 +1,166 @@
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// SFML - Simple and Fast Multimedia Library
|
||||||
|
// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org)
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it freely,
|
||||||
|
// subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented;
|
||||||
|
// you must not claim that you wrote the original software.
|
||||||
|
// If you use this software in a product, an acknowledgment
|
||||||
|
// in the product documentation would be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such,
|
||||||
|
// and must not be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Config.hpp>
|
||||||
|
|
||||||
|
#include <SFML/System/Export.hpp>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Abstract class for custom file input streams
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class SFML_SYSTEM_API InputStream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Virtual destructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
virtual ~InputStream() = default;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Read data from the stream
|
||||||
|
///
|
||||||
|
/// After reading, the stream's reading position must be
|
||||||
|
/// advanced by the amount of bytes read.
|
||||||
|
///
|
||||||
|
/// \param data Buffer where to copy the read data
|
||||||
|
/// \param size Desired number of bytes to read
|
||||||
|
///
|
||||||
|
/// \return The number of bytes actually read, or `std::nullopt` on error
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] virtual std::optional<std::size_t> read(void* data, std::size_t size) = 0;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Change the current reading position
|
||||||
|
///
|
||||||
|
/// \param position The position to seek to, from the beginning
|
||||||
|
///
|
||||||
|
/// \return The position actually sought to, or `std::nullopt` on error
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] virtual std::optional<std::size_t> seek(std::size_t position) = 0;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Get the current reading position in the stream
|
||||||
|
///
|
||||||
|
/// \return The current position, or `std::nullopt` on error.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
[[nodiscard]] virtual std::optional<std::size_t> tell() = 0;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Return the size of the stream
|
||||||
|
///
|
||||||
|
/// \return The total number of bytes available in the stream, or `std::nullopt` on error
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
virtual std::optional<std::size_t> getSize() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \class sf::InputStream
|
||||||
|
/// \ingroup system
|
||||||
|
///
|
||||||
|
/// This class allows users to define their own file input sources
|
||||||
|
/// from which SFML can load resources.
|
||||||
|
///
|
||||||
|
/// SFML resource classes like `sf::Texture` and
|
||||||
|
/// `sf::SoundBuffer` provide `loadFromFile` and `loadFromMemory` functions,
|
||||||
|
/// which read data from conventional sources. However, if you
|
||||||
|
/// have data coming from a different source (over a network,
|
||||||
|
/// embedded, encrypted, compressed, etc) you can derive your
|
||||||
|
/// own class from `sf::InputStream` and load SFML resources with
|
||||||
|
/// their `loadFromStream` function.
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// \code
|
||||||
|
/// // custom stream class that reads from inside a zip file
|
||||||
|
/// class ZipStream : public sf::InputStream
|
||||||
|
/// {
|
||||||
|
/// public:
|
||||||
|
///
|
||||||
|
/// ZipStream(const std::string& archive);
|
||||||
|
///
|
||||||
|
/// [[nodiscard]] bool open(const std::filesystem::path& filename);
|
||||||
|
///
|
||||||
|
/// [[nodiscard]] std::optional<std::size_t> read(void* data, std::size_t size);
|
||||||
|
///
|
||||||
|
/// [[nodiscard]] std::optional<std::size_t> seek(std::size_t position);
|
||||||
|
///
|
||||||
|
/// [[nodiscard]] std::optional<std::size_t> tell();
|
||||||
|
///
|
||||||
|
/// std::optional<std::size_t> getSize();
|
||||||
|
///
|
||||||
|
/// private:
|
||||||
|
///
|
||||||
|
/// ...
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// // now you can load textures...
|
||||||
|
/// ZipStream stream("resources.zip");
|
||||||
|
///
|
||||||
|
/// if (!stream.open("images/img.png"))
|
||||||
|
/// {
|
||||||
|
/// // Handle error...
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// const sf::Texture texture(stream);
|
||||||
|
///
|
||||||
|
/// // musics...
|
||||||
|
/// sf::Music music;
|
||||||
|
/// ZipStream stream("resources.zip");
|
||||||
|
///
|
||||||
|
/// if (!stream.open("musics/msc.ogg"))
|
||||||
|
/// {
|
||||||
|
/// // Handle error...
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// if (!music.openFromStream(stream))
|
||||||
|
/// {
|
||||||
|
/// // Handle error...
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // etc.
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \see `FileInputStream`, `MemoryInputStream`
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue