Compare commits

...

61 Commits

Author SHA1 Message Date
Jeff Moe d0cec92b62 celestia screenshot 2022-05-20 22:32:56 -06:00
Jeff Moe 34a3b5a9cd Install *.deb 2022-05-20 22:06:09 -06:00
Jeff Moe 470cbc3c99 oh. Use separate celestiacontent repo 2022-05-20 21:57:31 -06:00
Jeff Moe 88047d9b06 ignore vi 2022-05-20 21:56:32 -06:00
Jeff Moe 71cf5dda82 celestia-gaia-stardb deps, mostly python3 2022-05-20 21:15:01 -06:00
Jeff Moe 646e755964 more ^M 2022-05-20 20:43:19 -06:00
Jeff Moe d00a02c463 star DB perl script had ^M ... 2022-05-20 20:38:51 -06:00
Jeff Moe 791c80d3d0 Package build minihowto 2022-05-20 20:24:19 -06:00
Jeff Moe 7693e49057 Add readmes to install docs 2022-05-20 20:23:19 -06:00
Jeff Moe e5c825b5f0 rm missing qttxf, latest snapshot 2022-05-20 19:58:40 -06:00
Jeff Moe 916ac7be22 Debian notes 2022-05-20 19:50:14 -06:00
Jeff Moe 9878b500b1 readme stub 2022-05-20 19:43:17 -06:00
Jeff Moe 9b561aa551 mv upstream READMEs 2022-05-20 19:42:42 -06:00
dave-kaye 804a5de2a7 Update GTK solar system browser
Add Dwarf Planets and Minor Moons to solar system browser to match Qt version
2022-05-05 10:41:46 +03:00
Andrew Tribick c6a320d086 Allow EOF status after skipping chunks/trailing bytes in 3ds fies.
This shouldn't happen and I cannot reproduce it, but some people
are running into issues with false positive errors.
2022-05-02 19:32:18 +02:00
Andrew Tribick 0c177cae01 Rewrite 3DS loader 2022-05-02 19:32:18 +02:00
Andrew Tribick bc75235150 Skip testing externally-provided charconv 2022-04-30 22:16:25 +02:00
Hleb Valoshka 4c6fa126d6 Remove remnants of the old font rendering system
Closes: #1359
2022-04-17 13:54:24 +03:00
Hleb Valoshka 698d03cd82 [gtk] Fix display of rings and fading orbits
Closes: #1360
2022-04-17 13:54:09 +03:00
Hleb Valoshka 6ab7660e0c [cmake] Don't mix plain & keyword target_link_libraries()
Closes: #1357
2022-04-07 10:45:15 +03:00
Levin Li b4cf176ac3 Fix nebula/ssc sprite rendering on hidpi setting 2022-04-02 07:53:25 -07:00
Georgi 71a65fb33c updated guide 2022-03-31 22:34:58 -07:00
Georgi 704a075d0a updated demo 2022-03-31 22:34:58 -07:00
Georgi a87dc1bc62 added demo_bg.cel 2022-03-31 22:34:58 -07:00
Hleb Valoshka f4bd55991f Optimize meshes with meshoptimizer library if available 2022-03-07 16:59:47 +03:00
Hleb Valoshka 746b9e3ef3 Optimize model by merging similar meshes 2022-03-07 16:59:47 +03:00
Hleb Valoshka ca80f4448a Optimize mesh by merging similar primitive groups 2022-03-07 16:59:47 +03:00
Hleb Valoshka dee6a216f7 Remove discord from Readme.md 2022-03-03 00:19:33 +03:00
Andrew Tribick 2f77629216 Fix parsing and display of luminosity classes Ia-0, Ia, and Ib
- Allow spaces before luminosity class in stc file
- Allow Ia-0 to be spelled "Ia-0" (as displayed), "Ia0" (as previously), or
  "I-a0" (previous display format) in stc file
- Remove str() and ostream << operators on StellarClass (only used in tests)
2022-02-19 11:33:15 +01:00
Andrew Tribick d2f53d0a56 Supersede not supercede 2022-02-19 11:33:15 +01:00
Hleb Valoshka fb08de771a Create Logger in cmodview 2022-02-18 14:03:41 +03:00
Levin Li 318b4378a9 Fix lua crash in cleanup 2022-02-18 01:30:10 -08:00
Levin Li 6b856b3352 Fix broken star browser 2022-02-11 19:09:16 -08:00
Heiko Becker e51f3d5b97 Drop content submodule from .gitmodules
It's seems a bit confusing to have it in .gitmodules and .gitignore at
the same time.
Furthermore it makes distro packaging fail for my distro.
2022-02-05 21:47:29 +03:00
Andrew Tribick 60ed8238b1 Add integration test for 3ds loader 2022-02-05 09:52:02 +01:00
Hleb Valoshka cbdd9de63f Draw glow before objects
Closes: #1339
2022-01-31 12:20:18 +03:00
transifex-integration[bot] a783eee8fe Translate /po/celestia.pot in ru
translation completed for the source file '/po/celestia.pot'
on the 'ru' language.
2022-01-31 12:19:24 +03:00
Hleb Valoshka 9d60f6e660 [sdl] small cleanup 2022-01-26 22:59:43 +03:00
Hleb Valoshka b7dd51fc81 [sdl] set ShadowMapSize and SolarSystemMaxDistance from config 2022-01-26 22:59:43 +03:00
Hleb Valoshka fecc0ca0a9 [sdl] add support for CELESTIA_DATA_DIR environment variable 2022-01-26 22:59:43 +03:00
Hleb Valoshka c95e554c7a [sdl] allow copy/paste URL to/from a clipboard 2022-01-26 22:59:43 +03:00
Yasushi SHOJI 3702250525 cmod: 3dstocmod: Create logger
Without creating a logger, the command dies with SEGFAULT when
Read3DSFile(std::istream&) tries to print the verbose message.

    GetLogger()->verbose("3DS file, {} bytes\n", chunkSize + 6);

Signed-off-by: Yasushi SHOJI <yashi@spacecubics.com>
2022-01-26 22:59:28 +03:00
Yasushi SHOJI 3a218976bf cmod: Fix VertexAttributeSemantic::Position compilation error
The commit b79959979a extracted cmod::Mesh::Position to
cmod::VertexAttributeSemantic::Position but didn't change this line.

This problem occurs only with cmake -DENABLE_TOOLS=1.

Signed-off-by: Yasushi SHOJI <yashi@spacecubics.com>
2022-01-26 22:59:28 +03:00
SevenSpheres 38f645ff8f Add a vcpkg tip thanks to Andrew Tribick 2022-01-26 10:25:16 -07:00
Andrew Tribick 3a7e6d793b [win] Fix initialization of view options checkboxes 2022-01-26 18:21:44 +01:00
Hleb Valoshka 8f8a2f7677 Optimize calculation of center for renderLargePoint 2022-01-26 01:10:46 +03:00
Hleb Valoshka 772fe24e1b Reuse PointStarVertexBuffer do draw objects as points 2022-01-26 01:10:46 +03:00
Hleb Valoshka 96e282e161 Add methods to reset current matrices 2022-01-26 01:10:46 +03:00
Hleb Valoshka 20a4d13328 Refactor code to draw objects as points
* provide common routine to calculate point size
 * precalculate saturation magnitude
 * remove unused variables
2022-01-26 01:10:46 +03:00
Hleb Valoshka 29a2e1ec1c Update .clang-format 2022-01-26 01:01:15 +03:00
Hleb Valoshka 2cb9da1085 [win32] Convert decimal point & thousands separator to UTF-8 2022-01-25 23:28:17 +03:00
Hleb Valoshka 34d18bb316 Add missing include to fix selfshadowing
Fixes: #1330
2022-01-23 11:39:33 +03:00
Hleb Valoshka f969b37c3e Refactor font handling code
* Add cache for loaded fonts
 * Replace `const std::string &` with `std::string_view` in print
 * Remove static load method
 * Reformat with clang-format
 * Return bool from celestiacore::set*Font
2022-01-20 12:10:30 +03:00
Andrew Tribick 3c9334ece9 [qt] Do not capture menu bars when taking screenshots 2022-01-18 19:00:54 +01:00
Levin Li fc561a7927 Add methods for handling HiDPI, scale icons, splash images using StretchBlt 2022-01-16 02:27:25 -08:00
Levin Li 9d1bcf14b3 Enable dpiAwareness in manifest 2022-01-16 02:27:25 -08:00
Andrew Tribick 40ed2011bf Use qreal to store return value of devicePixelRatioF 2022-01-15 18:13:28 +01:00
Andrew Tribick 7cf1aac419 [qt] Experimental Qt6 support
- Switch from legacy QGLWidget to QOpenGLWidget

- [win32] Use a frameless window 1 pixel larger than the monitor instead of a
  fullscreen window, in order to avoid issues showing context menus

- Fix a settings bug where window state on the fullscreen transition was not
  saved in the MainWindow group.
2022-01-15 18:13:28 +01:00
Levin Li 25cbfabba0 Enable visual styles for Win32 controls 2022-01-14 21:13:55 -08:00
Andrew Tribick 245225dcdf Fix for SonarScanner out of bound false positive 2022-01-12 21:40:21 +01:00
Andrew Tribick 410f86fc88 Use while loop to fix SonarScanner issue 2022-01-08 21:25:52 +01:00
90 changed files with 2434 additions and 4555 deletions

View File

@ -1,47 +1,63 @@
AccessModifierOffset: -3 ---
AlignEscapedNewlinesLeft: true AccessModifierOffset: '-4'
AlignTrailingComments: true AlignAfterOpenBracket: AlwaysBreak
AllowAllParametersOfDeclarationOnNextLine: false AlignConsecutiveMacros: 'true'
AllowShortFunctionsOnASingleLine: true AlignConsecutiveAssignments: 'true'
AllowShortIfStatementsOnASingleLine: false AlignConsecutiveDeclarations: 'true'
AllowShortLoopsOnASingleLine: false AlignEscapedNewlines: Left
AlwaysBreakBeforeMultilineStrings: false AlignOperands: 'true'
AlwaysBreakTemplateDeclarations: true AlignTrailingComments: 'true'
BinPackParameters: false AllowAllArgumentsOnNextLine: 'false'
BreakBeforeBinaryOperators: false AllowAllConstructorInitializersOnNextLine: 'false'
AllowAllParametersOfDeclarationOnNextLine: 'false'
AllowShortBlocksOnASingleLine: 'false'
AllowShortCaseLabelsOnASingleLine: 'false'
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: 'false'
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: 'true'
AlwaysBreakAfterReturnType: TopLevelDefinitions
AlwaysBreakBeforeMultilineStrings: 'false'
AlwaysBreakTemplateDeclarations: 'Yes'
BinPackArguments: 'false'
BinPackParameters: 'false'
BreakBeforeBinaryOperators: All
BreakBeforeBraces: Allman BreakBeforeBraces: Allman
BreakBeforeTernaryOperators: false BreakBeforeTernaryOperators: 'false'
BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: AfterColon
ColumnLimit: 80 BreakInheritanceList: AfterColon
CommentPragmas: '' BreakStringLiterals: 'true'
ConstructorInitializerAllOnOneLineOrOnePerLine: false ColumnLimit: '100'
ConstructorInitializerIndentWidth: 0 CompactNamespaces: 'false'
ContinuationIndentWidth: 0 ConstructorInitializerAllOnOneLineOrOnePerLine: 'false'
Cpp11BracedListStyle: false Cpp11BracedListStyle: 'false'
DerivePointerBinding: false FixNamespaceComments: 'true'
IndentCaseLabels: false IncludeBlocks: Regroup
IndentFunctionDeclarationAfterType: false IndentCaseLabels: 'false'
IndentWidth: 4 IndentPPDirectives: None
IndentWidth: '4'
IndentWrappedFunctionNames: 'false'
KeepEmptyLinesAtTheStartOfBlocks: 'false'
Language: Cpp Language: Cpp
MaxEmptyLinesToKeep: 2 MaxEmptyLinesToKeep: '1'
NamespaceIndentation: None NamespaceIndentation: None
ObjCSpaceAfterProperty: true PointerAlignment: Right
ObjCSpaceBeforeProtocolList: true ReflowComments: 'true'
PenaltyBreakBeforeFirstCallParameter: 100 SortIncludes: 'true'
PenaltyBreakComment: 100 SortUsingDeclarations: 'true'
PenaltyBreakFirstLessLess: 0 SpaceAfterLogicalNot: 'false'
PenaltyBreakString: 100 SpaceAfterTemplateKeyword: 'false'
PenaltyExcessCharacter: 1 SpaceBeforeAssignmentOperators: 'true'
PenaltyReturnTypeOnItsOwnLine: 20 SpaceBeforeCtorInitializerColon: 'true'
PointerBindsToType: true SpaceBeforeInheritanceColon: 'true'
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false SpaceBeforeRangeBasedForLoopColon: 'true'
SpacesBeforeTrailingComments: 1 SpaceInEmptyParentheses: 'false'
SpacesInAngles: false SpacesBeforeTrailingComments: '1'
SpacesInCStyleCastParentheses: false SpacesInAngles: 'false'
SpacesInContainerLiterals: false SpacesInParentheses: 'false'
SpacesInParentheses: false SpacesInSquareBrackets: 'false'
Standard: Cpp11 Standard: c++17
TabWidth: 4 TabWidth: '4'
UseTab: Never UseTab: Never
UseCRLF: 'false'

2
.gitignore vendored
View File

@ -9,6 +9,7 @@ Release/
*.la *.la
*.exe *.exe
*.dll *.dll
*.swp
.DS_Store .DS_Store
po*/*.gmo po*/*.gmo
po*/POTFILES po*/POTFILES
@ -23,3 +24,4 @@ models/
textures/ textures/
mingw/ mingw/
content/ content/
CMakeSettings.json

3
.gitmodules vendored
View File

@ -1,9 +1,6 @@
[submodule "thirdparty/Spice"] [submodule "thirdparty/Spice"]
path = thirdparty/Spice path = thirdparty/Spice
url = https://github.com/OpenSpace/Spice.git url = https://github.com/OpenSpace/Spice.git
[submodule "content"]
path = content
url = https://github.com/CelestiaProject/CelestiaContent.git
[submodule "thirdparty/fmt"] [submodule "thirdparty/fmt"]
path = thirdparty/fmt path = thirdparty/fmt
url = https://github.com/fmtlib/fmt.git url = https://github.com/fmtlib/fmt.git

View File

@ -2,6 +2,11 @@ cmake_minimum_required(VERSION 3.8)
option(LEGACY_OPENGL_LIBS "Use legacy OpenGL libraries instead of glvnd library (Default: off)" OFF) option(LEGACY_OPENGL_LIBS "Use legacy OpenGL libraries instead of glvnd library (Default: off)" OFF)
# Plain and keyword target_link_libraries() signatures cannot be mixed
if (POLICY CMP0023)
cmake_policy(SET CMP0023 NEW)
endif()
# Honor link flags in try_compile() # Honor link flags in try_compile()
if (POLICY CMP0056) if (POLICY CMP0056)
cmake_policy(SET CMP0056 NEW) cmake_policy(SET CMP0056 NEW)
@ -57,6 +62,7 @@ option(FAST_MATH "Build with unsafe fast-math compiller option (Default: of
option(ENABLE_TESTS "Enable unit tests? (Default: off)" OFF) option(ENABLE_TESTS "Enable unit tests? (Default: off)" OFF)
option(ENABLE_GLES "Build for OpenGL ES 2.0 instead of OpenGL 2.1 (Default: off)" OFF) option(ENABLE_GLES "Build for OpenGL ES 2.0 instead of OpenGL 2.1 (Default: off)" OFF)
option(USE_GTKGLEXT "Use libgtkglext1 for GTK2 frontend (Default: on)" ON) option(USE_GTKGLEXT "Use libgtkglext1 for GTK2 frontend (Default: on)" ON)
option(USE_QT6 "Use Qt6 in Qt frontend (Default: off)" OFF)
option(USE_GTK3 "Use Gtk3 in GTK2 frontend (Default: off)" OFF) option(USE_GTK3 "Use Gtk3 in GTK2 frontend (Default: off)" OFF)
if(ENABLE_GLES) if(ENABLE_GLES)
@ -244,6 +250,14 @@ endif()
find_package(Freetype REQUIRED) find_package(Freetype REQUIRED)
link_libraries(Freetype::Freetype) link_libraries(Freetype::Freetype)
find_package(meshoptimizer CONFIG QUIET)
if(meshoptimizer_FOUND)
message(STATUS "Found meshoptimizer library")
set(HAVE_MESHOPTIMIZER 1)
else()
message(STATUS "meshoptimizer library is missing")
endif()
#[[ #[[
get_cmake_property(_variableNames VARIABLES) get_cmake_property(_variableNames VARIABLES)
list (SORT _variableNames) list (SORT _variableNames)

108
ChangeLog
View File

@ -246,7 +246,7 @@ Code:
* Windows version: InstallShield setup * Windows version: InstallShield setup
* Windows version: added controls help dialog * Windows version: added controls help dialog
* UNIX version: implemented find object and about dialogs (Gnome/Gtk only) * UNIX version: implemented find object and about dialogs (Gnome/Gtk only)
Code: Code:
* Moved star browser and solar system browser code into separate modules * Moved star browser and solar system browser code into separate modules
* Fixed DPRINTF macro so it's not broken in g++ * Fixed DPRINTF macro so it's not broken in g++
@ -276,7 +276,7 @@ Code:
textures added to OpenGL Info dialog. textures added to OpenGL Info dialog.
* New objects: Comet Borrelly, the giant Kuiper Belt object 2001 KX76, * New objects: Comet Borrelly, the giant Kuiper Belt object 2001 KX76,
and the Hubble Space Telescope and the Hubble Space Telescope
Code: Code:
* Rewrote texture and model managers * Rewrote texture and model managers
* Cleaned up simulation.cpp to use frames of reference and eliminated a lot * Cleaned up simulation.cpp to use frames of reference and eliminated a lot
@ -393,7 +393,7 @@ Code:
a single modeless dialog. a single modeless dialog.
* Fixed period and rotation of Phoebe * Fixed period and rotation of Phoebe
1.2.1 1.2.1
* Unix: configure.in changes to better find OpenGL libraries by Bruckner. * Unix: configure.in changes to better find OpenGL libraries by Bruckner.
* Added accurate orbital calculations for Galilean satellites. * Added accurate orbital calculations for Galilean satellites.
@ -404,7 +404,7 @@ Code:
* Windows: Fixed crash that occurred when recalling a location with * Windows: Fixed crash that occurred when recalling a location with
no selection no selection
1.2.2 1.2.2
* Improved find algorithm for starnames, and combined names from hdnames.dat * Improved find algorithm for starnames, and combined names from hdnames.dat
into starnames.dat. Also added several additional names and variant spellings into starnames.dat. Also added several additional names and variant spellings
@ -557,7 +557,7 @@ Code:
* New colors for celestial grid and constellation figures * New colors for celestial grid and constellation figures
* Tuning of Gnome GUI: underlined key accelerators, enabled operation of all * Tuning of Gnome GUI: underlined key accelerators, enabled operation of all
dialogs and menus with ALT <key>, arrow keys, and Tab dialogs and menus with ALT <key>, arrow keys, and Tab
* Linux: GUI now synced with current state of pixel/vertex shaders * Linux: GUI now synced with current state of pixel/vertex shaders
* New keyboard bindings: * New keyboard bindings:
Ctrl+Y : automag toggle Ctrl+Y : automag toggle
Ctrl+T : toggle display of comet tails Ctrl+T : toggle display of comet tails
@ -572,16 +572,16 @@ Code:
when building with VS.NET when building with VS.NET
* Cleaned up OpenGL extension initialization * Cleaned up OpenGL extension initialization
* Significantly improved the reliability of object selection via mouse * Significantly improved the reliability of object selection via mouse
click, notably for small fields of view in the arcsec range. click, notably for small fields of view in the arcsec range.
* Fixed the 'move' script command * Fixed the 'move' script command
* New script commands: setfaintestautomag45deg {magnitude float}, * New script commands: setfaintestautomag45deg {magnitude float},
lookback {} lookback {}
* [,] keys now adjust the limiting magnitude at 45 degrees * [,] keys now adjust the limiting magnitude at 45 degrees
field of view, if automag is ON. Values displayed via flash messages field of view, if automag is ON. Values displayed via flash messages
* Associated the 'looking back' operation with the '*' key shortcut * Associated the 'looking back' operation with the '*' key shortcut
* Fixed bug in orbits of Galilean moons * Fixed bug in orbits of Galilean moons
* Corrected equatorial planes and rotation offsets for the major planets * Corrected equatorial planes and rotation offsets for the major planets
* Linux: Added KDE interface, all features of the GTK interface are * Linux: Added KDE interface, all features of the GTK interface are
available (except for the Tour Guide), new features include: available (except for the Tour Guide), new features include:
- Bookmarks / URLs; - Bookmarks / URLs;
- History navigation;* Improved drag and drop of cel:// URLs on Windows - History navigation;* Improved drag and drop of cel:// URLs on Windows
@ -632,8 +632,8 @@ Code:
- Markers may also be set on objects using the right-click context menu - Markers may also be set on objects using the right-click context menu
- Added mark/unmark commands for scripts - Added mark/unmark commands for scripts
- Bound Ctrl+K to toggle display of markers - Bound Ctrl+K to toggle display of markers
- Added flash messages indicating on|off status of markers - Added flash messages indicating on|off status of markers
- Implemented markers into KDE interface - Implemented markers into KDE interface
* Added triangle-accurate picking of mesh objects * Added triangle-accurate picking of mesh objects
* Multiview * Multiview
- Ctrl+R : split view vertically - Ctrl+R : split view vertically
@ -664,7 +664,7 @@ Code:
* Updated configuration files for new versions of autoconf * Updated configuration files for new versions of autoconf
1.3.1 1.3.1
* Improved inclusion of light travel delay, also in KDE time setting dialog * Improved inclusion of light travel delay, also in KDE time setting dialog
* Fixed lookback command for subsequent changes of target speed * Fixed lookback command for subsequent changes of target speed
* Allow wildcard character * inplace of extension for texture filenames * Allow wildcard character * inplace of extension for texture filenames
* Fix bump mapping (again) * Fix bump mapping (again)
@ -706,7 +706,7 @@ Code:
* Made cancel script command stop motion, tracking, and any object-relative * Made cancel script command stop motion, tracking, and any object-relative
coordinate system. coordinate system.
* Adjusted estimates for radii and rotation periods of extrasolar planets; * Adjusted estimates for radii and rotation periods of extrasolar planets;
rotation rates account (somewhat) for the effects of tidal despinning. rotation rates account (somewhat) for the effects of tidal despinning.
* Fixed a bug that was causing precision loss in orientation values; this fixes * Fixed a bug that was causing precision loss in orientation values; this fixes
some of the jerkiness apparent at very low fields of view. some of the jerkiness apparent at very low fields of view.
* Corrected radii of Uranus's rings * Corrected radii of Uranus's rings
@ -739,7 +739,7 @@ Code:
* Eliminated obscuring of location labels that occurred low view aspect ratios * Eliminated obscuring of location labels that occurred low view aspect ratios
* Added models of comet Halley and the small moons Pandora and Larissa * Added models of comet Halley and the small moons Pandora and Larissa
* Added limit of knowledge masks for the Galilean moons * Added limit of knowledge masks for the Galilean moons
* Changed spectral class of carbon stars to C, which supercedes and combines * Changed spectral class of carbon stars to C, which supersedes and combines
R and N R and N
* Lua scripting additions * Lua scripting additions
* View management commands * View management commands
@ -760,7 +760,7 @@ Code:
* Implemented an algorithm for importance weights to avoid overlapping or * Implemented an algorithm for importance weights to avoid overlapping or
too crowded location labels for Mars, Venus and the Moon too crowded location labels for Mars, Venus and the Moon
* Added new textures for Titan based on recent imaging from the Cassini * Added new textures for Titan based on recent imaging from the Cassini
mission mission
* Improved depth sorting so that hidden surface removal works properly for * Improved depth sorting so that hidden surface removal works properly for
overlapping objects overlapping objects
* Added theoretical estimates of oblateness and rotation rate for extrasolar * Added theoretical estimates of oblateness and rotation rate for extrasolar
@ -805,16 +805,16 @@ Code:
* Implemented new GLSL render path; NVIDIA combiners and GeForceFX paths * Implemented new GLSL render path; NVIDIA combiners and GeForceFX paths
deprecated. deprecated.
* Display UTF-8 superscript digits in some star names * Display UTF-8 superscript digits in some star names
* Updated the Titan texture. It accomodates all published high resolution * Updated the Titan texture. It accomodates all published high resolution
imaging from the Cassini mission until and including the flyby of 03/31/05. imaging from the Cassini mission until and including the flyby of 03/31/05.
* Updated the Iapetus texture. It accomodates all published high resolution * Updated the Iapetus texture. It accomodates all published high resolution
imaging from the Cassini mission, including also a unique hires photo taken imaging from the Cassini mission, including also a unique hires photo taken
in "Saturn shine". in "Saturn shine".
* Added catalogs of 163 visual and 39 spectroscopic binary orbits, * Added catalogs of 163 visual and 39 spectroscopic binary orbits,
respectively, (S<>erhjelm 1999, Pourbaix 2000) with known primary/secondary respectively, (S<>erhjelm 1999, Pourbaix 2000) with known primary/secondary
mass ratios. mass ratios.
* Added an extended and precise data base of 942 galaxies * Added an extended and precise data base of 942 galaxies
(Steinicke's rev. NGC/IC, 2005) with a magnitude cutoff Bmag < 12. (Steinicke's rev. NGC/IC, 2005) with a magnitude cutoff Bmag < 12.
* Included the commented PERL scripts used to extract and adapt the binary * Included the commented PERL scripts used to extract and adapt the binary
orbit and galaxy data from published professional catalogs. orbit and galaxy data from published professional catalogs.
* Added --extrasdir command line option for specifying additional directories * Added --extrasdir command line option for specifying additional directories
@ -843,13 +843,13 @@ Code:
- fixed automake bug where GConf schema would always install - fixed automake bug where GConf schema would always install
- removed linking against glut for no reason - removed linking against glut for no reason
* Implemented complete precision catalog (Steinicke's revised NGC/IC, 2005) of * Implemented complete precision catalog (Steinicke's revised NGC/IC, 2005) of
10610 galaxies with 10610 galaxies with
- distance information from four catalogs ( 6 methods ), - distance information from four catalogs ( 6 methods ),
- <= 4 alternate names, - <= 4 alternate names,
- info-URLs, - info-URLs,
- absolute magnitudes and - absolute magnitudes and
- correct sizes & orientations in space, as calculated from catalog - correct sizes & orientations in space, as calculated from catalog
parameters. parameters.
* Included well commented Perl script (deepsky.pl) as documentation. The used distance determination method is indicated in catalog for each galaxy. * Included well commented Perl script (deepsky.pl) as documentation. The used distance determination method is indicated in catalog for each galaxy.
* Updated binary star data base (visualbins.stc, spectbins.dsc) and respective * Updated binary star data base (visualbins.stc, spectbins.dsc) and respective
PERL catalog extraction scripts (visualbins.pl, spectbins.pl), such as to eliminate double occurences wrto nearstars.stc (, which remained unaffected). PERL catalog extraction scripts (visualbins.pl, spectbins.pl), such as to eliminate double occurences wrto nearstars.stc (, which remained unaffected).
@ -890,7 +890,7 @@ Code:
template from S0 disk template via rescaling by (1.0f, 3.8f, 1.0f); template from S0 disk template via rescaling by (1.0f, 3.8f, 1.0f);
- fixed wrong x,y alignment of elliptical rescaling. - fixed wrong x,y alignment of elliptical rescaling.
* Added code to ease compilation with newer Xcode versions (Macintosh). * Added code to ease compilation with newer Xcode versions (Macintosh).
* Updated src/celengine/Makefile.am for Linux building. * Updated src/celengine/Makefile.am for Linux building.
* Introduced a new cel function => renderflags {set "nebulae"}. * Introduced a new cel function => renderflags {set "nebulae"}.
* Reduced the default value of 'faintestAutoMag45deg' from 8.5 to 7.0. * Reduced the default value of 'faintestAutoMag45deg' from 8.5 to 7.0.
* Fixed the visibility of the Milky Way during day-time and the abrupt * Fixed the visibility of the Milky Way during day-time and the abrupt
@ -904,10 +904,10 @@ Code:
* Deleted various source code files that became superfluous. * Deleted various source code files that became superfluous.
* Improved comet display. Introduced a neat scheme implementing comet tail * Improved comet display. Introduced a neat scheme implementing comet tail
fading (between 4 and 6 AU for Sol). Systems with several suns and fading (between 4 and 6 AU for Sol). Systems with several suns and
luminosities different from the solar one are accounted for. luminosities different from the solar one are accounted for.
* Implemented a new, simple scheme avoiding overcrowded galaxy labels. * Implemented a new, simple scheme avoiding overcrowded galaxy labels.
Their "importance" is sorted according to apparent magnitude! Thus the Their "importance" is sorted according to apparent magnitude! Thus the
labels of the brightest galaxies pop up first upon zooming in... labels of the brightest galaxies pop up first upon zooming in...
* Fixes/workarounds for OpenGL 2.0 render paths on both nVidia and ATI cards. * Fixes/workarounds for OpenGL 2.0 render paths on both nVidia and ATI cards.
@ -932,7 +932,7 @@ Code:
located inside the galaxy (Milky Way...). located inside the galaxy (Milky Way...).
* Eliminated various incorrect Hubble type acronyms in deepsky.dsc that had * Eliminated various incorrect Hubble type acronyms in deepsky.dsc that had
penetrated the PERL filter. penetrated the PERL filter.
* Add the corrected PERL script deepsky.pl. * Add the corrected PERL script deepsky.pl.
* Mac: Universal binary - runs natively on Intel and PPC * Mac: Universal binary - runs natively on Intel and PPC
* Mac: OpenGL 2.0 render path should now work on many configurations * Mac: OpenGL 2.0 render path should now work on many configurations
(requires OS X 10.4.3 or later) (requires OS X 10.4.3 or later)
@ -948,7 +948,7 @@ Code:
* Mac: Fixed crash when LANG or LC environment variables are set * Mac: Fixed crash when LANG or LC environment variables are set
* Mac: Added bona fide English and French help menu * Mac: Added bona fide English and French help menu
* Mac: Cleaned up README in general * Mac: Cleaned up README in general
* Added Phoebe textures in medres and lores directories from recent published * Added Phoebe textures in medres and lores directories from recent published
Ciclops cylindrical maps Ciclops cylindrical maps
* Updated Titan and Iapetus textures in lores directory * Updated Titan and Iapetus textures in lores directory
* Windows: save and restore the last used GL render path * Windows: save and restore the last used GL render path
@ -959,10 +959,10 @@ Code:
* KDE: Reverted mouse wheel action to be compatible with the other interfaces. * KDE: Reverted mouse wheel action to be compatible with the other interfaces.
* KDE: New configurable splash screen * KDE: New configurable splash screen
(http://celestia.teyssier.org/splash_spec.html) (http://celestia.teyssier.org/splash_spec.html)
* Updated/added Tethys textures in lores, medres and hires directories. * Updated/added Tethys textures in lores, medres and hires directories.
* Added locations on Phoebe in satmoons2.ssc, as extracted from USGS/IAU * Added locations on Phoebe in satmoons2.ssc, as extracted from USGS/IAU
official data. official data.
* Added Mesh for Phoebe texture. * Added Mesh for Phoebe texture.
* Updated Iapetus texture. * Updated Iapetus texture.
* Moved locations files from extras into data directory for inclusion in * Moved locations files from extras into data directory for inclusion in
standard package. standard package.
@ -1002,7 +1002,7 @@ Code:
- HIP 14810 c, HD 185269 b, Gliese 849 b - HIP 14810 c, HD 185269 b, Gliese 849 b
- Mu Ara e - Mu Ara e
- Gliese 581 c & d, HD 175541 b, HD 210702 b, HD192699 b - Gliese 581 c & d, HD 175541 b, HD 210702 b, HD192699 b
- HD 47536 c, XO-2 b, HD 147506 (HAT-P-2), HD 17092 b - HD 47536 c, XO-2 b, HD 147506 (HAT-P-2), HD 17092 b
* Revised orbits of many extrasolar planets to reflect new data * Revised orbits of many extrasolar planets to reflect new data
* Added stars for new extrasolar planets: GSC 92941-01657 * Added stars for new extrasolar planets: GSC 92941-01657
* Mac: Show menu bar when moving mouse to top of screen in full screen * Mac: Show menu bar when moving mouse to top of screen in full screen
@ -1067,7 +1067,7 @@ Code:
* Added cmodsphere, a utility for producing cmod meshes from height samples * Added cmodsphere, a utility for producing cmod meshes from height samples
regularly spaced in longitude and latitude. regularly spaced in longitude and latitude.
* COPYING, controls.txt, start script, and guide can all be localized * COPYING, controls.txt, start script, and guide can all be localized
* cel and celx scripting: * cel and celx scripting:
- added openclusters and cloudshadows render flags - added openclusters and cloudshadows render flags
- added location, nebulae, openclusers, and i18nconsteallations label flags - added location, nebulae, openclusers, and i18nconsteallations label flags
* Established Barycentric Dynamical Time (TDB) as the time scale used * Established Barycentric Dynamical Time (TDB) as the time scale used
@ -1090,12 +1090,12 @@ Code:
spectra spectra
* Made star orbit paths visible * Made star orbit paths visible
* galaxies: * galaxies:
-changed galaxy template format to standard (grayscale) PNG -changed galaxy template format to standard (grayscale) PNG
-allow a custom template for each galaxy in deepsky.dsc -allow a custom template for each galaxy in deepsky.dsc
-new approach to thickness of galaxy (arms): assumed proportional to read-in -new approach to thickness of galaxy (arms): assumed proportional to read-in
brightness values brightness values
-emulate dust lanes around galactic plane (y=0) -emulate dust lanes around galactic plane (y=0)
-considerable improvement of Milky Way appearance as seen from Earth -considerable improvement of Milky Way appearance as seen from Earth
-implement galaxy labels of transparency increasing with distance, thus -implement galaxy labels of transparency increasing with distance, thus
providing a neat 3d effect providing a neat 3d effect
* galaxy templates: * galaxy templates:
@ -1114,10 +1114,10 @@ Code:
- Guarded against crash when the JPL ephemeris file can't be found - Guarded against crash when the JPL ephemeris file can't be found
* Generalized rotations * Generalized rotations
- Clear syntax for ssc files - Clear syntax for ssc files
- UniformRotation - UniformRotation
- PrecessingOrientation - PrecessingOrientation
- SampledOrientation - interpolated sequence of quaternion key frames - SampledOrientation - interpolated sequence of quaternion key frames
* Scripting improvements * Scripting improvements
- New celx scripting commands: - New celx scripting commands:
- utctotdb and tdbtoutc - utctotdb and tdbtoutc
- gl commands - gl commands
@ -1125,7 +1125,7 @@ Code:
- iterators: celestia:stars and celestia:dsos - iterators: celestia:stars and celestia:dsos
- get/setaltazimuthmode - get/setaltazimuthmode
- Lua hooks for script extensions to Celestia - Lua hooks for script extensions to Celestia
- Script interfaces for orbits and rotation models (ScriptedOrbit and - Script interfaces for orbits and rotation models (ScriptedOrbit and
ScriptedRotation) ScriptedRotation)
- Support Lua 5.1 (5.0 compatibility retained) - Support Lua 5.1 (5.0 compatibility retained)
- Made celestia:loadtexture use relative file names - Made celestia:loadtexture use relative file names
@ -1148,7 +1148,7 @@ Code:
* Corrected kilometers per light year constant * Corrected kilometers per light year constant
* Added various improvements to the MilkyWay & other galaxy template display. * Added various improvements to the MilkyWay & other galaxy template display.
* Added E0.png galaxy template that allows for better En, n=1..7 elliptical * Added E0.png galaxy template that allows for better En, n=1..7 elliptical
shapes. shapes.
* Fixed sizes of irregular galaxies (factor of 2!). * Fixed sizes of irregular galaxies (factor of 2!).
* Prevented galaxy code from crashing if a template is missing. * Prevented galaxy code from crashing if a template is missing.
* Improved selection of galaxies by taking into account their 3d shape * Improved selection of galaxies by taking into account their 3d shape
@ -1163,11 +1163,11 @@ Code:
* Windows: Fixed crash that occurred when star browser was closed * Windows: Fixed crash that occurred when star browser was closed
* Fixed bug that made moons disappear as a planet approached stellar transit * Fixed bug that made moons disappear as a planet approached stellar transit
* Added a major update of the galaxy database such that close to 100% of the * Added a major update of the galaxy database such that close to 100% of the
galaxies now involve distance measurements galaxies now involve distance measurements
* Included the complete local group of galaxies * Included the complete local group of galaxies
* Added varying label transparency also for stars * Added varying label transparency also for stars
* Added the PERL scripts used for extraction of galaxy and binary orbit data * Added the PERL scripts used for extraction of galaxy and binary orbit data
from scientific sources. They both are useful tools and a concise from scientific sources. They both are useful tools and a concise
documentation of Celestia's data documentation of Celestia's data
* updated binary orbit data (visualbins.stc and spectbins.stc) along with * updated binary orbit data (visualbins.stc and spectbins.stc) along with
respective PERL scripts (visualbins.pl and spectbins.pl) respective PERL scripts (visualbins.pl and spectbins.pl)
@ -1220,7 +1220,7 @@ Code:
HD 167042 b, HD 74156 d, HD 285968 b, V391 Peg b, HD 167042 b, HD 74156 d, HD 285968 b, V391 Peg b,
HD 132406 b, HD 43691 b, NGC 2423 3 b, Gliese 317 b & c, HD 132406 b, HD 43691 b, NGC 2423 3 b, Gliese 317 b & c,
TrES-3, HD 155358 b&c, HD 5319 b, HD 75898 b, OGLE-TR-182 b, WASP-3 b, TrES-3, HD 155358 b&c, HD 5319 b, HD 75898 b, OGLE-TR-182 b, WASP-3 b,
55 Cnc f, Lupus-TR-3 b, OGLE-TR-211 b, HD 156846 b, HD 4113 b, Kap CrB b, 55 Cnc f, Lupus-TR-3 b, OGLE-TR-211 b, HD 156846 b, HD 4113 b, Kap CrB b,
GD 66 b, XO-3 b, WASP-4 b TW Hya b GD 66 b, XO-3 b, WASP-4 b TW Hya b
removed HD 33636 b removed HD 33636 b
* Set up transit of Gliese 436 * Set up transit of Gliese 436
@ -1383,7 +1383,7 @@ Bug fixes
* Fixed search path for Lua scripts * Fixed search path for Lua scripts
* Fixed numerous bugs that occurred when an object's orbit center was different * Fixed numerous bugs that occurred when an object's orbit center was different
* Fixed a bug in the celx function celestia:getscreendimension * Fixed a bug in the celx function celestia:getscreendimension
* Fixed bug with returning Hubble type for galaxies * Fixed bug with returning Hubble type for galaxies
* Eliminated error-prone min/max macros; use STL functions instead * Eliminated error-prone min/max macros; use STL functions instead
* Fixed discrepancy between apparent magnitudes shown in the 3D view and * Fixed discrepancy between apparent magnitudes shown in the 3D view and
the star browser. the star browser.
@ -1424,9 +1424,9 @@ Data file updates
* Changed class of small outer planet moons to minormoon * Changed class of small outer planet moons to minormoon
* Included new and updated solar system body features from the IAU * Included new and updated solar system body features from the IAU
* Added provisional rotation period for Eris * Added provisional rotation period for Eris
Tools Tools
* Added Perl script globulars.pl used to extract the globular data from scientific publications and as documentation * Added Perl script globulars.pl used to extract the globular data from scientific publications and as documentation
* Added spice2xyzv tool for extracting xyzv files from a pool of SPICE kernels * Added spice2xyzv tool for extracting xyzv files from a pool of SPICE kernels
* Added Perl script to build cross-indices * Added Perl script to build cross-indices
* Added Perl script to generate CHARM2 catalog * Added Perl script to generate CHARM2 catalog
@ -1557,7 +1557,7 @@ Scripting
- windowbordersvisible, setwindowbordersvisible - windowbordersvisible, setwindowbordersvisible
* Split celx scripting support into several modules * Split celx scripting support into several modules
* Cel scripting * Cel scripting
- splitview, deleteview, singleview, setactiveview - splitview, deleteview, singleview, setactiveview
- setgalaxylightgain - setgalaxylightgain
- setradius - setradius
- setlinecolor - setlinecolor

View File

@ -150,7 +150,7 @@ following option to cmake: -DCMAKE_INSTALL_PREFIX=/another/path.
## Celestia Install instructions for Windows (MSVC) ## Celestia Install instructions for Windows (MSVC)
Currently to build on Windows you need a Visual Studio 2015 or later, CMake Currently to build on Windows you need Visual Studio 2015 or later, CMake
and vcpkg (*). and vcpkg (*).
Install required packages: Install required packages:
@ -170,6 +170,9 @@ for 64-bit versions.
Instead of `luajit` `lua` can be used. Instead of `luajit` `lua` can be used.
Use `vcpkg list` to ensure that all packages have actually been installed.
If not, try installing them one at a time.
Configure and build 32-bit version: Configure and build 32-bit version:
``` ```
@ -188,8 +191,8 @@ cmake -DCMAKE_GENERATOR_PLATFORM=x64 -DCMAKE_TOOLCHAIN_FILE=c:/tools/vcpkg/scrip
cmake --build . -- /maxcpucount:N /nologo cmake --build . -- /maxcpucount:N /nologo
``` ```
Instead of N in /maxcpucount pass a number of CPU cores you want to use during Instead of N in /maxcpucount pass the number of CPU cores you want to use during
a build. the build.
This example assumes that `vcpkg` is installed into `c:/tools/vcpkg`. Update This example assumes that `vcpkg` is installed into `c:/tools/vcpkg`. Update
the path to `vcpkg.cmake` according to your installation. the path to `vcpkg.cmake` according to your installation.

142
README-upstream.md 100644
View File

@ -0,0 +1,142 @@
| **`Release`** | **`Localized`** | **`License`** | **`Contribute`** |
|-------------------|---------------|---------------|---------------|
|[![GitHub release](https://img.shields.io/github/v/release/CelestiaProject/Celestia?label=Release)](https://celestia.space/download.html) | [![Localization](https://img.shields.io/badge/Localized-85%25-green.svg)](#) | [![License](https://img.shields.io/github/license/CelestiaProject/Celestia?label=License)](https://github.com/CelestiaProject/Celestia/blob/master/COPYING) | [![Contribute](https://img.shields.io/badge/PRs-Welcome-brightgreen.svg)](#contributing) |
# Celestia
![Celestia](celestia-logo.png)<br>
**A real-time space simulation that lets you experience our universe in three dimensions.**
**Copyright © 2001-2021, Celestia Development Team**<br>
**Celestia website: https://celestia.space**<br>
**Celestia Wikibook: https://en.wikibooks.org/wiki/Celestia**<br>
**Celestia forums: https://celestia.space/forum/**<br>
**Celestia Subreddit: https://www.reddit.com/r/Celestiasoftware/**<br>
**Celestia Archive Repository: https://github.com/Anthony-B-Russo10/Celestia-Archive**
## License
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software Foundation;
either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details,
which you should have received along with this program (filename: COPYING).
If not, request a copy from:<br>
Free Software Foundation, Inc.<br>
59 Temple Place - Suite 330<br>
Boston, MA 02111-1307<br>
USA
## Getting started
Celestia will start up in a window, and if everything is working correctly,
you'll see Earth in front of a field of stars. Displayed on-screen, is some
information about your target (Earth), your speed, and the current time
(Universal Time, so it'll probably be a few hours off from your computer's
clock).
Right drag the mouse to orbit Earth and you might see the Moon and some
familiar constellations. Left dragging the mouse changes your orientation
also, but the camera rotates about its center instead of rotating around
Earth. Rolling the mouse wheel will change your distance to Earth--you can
move light years away, then roll the wheel in the opposite direction to get
back to your starting location. If your mouse lacks a wheel, you can use the
Home and End keys instead.
When running Celestia, you will usually have some object selected. Currently,
it's Earth, but it could also be a star, moon, spacecraft, galaxy, or some
other object. The simplest way to select an object is to click on it. Try
clicking on a star to select it. The information about Earth is replaced with
some details about the star. Press G (or use the Navigation menu), and you'll
zoom through space toward the selected star. If you press G again, you'll
approach the star even closer.
Press H to select our Sun, and then G to go back to our Sun. Right click on
the sun to bring up a menu of planets and other objects in the solar system.
After selecting a planet from the menu, hit G again to travel toward it. Once
there, hold down the right mouse button and drag to orbit the planet.
The Tour Guide is a list of some of the more interesting objects you can visit
in Celestia. Select the Tour Guide option in the Navigation menu to display
the Tour Guide window. Choose a destination from the list, click the Goto
button, and you're off.
That covers the very basics. For a more in-depth look at Celestia and the
controls available to you, download the "Celestia User's Guide" (written by
Frank Gregorio), available in several languages, from:<br>
https://celestia.space/guides.html<br>
This web page also includes links to the Celestia README file translated into
Japanese.
### Star browser
By default, the Star Browser window displays a table of the 100 nearest stars,
along with their Distance, Apparent and Absolute Magnitude, and Type. Clicking
on the column headers will sort the stars. The table is not continuously
updated, so if you travel to another star, you should press the Refresh button
to update the table for your current position. The radio buttons beneath the
table let you switch between viewing a list of Nearest, Brightest, or 'With
planets' stars. As with the solar system browser, clicking on any star name
in the table will select it. Use this feature along with the Center and Go
To buttons to tour the stars visible from any night sky in the galaxy.
### Solar system browser
The Solar System Browser displays a window with a tree view of all the objects
in the nearest solar system (if there is one within a light year of your current
position.) Clicking on the name of any object in the window will select it.
You can then use the Center or Go To buttons to display that object in the main
Celestia window.
### Selecting objects by name
Celestia provides several ways to select an object by name...
1. Choose 'Select Object' from the Navigation menu, type in the object name, and click OK.
2. Press Enter, type in the entire object name, and press Enter again.
3. Press Enter, type in the first few characters of the object name,
press the Tab key to move through the displayed listing until the object is highlighted,
then press Enter again.
You can use common names, Bayer designations or catalog numbers for stars.
Celestia currently supports the HIP, HD and SAO catalogs. Catalog numbers must
be entered with a space between the prefix and the catalog number.
### Known issues
For up-to-the-minute answers to some common problems encountered when running
Celestia, please view either the FAQ in the Help menu or take a look at the
"Celestia User's FAQ" located on the Celestia User's Forum:
https://celestia.space/forum/
### User modifiable elements
You can modify how Celestia starts up each time you run it, by defining your
own start-up settings. Simply open the file "start.cel" in a plain text
editor and follow the in-file instructions. Also, view the celestia.cfg file
in a plain text editor to see additional settings.
Celestia allows you to easily add real, hypothetical, or fictional objects
by creating new catalog files. It is *not* recommended that you alter the
built-in data files; nearly all desired modifications and additions can be
made by placing new catalog files in Celestia's extras folders. There are three
types of catalog files:
* ssc (solar system catalog: planets, moons, spacecraft, etc.)
* stc (star catalog)
* dsc (deep sky catalog: galaxies, star clusters, and nebulae)
All three types of catalog file are text files that can be updated with your
favorite text editing program.
### Building from sources
See instructions in file [INSTALL.md](INSTALL.md).
## Contributions
| **`Authors`** | **`Contributors`** | **`Documentation`** | **`Other`** |
|-----------------|---------------------|------------------|-------------------|
| Chris Laurel, Clint Weisbrod, Fridger Schrempp, Bob Ippolito, Christophe Teyssier, Hank Ramsey, Grant Hutchison, Pat Suwalski, Toti, Da Woon Jung, Vincent Giangiulio, Andrew Tribick, Hleb Valoshka, Łukasz Buczyński, Li Linfeng | Deon Ramsey, Christopher Andre, Colin Walters, Peter Chapman, James Holmes, Harald Schmidt, Nils Larsson, Sergey Leonov, Alexell, Dmitry Brant, Janus | Selden Ball, Frank Gregorio, Hitoshi Suzuki, Christophe Teyssier, Diego Rodriguez, Don Goyette, Harald Schmidt | Creators of scientific database, texture maps, 3D models and used libraries, you can see in full README.|
### Contributing
**We welcome feedback, bug reports, and pull requests!**
For pull requests, please stick to the following guidelines:
* Be sure to test your code changes.
* Follow the existing code style (e.g., indents).
* Put a lot of comments into the code, if necessary.
* Separate unrelated changes into multiple pull requests.

207
README.md
View File

@ -1,143 +1,110 @@
| **`Release`** | **`Localized`** | **`License`** | **`Contribute`** |
|-------------------|---------------|---------------|---------------|
|[![GitHub release](https://img.shields.io/github/v/release/CelestiaProject/Celestia?label=Release)](https://celestia.space/download.html) | [![Localization](https://img.shields.io/badge/Localized-85%25-green.svg)](#) | [![License](https://img.shields.io/github/license/CelestiaProject/Celestia?label=License)](https://github.com/CelestiaProject/Celestia/blob/master/COPYING) | [![Contribute](https://img.shields.io/badge/PRs-Welcome-brightgreen.svg)](#contributing) |
# Celestia # Celestia
![Celestia](celestia-logo.png)<br> Celestia is a "real-time space simulation that lets you experience
**A real-time space simulation that lets you experience our universe in three dimensions.** our universe in three dimensions".
**Copyright © 2001-2021, Celestia Development Team**<br> ![celestia-screenshot](pics/celestia-screenshot.png)
**Celestia website: https://celestia.space**<br>
**Celestia Wikibook: https://en.wikibooks.org/wiki/Celestia**<br>
**Celestia forums: https://celestia.space/forum/**<br>
**Celestia Discord Server: https://discordapp.com/invite/WEWDcJh**<br>
**Celestia Subreddit: https://www.reddit.com/r/Celestiasoftware/**<br>
**Celestia Archive Repository: https://github.com/Anthony-B-Russo10/Celestia-Archive**
## License
This program is free software; you can redistribute it and/or modify it under # Upstream
the terms of the GNU General Public License as published by the Free Software Foundation; This repo is a lesser fork of the upstream project,
either version 2 of the License, or (at your option) any later version. which has been revived.
This program is distributed in the hope that it will be useful, but WITHOUT * https://celestia.space/
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details,
which you should have received along with this program (filename: COPYING).
If not, request a copy from:<br>
Free Software Foundation, Inc.<br>
59 Temple Place - Suite 330<br>
Boston, MA 02111-1307<br>
USA
## Getting started * https://github.com/CelestiaProject/Celestia
Celestia will start up in a window, and if everything is working correctly, See also: `README-upstream`, `README-upstream.md`.
you'll see Earth in front of a field of stars. Displayed on-screen, is some
information about your target (Earth), your speed, and the current time
(Universal Time, so it'll probably be a few hours off from your computer's
clock).
Right drag the mouse to orbit Earth and you might see the Moon and some ## License/Copyright
familiar constellations. Left dragging the mouse changes your orientation GPLv2+
also, but the camera rotates about its center instead of rotating around
Earth. Rolling the mouse wheel will change your distance to Earth--you can
move light years away, then roll the wheel in the opposite direction to get
back to your starting location. If your mouse lacks a wheel, you can use the
Home and End keys instead.
When running Celestia, you will usually have some object selected. Currently, Copyright © 2001-2021, Celestia Development Team
it's Earth, but it could also be a star, moon, spacecraft, galaxy, or some
other object. The simplest way to select an object is to click on it. Try
clicking on a star to select it. The information about Earth is replaced with
some details about the star. Press G (or use the Navigation menu), and you'll
zoom through space toward the selected star. If you press G again, you'll
approach the star even closer.
Press H to select our Sun, and then G to go back to our Sun. Right click on # Debian
the sun to bring up a menu of planets and other objects in the solar system. Package was removed from Debian in the ancient days due to bitrot.
After selecting a planet from the menu, hit G again to travel toward it. Once The upstream code has a new team and active development, using
there, hold down the right mouse button and drag to orbit the planet. recent libraries. The package can be built under Debian Ok, except
for the `data/` files.
The Tour Guide is a list of some of the more interesting objects you can visit Debian upstream bug:
in Celestia. Select the Tour Guide option in the Navigation menu to display
the Tour Guide window. Choose a destination from the list, click the Goto
button, and you're off.
That covers the very basics. For a more in-depth look at Celestia and the * https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=809916
controls available to you, download the "Celestia User's Guide" (written by
Frank Gregorio), available in several languages, from:<br>
https://celestia.space/guides.html<br>
This web page also includes links to the Celestia README file translated into
Japanese.
### Star browser ```
By default, the Star Browser window displays a table of the 100 nearest stars, Upstream has not produced any new releases in the last 4 years. In the
along with their Distance, Apparent and Absolute Magnitude, and Type. Clicking mean time, the package is accumulating bugs due to bitrot. It already
on the column headers will sort the stars. The table is not continuously wasn't a trouble-free package, due to some quite important resources not
updated, so if you travel to another star, you should press the Refresh button being DFSG compliant.
to update the table for your current position. The radio buttons beneath the ```
table let you switch between viewing a list of Nearest, Brightest, or 'With
planets' stars. As with the solar system browser, clicking on any star name
in the table will select it. Use this feature along with the Center and Go
To buttons to tour the stars visible from any night sky in the galaxy.
### Solar system browser I do see some of the resources now are CC-by-SA 4.0, a license which
The Solar System Browser displays a window with a tree view of all the objects didn't exist when the Debian bug was created. So it may be that it
in the nearest solar system (if there is one within a light year of your current can be built happily without DFSG issues using new data files.
position.) Clicking on the name of any object in the window will select it.
You can then use the Center or Go To buttons to display that object in the main
Celestia window.
### Selecting objects by name
Celestia provides several ways to select an object by name...
1. Choose 'Select Object' from the Navigation menu, type in the object name, and click OK.
2. Press Enter, type in the entire object name, and press Enter again.
3. Press Enter, type in the first few characters of the object name,
press the Tab key to move through the displayed listing until the object is highlighted,
then press Enter again.
You can use common names, Bayer designations or catalog numbers for stars.
Celestia currently supports the HIP, HD and SAO catalogs. Catalog numbers must
be entered with a space between the prefix and the catalog number.
### Known issues Celestia depending on NASA's Spice/NAIF may be afoul of Debian's
For up-to-the-minute answers to some common problems encountered when running DFSG because the terms are unique. It isn't really a standard license.
Celestia, please view either the FAQ in the Help menu or take a look at the
"Celestia User's FAQ" located on the Celestia User's Forum:
https://celestia.space/forum/
### User modifiable elements
You can modify how Celestia starts up each time you run it, by defining your
own start-up settings. Simply open the file "start.cel" in a plain text
editor and follow the in-file instructions. Also, view the celestia.cfg file
in a plain text editor to see additional settings.
Celestia allows you to easily add real, hypothetical, or fictional objects Debian tracker link:
by creating new catalog files. It is *not* recommended that you alter the
built-in data files; nearly all desired modifications and additions can be
made by placing new catalog files in Celestia's extras folders. There are three
types of catalog files:
* ssc (solar system catalog: planets, moons, spacecraft, etc.)
* stc (star catalog)
* dsc (deep sky catalog: galaxies, star clusters, and nebulae)
All three types of catalog file are text files that can be updated with your * https://tracker.debian.org/pkg/celestia
favorite text editing program.
### Building from sources # Build
See instructions in file [INSTALL.md](INSTALL.md). Mini Debian package build howto.
## Contributions ```
| **`Authors`** | **`Contributors`** | **`Documentation`** | **`Other`** | # Install deps
|-----------------|---------------------|------------------|-------------------| sudo apt update
| Chris Laurel, Clint Weisbrod, Fridger Schrempp, Bob Ippolito, Christophe Teyssier, Hank Ramsey, Grant Hutchison, Pat Suwalski, Toti, Da Woon Jung, Vincent Giangiulio, Andrew Tribick, Hleb Valoshka, Łukasz Buczyński, Li Linfeng | Deon Ramsey, Christopher Andre, Colin Walters, Peter Chapman, James Holmes, Harald Schmidt, Nils Larsson, Sergey Leonov, Alexell, Dmitry Brant, Janus | Selden Ball, Frank Gregorio, Hitoshi Suzuki, Christophe Teyssier, Diego Rodriguez, Don Goyette, Harald Schmidt | Creators of scientific database, texture maps, 3D models and used libraries, you can see in full README.| sudo apt install build-essential ccache devscripts \
debhelper chrpath cmake freeglut3-dev libeigen3-dev libfmt-dev \
libfreetype6-dev libepoxy-dev libglu1-mesa-dev libgtk2.0-dev \
libgtkglext1-dev libjpeg62-turbo-dev libluajit-5.1-dev libpng-dev \
libqt5opengl5-dev libtheora-dev qtbase5-dev qtbase5-dev-tools
### Contributing # Add ccache to PATH in ~/.bashrc, and log back in
PATH=/usr/lib/ccache:$PATH
**We welcome feedback, bug reports, and pull requests!** # Make dirs to put it all, as it writes packages to the *parent* dir.
mkdir celestia-deb
cd celestia-deb
git clone https://spacecruft.org/spacecruft/CelestiaContent
cd CelestiaContent
# Build the source package, writes to parent dir
dpkg-buildpackage -rfakeroot -S -uc -us -sa
# Build Debian Packages
dpkg-buildpackage -rfakeroot -b -uc
cd ..
# Install the data package
sudo dpkg -i celestia-data_1.7.0~git20211202+668347e9+0_all.deb
# Make sure apt is happy
sudo apt -f install
git clone --recursive https://spacecruft.org/spacecruft/celestia
cd celestia
# Build the source package, writes to parent dir
dpkg-buildpackage -rfakeroot -S -uc -us -sa
# Build Debian Packages
dpkg-buildpackage -rfakeroot -b -uc
cd ..
# Install
sudo dpkg -i celestia_1.7.0~git20220520+1_all.deb \
celestia-common_1.7.0~git20220520+1_all.deb \
celestia-qt_1.7.0~git20220520+1_amd64.deb \
celestia-tools_1.7.0~git20220520+1_amd64.deb \
libcelestia1.7_1.7.0~git20220520+1_amd64.deb
# Make sure apt is happy
sudo apt -f install
```
For pull requests, please stick to the following guidelines:
* Be sure to test your code changes.
* Follow the existing code style (e.g., indents).
* Put a lot of comments into the code, if necessary.
* Separate unrelated changes into multiple pull requests.

View File

@ -227,16 +227,17 @@ StarTextures
# text on the display screen. To view the list of fonts available with # text on the display screen. To view the list of fonts available with
# your distribution of Celestia, look in the fonts directory located # your distribution of Celestia, look in the fonts directory located
# under the Celestia root directory. The default fonts are UTF-8 # under the Celestia root directory. The default fonts are UTF-8
# compatible in order to display non-English characters. # compatible in order to display non-English characters. Font size is
# measured in points to ensure the same sizes on all DPI configurations.
# #
# Font: Used to display all informational text. # Font: Used to display all informational text.
# Default: "sans12.txf" # Default: "DejaVuSans.ttf,9"
# #
# LabelFont: Used to display all label text (objects, locations, etc.). # LabelFont: Used to display all label text (objects, locations, etc.).
# Default "sans12.txf" # Default "DejaVuSans.ttf,9"
# #
# TitleFont: Used to display object names, messages, and script text. # TitleFont: Used to display object names, messages, and script text.
# Default "sansbold20.txf" # Default "DejaVuSans-Bold.ttf,15"
#------------------------------------------------------------------------ #------------------------------------------------------------------------
Font "DejaVuSans.ttf,9" Font "DejaVuSans.ttf,9"
LabelFont "DejaVuSans.ttf,9" LabelFont "DejaVuSans.ttf,9"

View File

@ -212,6 +212,7 @@ Source: "locale\controls_zh_CN.txt"; DestDir: "{app}/locale"; Flags: ignor
Source: "locale\controls_zh_TW.txt"; DestDir: "{app}/locale"; Flags: ignoreversion Source: "locale\controls_zh_TW.txt"; DestDir: "{app}/locale"; Flags: ignoreversion
Source: "locale\demo_be.cel"; DestDir: "{app}/locale"; Flags: ignoreversion Source: "locale\demo_be.cel"; DestDir: "{app}/locale"; Flags: ignoreversion
Source: "locale\demo_bg.cel"; DestDir: "{app}/locale"; Flags: ignoreversion
Source: "locale\demo_de.cel"; DestDir: "{app}/locale"; Flags: ignoreversion Source: "locale\demo_de.cel"; DestDir: "{app}/locale"; Flags: ignoreversion
Source: "locale\demo_es.cel"; DestDir: "{app}/locale"; Flags: ignoreversion Source: "locale\demo_es.cel"; DestDir: "{app}/locale"; Flags: ignoreversion
Source: "locale\demo_fr.cel"; DestDir: "{app}/locale"; Flags: ignoreversion Source: "locale\demo_fr.cel"; DestDir: "{app}/locale"; Flags: ignoreversion

View File

@ -3,4 +3,5 @@
#cmakedefine HAVE_FLOAT_CHARCONV #cmakedefine HAVE_FLOAT_CHARCONV
#cmakedefine HAVE_STD_FILESYSTEM #cmakedefine HAVE_STD_FILESYSTEM
#cmakedefine HAVE_WORDEXP #cmakedefine HAVE_WORDEXP
#cmakedefine HAVE_MESHOPTIMIZER
#cmakedefine WORDS_BIGENDIAN #cmakedefine WORDS_BIGENDIAN

View File

@ -1,3 +1,5 @@
README README.md
README-upstream
README-upstream.md
AUTHORS AUTHORS
TRANSLATORS TRANSLATORS

View File

@ -12,7 +12,7 @@ usr/bin/3dstocmod
usr/bin/cmodfix usr/bin/cmodfix
usr/bin/txt2cmod usr/bin/txt2cmod
usr/bin/cmodsphere usr/bin/cmodsphere
usr/bin/qttxf #usr/bin/qttxf
#usr/bin/spice2xyzv #usr/bin/spice2xyzv
usr/bin/vsoptrunc-rect usr/bin/vsoptrunc-rect
usr/bin/vsoptrunc-sph usr/bin/vsoptrunc-sph

13
debian/changelog vendored
View File

@ -1,3 +1,16 @@
celestia (1.7.0~git20220520+1) UNRELEASED; urgency=medium
* Fix control character ^M in perl scripts.
-- Jeff Moe <moe@spacecruft.org> Fri, 20 May 2022 21:02:00 -0600
celestia (1.7.0~git20220520+0) UNRELEASED; urgency=medium
* New snapshot build.
* Remove missing qttxf.
-- Jeff Moe <moe@spacecruft.org> Fri, 20 May 2022 19:55:59 -0600
celestia (1.7.0~git20190807+d9746691+0) UNRELEASED; urgency=medium celestia (1.7.0~git20190807+d9746691+0) UNRELEASED; urgency=medium
* New snapshot build * New snapshot build

1
debian/control vendored
View File

@ -5,6 +5,7 @@ Maintainer: Hleb Valoshka <375gnu@gmail.com>
Build-Depends: debhelper (>= 10~), Build-Depends: debhelper (>= 10~),
chrpath, chrpath,
cmake (>= 3.1~), cmake (>= 3.1~),
dos2unix,
freeglut3-dev, freeglut3-dev,
libeigen3-dev (>= 3.3~), libeigen3-dev (>= 3.3~),
libfmt-dev (>= 4), libfmt-dev (>= 4),

2
debian/rules vendored
View File

@ -26,6 +26,8 @@ override_dh_auto_configure:
override_dh_install: override_dh_install:
dos2unix ./src/tools/stardb/buildstardb.pl
dos2unix ./src/tools/xindex/buildxindices.pl
find debian/tmp/usr/bin/ -type f ! -name *.pl -exec chrpath --delete {} ';' find debian/tmp/usr/bin/ -type f ! -name *.pl -exec chrpath --delete {} ';'
chrpath --delete debian/tmp/usr/lib/*/libcelestia.so.* chrpath --delete debian/tmp/usr/lib/*/libcelestia.so.*
dh_install --fail-missing dh_install --fail-missing

View File

@ -3,10 +3,10 @@
labels { clear "planets|minorplanets|stars|constellations" } labels { clear "planets|minorplanets|stars|constellations" }
renderflags { set "stars|planets" renderflags { set "stars|planets"
clear "constellations|orbits|cloudmaps" } clear "constellations|orbits|cloudmaps" }
print { text "Начало на демонстрацията . . .\nНатиснете ESC за край." origin "center" duration 2 } print { text "Начало на демонстрацията...\nНатиснете „Esc“ за край." origin "center" duration 2 }
wait { duration 2.0 } wait { duration 2.0 }
print { text "Нека да започнем от нашия дом . . ." row -3 } print { text "Нека да започнем от нашия дом..." row -3 }
select { object "Sol/Earth" } select { object "Sol/Earth" }
cancel {} cancel {}
# goto { time 0 distance 3 upframe "ecliptical" } # goto { time 0 distance 3 upframe "ecliptical" }
@ -18,25 +18,25 @@
wait { duration 1.0 } wait { duration 1.0 }
follow {} follow {}
print { text "В момента се намираме на 12 500 км над Земята" row -3 duration 5 } print { text "В момента се намираме на 12 500 км. над Земята." row -3 duration 5 }
orbit { axis [ 0 1 0 ] rate 30 duration 10 } orbit { axis [ 0 1 0 ] rate 30 duration 10 }
print { text "Като добавим и облаците, Земята изглежда по позната." row -3} print { text "Като добавим и облаците, Земята изглежда по-позната." row -3}
wait { duration 0.1 } wait { duration 0.1 }
renderflags { set "cloudmaps" } renderflags { set "cloudmaps" }
orbit { axis [ 0 1 0 ] rate 30 duration 6 } orbit { axis [ 0 1 0 ] rate 30 duration 6 }
print { text "Следваща спирка: Луната." row -3 } print { text "Следваща спирка: Луната" row -3 }
select { object "Moon" } select { object "Moon" }
goto { time 5 distance 4 upframe "equatorial" } goto { time 5 distance 4 upframe "equatorial" }
wait { duration 5.5 } wait { duration 5.5 }
print { text "Оглеждайте се за Земята и Слънцето, докато се движим около Луната" row -3} print { text "Оглеждайте се за Земята и Слънцето, докато обикаляме около Луната." row -3}
orbit { axis [ 0 1 0 ] rate 30 duration 10 } orbit { axis [ 0 1 0 ] rate 30 duration 10 }
print { text "Напред към Слънцето." row -3} print { text "Напред към Слънцето!" row -3}
select { object "Sol" } select { object "Sol" }
goto { time 8 distance 12 upframe "equatorial" up [ 0 1 0 ] } goto { time 8 distance 12 upframe "equatorial" up [ 0 1 0 ] }
wait { duration 8.5 } wait { duration 8.5 }
print { text "От това разстояние могат да се видят тъмните слънчеви петна по повърхността му." row -3} print { text "От това разстояние може да видим тъмните слънчеви петна по повърхността му." row -3}
orbit { axis [ 0 1 0 ] rate 20 duration 10 } orbit { axis [ 0 1 0 ] rate 20 duration 10 }
print { text "Нека да се отдалечим и разгледаме вътрешната част на Слънчевата система." row -3} print { text "Нека да се отдалечим и разгледаме вътрешната част на Слънчевата система." row -3}
@ -44,10 +44,10 @@
renderflags { set "orbits" } renderflags { set "orbits" }
changedistance { duration 4.0 rate 1.0 } changedistance { duration 4.0 rate 1.0 }
print { text "Да включим имената на планетите . . ." row -3} print { text "Да включим имената на планетите..." row -3}
labels { set "planets" } labels { set "planets" }
wait { duration 1.0 } wait { duration 1.0 }
print { text "Можем да ускорим времето за да видим как планетите обикалят около Слънцето." row -3} print { text "Може да ускорим времето за да видим как планетите обикалят около Слънцето." row -3}
timerate { rate 2592000 } timerate { rate 2592000 }
wait { duration 3.0 } wait { duration 3.0 }
print { text "Всяка секунда в реално време е равна на един месец в симулацията." row -3} print { text "Всяка секунда в реално време е равна на един месец в симулацията." row -3}
@ -56,7 +56,7 @@
print { text "В момента, времето е спряно." row -3} print { text "В момента, времето е спряно." row -3}
wait { duration 1.0 } wait { duration 1.0 }
print { text "Следващата ни дестинация е Сатурн." row -3} print { text "Следваща спирка: Сатурн" row -3}
select { object "Saturn" } select { object "Saturn" }
center { time 2 } center { time 2 }
wait { duration 2 } wait { duration 2 }
@ -64,12 +64,12 @@
wait { duration 6.5 } wait { duration 6.5 }
renderflags { clear "orbits" } renderflags { clear "orbits" }
labels { clear "planets" } labels { clear "planets" }
print { text "Няколко от луните на Сатурн са видими като ярки точки" row -3 duration 3} print { text "Няколко от спътниците на Сатурн са видими като ярки точки." row -3 duration 3}
orbit { axis [ 0 1 0 ] rate 30 duration 12 } orbit { axis [ 0 1 0 ] rate 30 duration 12 }
select { object "Mimas" } select { object "Mimas" }
goto { time 5 distance 4 upframe "equatorial" } goto { time 5 distance 4 upframe "equatorial" }
print { text "Най-интересната характеристика на Мимас е огромния кратер Хершел." row -3 duration 9 } print { text "Най-интересната характеристика на Мимас е огромният кратер Хершел." row -3 duration 9 }
orbit { axis [ 0 1 0 ] rate 30 duration 12 } orbit { axis [ 0 1 0 ] rate 30 duration 12 }
changedistance { duration 6.0 rate 0.5 } changedistance { duration 6.0 rate 0.5 }
@ -82,22 +82,22 @@
wait { duration 2 } wait { duration 2 }
select { object "Alpha UMa" } select { object "Alpha UMa" }
center { time 2 } center { time 2 }
print { text "Ако живеете в северното полукълбо, ще разпознаете Колата в съзвездието Голямата мечка." row -3 duration 3 } print { text "Ако живеете в северното полукълбо, ще разпознаете Волската кола в съзвездието Голямата мечка." row -3 duration 3 }
wait { duration 4 } wait { duration 4 }
select { object "Polaris" } select { object "Polaris" }
center { time 2 } center { time 2 }
wait { duration 2 } wait { duration 2 }
print { text "А това е Поларис, известна още като Северната звезда." row -3} print { text "Това е Поларис, известна още като Северната звезда." row -3}
wait { duration 1 } wait { duration 1 }
labels { set "stars" } labels { set "stars" }
wait { duration 2 } wait { duration 2 }
print { text "Поларис е част от Малката мечка." row -3} print { text "Поларис е част от Малката мечка." row -3}
wait { duration 2 } wait { duration 2 }
print { text "За по-добра ориентация в небето, Celestia може да активира диаграмите на съзвездията . . ." row -3} print { text "За по-добра ориентация в небето, „Celestia“ може да активира очертанията на съзвездията..." row -3}
renderflags { set "constellations" } renderflags { set "constellations" }
wait { duration 2 } wait { duration 2 }
print { text ". . . и имената на съзвездията" row -3} print { text "...и имената на съзвездията." row -3}
labels { set "constellations" } labels { set "constellations" }
wait { duration 2 } wait { duration 2 }
@ -114,7 +114,7 @@
wait { duration 4 } wait { duration 4 }
rotate { axis [ 0.707 0.707 0 ] rate 20 duration 7 } rotate { axis [ 0.707 0.707 0 ] rate 20 duration 7 }
print { text "Нека да включим рендерирането на галактиките за да видим Млечния път" row -3 duration 4 } print { text "Нека да включим показването на галактиките за да видим Млечния път." row -3 duration 4 }
renderflags { set "galaxies" } renderflags { set "galaxies" }
rotate { axis [ 0.707 0.707 0 ] rate 20 duration 14 } rotate { axis [ 0.707 0.707 0 ] rate 20 duration 14 }
rotate { axis [ 0.707 0.707 0 ] rate 20 duration 10 } rotate { axis [ 0.707 0.707 0 ] rate 20 duration 10 }
@ -122,7 +122,7 @@
select { object "Antares" } select { object "Antares" }
center { time 5 } center { time 5 }
wait { duration 3 } wait { duration 3 }
print { text "Сега ще пътуваме до Антарес, това е звезда червен гигант в съзвездието Скорпион." row -3 duration 5 } print { text "Сега ще посетим Антарес, това е звезда червен гигант в съзвездието Скорпион." row -3 duration 5 }
wait { duration 2 } wait { duration 2 }
renderflags { clear "constellations" } renderflags { clear "constellations" }
labels { clear "constellations|stars" } labels { clear "constellations|stars" }
@ -134,13 +134,13 @@
print { text "Въпреки че сме 10 пъти по-далече от Антарес\nотколкото Земята е от Слънцето, масивната звезда червен гигант изглежда застрашително голяма." row -3} print { text "Въпреки че сме 10 пъти по-далече от Антарес\nотколкото Земята е от Слънцето, масивната звезда червен гигант изглежда застрашително голяма." row -3}
wait { duration 4.0 } wait { duration 4.0 }
print { text "Нека да се отдалечим за да видим как изглежда нашата галактика . . ." row -3} print { text "Нека да се отдалечим за да видим как изглежда нашата галактика..." row -3}
changedistance { duration 10.0 rate 2.0 } changedistance { duration 10.0 rate 2.0 }
select { object "Milky Way" } select { object "Milky Way" }
print { text "Това е Млечния път." row -3 duration 6 } print { text "Това е Млечният път." row -3 duration 6 }
orbit { axis [ 1 0 0 ] rate 30 duration 16.0 } orbit { axis [ 1 0 0 ] rate 30 duration 16.0 }
print { text "Време е да се прибираме . . ." row -3} print { text "Време е да се прибираме..." row -3}
select { object "Sol/Earth" } select { object "Sol/Earth" }
goto { time 20 distance 10 upframe "equatorial" } goto { time 20 distance 10 upframe "equatorial" }

View File

@ -1,7 +1,7 @@
{ {
Name "Юпитер" Name "Юпитер"
Target "Sol/Jupiter" Target "Sol/Jupiter"
Description "Юпитер е най-голямата планета в Слънчевата система и е на пета позиция от Слънцето. Както и останалите външни планети, Юпитер е газов гигант без твърда повърхност. Голямото червено петно е най-голямата и най-продължителната буря в турболентната атмосфера на планетата; тази вихрушка с размерите на Земята съществува от около 300 години." Description "Юпитер е най-голямата планета в Слънчевата система и е на пета позиция от Слънцето. Както и останалите външни планети, Юпитер е газов гигант без твърда повърхност. Голямото червено петно е най-голямата и най-продължителната буря в турболентната атмосфера на планетата тази вихрушка с размерите на Земята съществува от около 300 години."
} }
{ {
@ -9,13 +9,13 @@
Target "Sol/Pluto" Target "Sol/Pluto"
Distance 40000 Distance 40000
DistanceUnits "km" DistanceUnits "km"
Description "Плутон обикаля около Слънцето на средно разстояние от шест милиарда километра. Луната му Харон е толкова голяма, че често ги наричат с Плутон 'двойна планета'." Description "Плутон обикаля около Слънцето на средно разстояние от шест милиарда километра. Спътникът му Харон е толкова голям, че често ги наричат заедно с Плутон „двойната планета“."
} }
{ {
Name "Ерос" Name "Ерос"
Target "Sol/Eros" Target "Sol/Eros"
Description "Ерос е астероид във формата на картоф и е дълъг около 33 км. Благодарение на космическия апарат NEAR Shoemaker, за Ерос знаем повече, отколкото за който и да било друг астероид. На 14 февруари 2001 г. NEAR се спусна на Ерос и стана първият апарат, приземил се на астероид." Description "Ерос е астероид във формата на картоф и е дълъг около 33 км. Благодарение на космическия апарат NEAR Shoemaker, за Ерос знаем повече, отколкото за който и да било друг астероид. На 14 Февруари 2001 г., „NEAR“ се спусна на Ерос и стана първият апарат, приземил се на астероид."
} }
{ {
@ -23,7 +23,7 @@
Target "Alpha Centauri" Target "Alpha Centauri"
Distance 90 Distance 90
DistanceUnits "au" DistanceUnits "au"
Description "Алфа Кантавър А и Б, заедно с Проксима Кентавър, са най-близката звездна система до Земята. Алфа Кентавър А много прилича на Слънцето, въпреки че е малко по-стара и по-ярка. Б е по-тъмна и по-червеникава, а Проксима е толкова слаба, че не може да се види с невъоръжено око, въпреки, че е най-близката звезда до Слънцето." Description "Алфа Кентавър А и Б, заедно с Проксима Кентавър, са най-близката звездна система до Земята. Алфа Кентавър А много прилича на Слънцето, въпреки че е малко по-стара и по-ярка звезда. Алфа Кентавър Б е по-тъмна и по-червеникава, а Проксима Кентавър е толкова слаба, че не може да се види с невъоръжено око, въпреки, че е най-близката звезда до Слънцето."
} }
{ {
@ -31,7 +31,7 @@
Target "Alcyone" Target "Alcyone"
Distance 35 Distance 35
DistanceUnits "ly" DistanceUnits "ly"
Description "Звездния куп Плеяди е група ярки, наскоро формирани звезди. Плеядите носят името на седем сестри от гръцката митология, въпреки, че телескопите са разкрили, че в звездния куп има доста повече от седем звезди." Description "Звездният куп Плеяди е група ярки, наскоро формирани звезди. Плеядите носят името на седем сестри от гръцката митология, въпреки че телескопите са разкрили, че в звездния куп има доста повече от седем звезди."
} }
{ {
@ -39,13 +39,13 @@
Target "63 Tau" Target "63 Tau"
Distance 25 Distance 25
DistanceUnits "ly" DistanceUnits "ly"
Description "Носещи името на петте дъщери на Атлас и Аетра, Хиядите са един от най-видните разсеяни звездни купове в небето. Звездите от звездния куп Хияди са на около 660 милиона години - около шест пъти по-стари от по-горещите и по-сини Плеяди." Description "Носещи името на петте дъщери на Атлас и Аетра, Хиядите са един от най-видните разсеяни звездни купове в небето. Звездите от звездния куп Хияди са на около 660 милиона години - около шест пъти по-стари от по-горещите и по-сини Плеяди."
} }
{ {
Name "Глийзе 876 б" Name "Глийзе 876 б"
Target "Gliese 876/b" Target "Gliese 876/b"
Description "Глийзе 876/б е гигантска планета в орбита около червено джудже. Тя е в резонанс 2:1 с друга планета от същата система." Description "Глийзе 876/б е гигантска планета в орбита около червено джудже. Тя е в резонанс 2:1 с друга планета от същата система."
} }
{ {
@ -53,24 +53,24 @@
Target "Sol/Ida" Target "Sol/Ida"
Distance 200 Distance 200
DistanceUnits "km" DistanceUnits "km"
Description "Космическият апарат Галилео фотографира астероида 243 Ида през 1993 г. на път към Юпитер. Снимките разкриха, че Ида има малък сателит, по-късно наречен Дактил. От тогава насам са открити още няколко астероида със спътници." Description "Космическият апарат Галилео засне астероида 243 Ида през 1993 г. на път към Юпитер. Снимките разкриха, че Ида има малък спътник, по-късно наречен Дактил. От тогава до сега са открити още няколко астероида със спътници."
} }
{ {
Name "51 Пегас б" Name "51 Пегас б"
Target "51 Peg/b" Target "51 Peg/b"
Description "51 Пегас б е първата открита планета, която обикаля около нормална звезда, различна от Слънцето. Тя е планета газов гигант и орбитата ѝ е изключително близо до звездата ѝ - по-малко от една пета от разстоянието между Меркурий и Слънцето. Съществуването на такава планета толкова близо до звезда накара астрономите да преразгледат теориите си за формирането на планетните системи." Description "51 Пегас б е първата открита планета, която обикаля около нормална звезда, различна от Слънцето. Тя е газов гигант и орбитата ѝ е изключително близо до нейната звездата - по-малко от една пета от разстоянието между Меркурий и Слънцето. Съществуването на такава планета толкова близо до звезда накара астрономите да преразгледат теориите си за формирането на планетните системи."
} }
{ {
Name "Албирео" Name "Албирео"
Target "Albireo" Target "Albireo"
Distance 0.6 Distance 0.6
Description "Заради контрастните оранжеви и синьо-бели цветове на съставните ѝ звезди, двойната звездна система Албирео е смятана за една от най-красивите двойки в небето. Оранжевата звезда е клас K гигант, а спътникът ѝ е B джудже." Description "Заради контрастните оранжеви и синьо-бели цветове на съставните ѝ звезди, двойната звездна система Албирео е смятана за една от най-красивите двойки в небето. Оранжевата звезда е гигант от клас K, а спътникът ѝ е джудже от клас B."
} }
{ {
Name "Кометата Борели" Name "Кометата Борели"
Target "Sol/Borrelly" Target "Sol/Borrelly"
Description "На 22 Септември 2001 г., кометата Борели стана втората комета, която беше снимана от космически апарат от близко разстояние. Въпреки че не беше проектиран да облита комети, Deep Space 1 се приближи на 2 200 километра от ядрото на Борели и ни изпрати най-добрите снимки на ядро на комета, с които разполагаме." Description "На 22 Септември 2001 г., кометата Борели стана втората комета, която е заснета от космически апарат от близко разстояние. Въпреки че не е проектиран за това, „Deep Space“ 1 се приближи на 2 200 километра от ядрото на Борели и изпрати най-добрите снимки на ядро на комета, с които разполагаме."
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 716 KiB

2678
po/ru.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -55,7 +55,8 @@ write_buffer(const char* first, const char* last, chars_format fmt, char* buffer
if (*ptr == 'i' || *ptr == 'I') if (*ptr == 'i' || *ptr == 'I')
{ {
if (last - ptr < inf_length) { return { first, std::errc::invalid_argument }; } if (last - ptr < inf_length) { return { first, std::errc::invalid_argument }; }
std::size_t length = std::min(static_cast<std::size_t>(infinity_length), static_cast<std::size_t>(last - ptr)); std::size_t length = std::min(infinity_length, static_cast<std::size_t>(last - ptr));
static_assert(infinity_length < buffer_size, "Buffer too small to hold 'infinity' literal");
std::memcpy(buffer, ptr, length); std::memcpy(buffer, ptr, length);
buffer += length; buffer += length;
} }

View File

@ -100,7 +100,7 @@ void Nebula::render(const Vector3f& /*offset*/,
getOrientation()); getOrientation());
GLSLUnlit_RenderContext rc(renderer, getRadius(), &mv, m.projection); GLSLUnlit_RenderContext rc(renderer, getRadius(), &mv, m.projection);
rc.setPointScale(2.0f * getRadius() / pixelSize * renderer->getScreenDpi() / 96.0f); rc.setPointScale(2.0f * getRadius() / pixelSize);
g->render(rc); g->render(rc);
renderer->enableBlending(); renderer->enableBlending();

View File

@ -25,30 +25,14 @@ template <class OBJ, class PREC> class ObjectRenderer : public OctreeProcessor<O
const Observer* observer { nullptr }; const Observer* observer { nullptr };
Renderer* renderer { nullptr }; Renderer* renderer { nullptr };
Eigen::Vector3f viewNormal;
float fov { 0.0f }; float fov { 0.0f };
float size { 0.0f };
float pixelSize { 0.0f }; float pixelSize { 0.0f };
float faintestMag { 0.0f }; float faintestMag { 0.0f };
float faintestMagNight { 0.0f };
float saturationMag { 0.0f };
float brightnessScale { 0.0f };
float brightnessBias { 0.0f };
float distanceLimit { 0.0f }; float distanceLimit { 0.0f };
// Objects brighter than labelThresholdMag will be labeled // Objects brighter than labelThresholdMag will be labeled
float labelThresholdMag { 0.0f }; float labelThresholdMag { 0.0f };
// These are not fully used by this template's descendants
// but we place them here just in case a more sophisticated
// rendering scheme is implemented:
int nRendered { 0 };
int nClose { 0 };
int nBright { 0 };
int nProcessed { 0 };
int nLabelled { 0 };
uint64_t renderFlags { 0 }; uint64_t renderFlags { 0 };
int labelMode { 0 }; int labelMode { 0 };
}; };

View File

@ -34,7 +34,8 @@ PointStarRenderer::PointStarRenderer() :
void PointStarRenderer::process(const Star& star, float distance, float appMag) void PointStarRenderer::process(const Star& star, float distance, float appMag)
{ {
nProcessed++; if (distance > distanceLimit)
return;
Vector3f starPos = star.getPosition(); Vector3f starPos = star.getPosition();
@ -44,9 +45,6 @@ void PointStarRenderer::process(const Star& star, float distance, float appMag)
float orbitalRadius = star.getOrbitalRadius(); float orbitalRadius = star.getOrbitalRadius();
bool hasOrbit = orbitalRadius > 0.0f; bool hasOrbit = orbitalRadius > 0.0f;
if (distance > distanceLimit)
return;
// A very rough check to see if the star may be visible: is the star in // A very rough check to see if the star may be visible: is the star in
// front of the viewer? If the star might be close (relPos.x^2 < 0.1) or // front of the viewer? If the star might be close (relPos.x^2 < 0.1) or
// is moving in an orbit, we'll always regard it as potentially visible. // is moving in an orbit, we'll always regard it as potentially visible.
@ -69,10 +67,10 @@ void PointStarRenderer::process(const Star& star, float distance, float appMag)
// * It may be large enough that we should render it as a mesh // * It may be large enough that we should render it as a mesh
// instead of a particle // instead of a particle
// It's possible that the second condition might apply for stars // It's possible that the second condition might apply for stars
// further than one light year away if the star is huge, the fov is // further than a solar system size if the star is huge, the fov is
// very small and the resolution is high. We'll ignore this for now // very small and the resolution is high. We'll ignore this for now
// and use the most inexpensive test possible . . . // and use the most inexpensive test possible . . .
if (distance < 1.0f || orbitSizeInPixels > 1.0f) if (distance < SolarSystemMaxDistance || orbitSizeInPixels > 1.0f)
{ {
// Compute the position of the observer relative to the star. // Compute the position of the observer relative to the star.
// This is a much more accurate (and expensive) distance // This is a much more accurate (and expensive) distance
@ -85,10 +83,9 @@ void PointStarRenderer::process(const Star& star, float distance, float appMag)
distance = relPos.norm(); distance = relPos.norm();
// Recompute apparent magnitude using new distance computation // Recompute apparent magnitude using new distance computation
appMag = star.getApparentMagnitude((float)distance); appMag = star.getApparentMagnitude(distance);
discSizeInPixels = star.getRadius() / astro::lightYearsToKilometers(distance) / pixelSize; discSizeInPixels = star.getRadius() / astro::lightYearsToKilometers(distance) / pixelSize;
++nClose;
} }
// Stars closer than the maximum solar system size are actually // Stars closer than the maximum solar system size are actually
@ -96,44 +93,19 @@ void PointStarRenderer::process(const Star& star, float distance, float appMag)
// planets. // planets.
if (distance > SolarSystemMaxDistance) if (distance > SolarSystemMaxDistance)
{ {
float satPoint = faintestMag - (1.0f - brightnessBias) / brightnessScale; // TODO: precompute this value float pointSize, alpha, glareSize, glareAlpha;
float alpha = (faintestMag - appMag) * brightnessScale + brightnessBias; float size = BaseStarDiscSize * static_cast<float>(renderer->getScreenDpi()) / 96.0f;
renderer->calculatePointSize(appMag,
size,
pointSize,
alpha,
glareSize,
glareAlpha);
if (useScaledDiscs) if (glareSize != 0.0f)
{ glareVertexBuffer->addStar(relPos, Color(starColor, glareAlpha), glareSize);
float discSize = size; if (pointSize != 0.0f)
if (alpha < 0.0f) starVertexBuffer->addStar(relPos, Color(starColor, alpha), pointSize);
{
alpha = 0.0f;
}
else if (alpha > 1.0f)
{
float discScale = min(MaxScaledDiscStarSize, (float) pow(2.0f, 0.3f * (satPoint - appMag)));
discSize *= discScale;
float glareAlpha = min(0.5f, discScale / 4.0f);
glareVertexBuffer->addStar(relPos, Color(starColor, glareAlpha), discSize * 3.0f);
alpha = 1.0f;
}
starVertexBuffer->addStar(relPos, Color(starColor, alpha), discSize);
}
else
{
if (alpha < 0.0f)
{
alpha = 0.0f;
}
else if (alpha > 1.0f)
{
float discScale = min(100.0f, satPoint - appMag + 2.0f);
float glareAlpha = min(GlareOpacity, (discScale - 2.0f) / 4.0f);
glareVertexBuffer->addStar(relPos, Color(starColor, glareAlpha), 2.0f * discScale * size);
}
starVertexBuffer->addStar(relPos, Color(starColor, alpha), size);
}
++nRendered;
// Place labels for stars brighter than the specified label threshold brightness // Place labels for stars brighter than the specified label threshold brightness
if (((labelMode & Renderer::StarLabels) != 0) && appMag < labelThresholdMag) if (((labelMode & Renderer::StarLabels) != 0) && appMag < labelThresholdMag)
@ -147,7 +119,6 @@ void PointStarRenderer::process(const Star& star, float distance, float appMag)
starDB->getStarName(star, true), starDB->getStarName(star, true),
color, color,
relPos); relPos);
nLabelled++;
} }
} }
} }

View File

@ -43,13 +43,12 @@ class PointStarRenderer : public ObjectRenderer<Star, float>
void process(const Star &star, float distance, float appMag); void process(const Star &star, float distance, float appMag);
Eigen::Vector3d obsPos; Eigen::Vector3d obsPos;
Eigen::Vector3f viewNormal;
std::vector<RenderListEntry>* renderList { nullptr }; std::vector<RenderListEntry>* renderList { nullptr };
PointStarVertexBuffer* starVertexBuffer { nullptr }; PointStarVertexBuffer* starVertexBuffer { nullptr };
PointStarVertexBuffer* glareVertexBuffer { nullptr }; PointStarVertexBuffer* glareVertexBuffer { nullptr };
const StarDatabase* starDB { nullptr }; const StarDatabase* starDB { nullptr };
const ColorTemperatureTable* colorTemp { nullptr }; const ColorTemperatureTable* colorTemp { nullptr };
float SolarSystemMaxDistance { 1.0f }; float SolarSystemMaxDistance { 1.0f };
float maxDiscSize { 1.0f };
float cosFOV { 1.0f }; float cosFOV { 1.0f };
bool useScaledDiscs { false };
}; };

View File

@ -80,7 +80,7 @@ void PointStarVertexBuffer::makeCurrent()
current->finish(); current->finish();
program->use(); program->use();
program->setMVPMatrices(renderer.getProjectionMatrix(), renderer.getModelViewMatrix()); program->setMVPMatrices(renderer.getCurrentProjectionMatrix(), renderer.getCurrentModelViewMatrix());
if (pointSizeFromVertex) if (pointSizeFromVertex)
{ {
program->samplerParam("starTex") = 0; program->samplerParam("starTex") = 0;

View File

@ -16,6 +16,7 @@
#include "lightenv.h" #include "lightenv.h"
#include "rendcontext.h" #include "rendcontext.h"
#include "render.h" #include "render.h"
#include "shadowmap.h" // GL_ONLY_SHADOWS definition
#include "texmanager.h" #include "texmanager.h"
#include "texture.h" #include "texture.h"

View File

@ -1560,6 +1560,13 @@ void Renderer::draw(const Observer& observer,
else else
brightnessScale = 0.1667f; brightnessScale = 0.1667f;
brightnessScale *= corrFac;
if (starStyle == ScaledDiscStars)
brightnessScale *= 2.0f;
// Calculate saturation magnitude
satPoint = faintestMag - (1.0f - brightnessBias) / brightnessScale;
ambientColor = Color(ambientLightLevel, ambientLightLevel, ambientLightLevel); ambientColor = Color(ambientLightLevel, ambientLightLevel, ambientLightLevel);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
@ -1662,43 +1669,7 @@ void Renderer::draw(const Observer& observer,
enableDepthMask(); enableDepthMask();
} }
void renderPoint(const Renderer &renderer, static
const Vector3f &position,
const Color &color,
float size,
bool useSprite,
const Matrices &m)
{
auto *prog = renderer.getShaderManager().getShader("star");
if (prog == nullptr)
return;
prog->use();
prog->samplerParam("starTex") = 0;
prog->setMVPMatrices(*m.projection, *m.modelview);
#ifndef GL_ES
glEnable(GL_POINT_SPRITE);
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
#endif
// Workaround for macOS to pass a single vertex coord
glEnableVertexAttribArray(CelestiaGLProgram::VertexCoordAttributeIndex);
glVertexAttribPointer(CelestiaGLProgram::VertexCoordAttributeIndex,
3, GL_FLOAT, GL_FALSE, sizeof(position), position.data());
glVertexAttrib(CelestiaGLProgram::ColorAttributeIndex, color);
glVertexAttrib1f(CelestiaGLProgram::PointSizeAttributeIndex, useSprite ? size : renderer.getScreenDpi() / 96.0f);
glDrawArrays(GL_POINTS, 0, 1);
glDisableVertexAttribArray(CelestiaGLProgram::VertexCoordAttributeIndex);
#ifndef GL_ES
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
glDisable(GL_POINT_SPRITE);
#endif
}
void renderLargePoint(Renderer &renderer, void renderLargePoint(Renderer &renderer,
const Vector3f &position, const Vector3f &position,
const Color &color, const Color &color,
@ -1741,6 +1712,64 @@ void renderLargePoint(Renderer &renderer,
vo.unbind(); vo.unbind();
} }
static Eigen::Vector3f
calculateQuadCenter(const Eigen::Quaternionf &cameraOrientation,
const Eigen::Vector3f &position,
float radius)
{
Matrix3f m = cameraOrientation.conjugate().toRotationMatrix();
// Offset the glare sprite so that it lies in front of the object
Vector3f direction = position.normalized();
// Position the sprite on the the line between the viewer and the
// object, and on a plane normal to the view direction.
return position + direction * (radius / (m * Vector3f::UnitZ()).dot(direction));
}
void
Renderer::calculatePointSize(float appMag,
float size,
float &discSize,
float &alpha,
float &glareSize,
float &glareAlpha) const
{
alpha = std::max(0.0f, (faintestMag - appMag) * brightnessScale + brightnessBias);
discSize = size;
if (starStyle == ScaledDiscStars)
{
if (alpha > 1.0f)
{
float discScale = std::min(MaxScaledDiscStarSize, pow(2.0f, 0.3f * (satPoint - appMag)));
discSize *= std::max(1.0f, discScale);
glareAlpha = std::min(0.5f, discScale / 4.0f);
glareSize = discSize * 3.0f;
alpha = 1.0f;
}
else
{
glareSize = glareAlpha = 0.0f;
}
}
else
{
if (alpha > 1.0f)
{
float discScale = std::min(100.0f, satPoint - appMag + 2.0f);
glareAlpha = std::min(GlareOpacity, (discScale - 2.0f) / 4.0f);
glareSize = 2.0f * discScale * size;
alpha = 1.0f;
}
else
{
glareSize = glareAlpha = 0.0f;
}
}
}
// If the an object occupies a pixel or less of screen space, we don't // If the an object occupies a pixel or less of screen space, we don't
// render its mesh at all and just display a starlike point instead. // render its mesh at all and just display a starlike point instead.
@ -1751,95 +1780,49 @@ void renderLargePoint(Renderer &renderer,
void Renderer::renderObjectAsPoint(const Vector3f& position, void Renderer::renderObjectAsPoint(const Vector3f& position,
float radius, float radius,
float appMag, float appMag,
float _faintestMag,
float discSizeInPixels, float discSizeInPixels,
const Color &color, const Color &color,
bool useHalos, bool useHalos,
bool emissive, bool emissive,
const Matrices &mvp) const Matrices &mvp)
{ {
const float maxSize = MaxScaledDiscStarSize; const bool useScaledDiscs = starStyle == ScaledDiscStars;
float maxDiscSize = (starStyle == ScaledDiscStars) ? maxSize : 1.0f; float maxDiscSize = useScaledDiscs ? MaxScaledDiscStarSize : 1.0f;
float maxBlendDiscSize = maxDiscSize + 3.0f; float maxBlendDiscSize = maxDiscSize + 3.0f;
bool useScaledDiscs = starStyle == ScaledDiscStars;
if (discSizeInPixels < maxBlendDiscSize || useHalos) if (discSizeInPixels < maxBlendDiscSize || useHalos)
{ {
float alpha = 1.0f;
float fade = 1.0f; float fade = 1.0f;
float size = BaseStarDiscSize * screenDpi / 96.0f;
float satPoint = _faintestMag - (1.0f - brightnessBias) / brightnessScale;
if (discSizeInPixels > maxDiscSize) if (discSizeInPixels > maxDiscSize)
{ {
fade = (maxBlendDiscSize - discSizeInPixels) / fade = std::min(1.0f, (maxBlendDiscSize - discSizeInPixels) /
(maxBlendDiscSize - maxDiscSize); (maxBlendDiscSize - maxDiscSize));
if (fade > 1)
fade = 1;
} }
alpha = (_faintestMag - appMag) * brightnessScale * 2.0f + brightnessBias; float scale = static_cast<float>(screenDpi) / 96.0f;
if (alpha < 0.0f) float pointSize, alpha, glareSize, glareAlpha;
alpha = 0.0f; calculatePointSize(appMag, BaseStarDiscSize * scale, pointSize, alpha, glareSize, glareAlpha);
float pointSize = size; if (useScaledDiscs && discSizeInPixels > MaxScaledDiscStarSize)
float glareSize = 0.0f; glareAlpha = std::min(glareAlpha, (MaxScaledDiscStarSize - discSizeInPixels) / MaxScaledDiscStarSize + 1.0f);
float glareAlpha = 0.0f;
if (useScaledDiscs)
{
if (alpha > 1.0f)
{
float discScale = min(maxSize, (float) pow(2.0f, 0.3f * (satPoint - appMag)));
pointSize *= max(1.0f, discScale);
glareAlpha = min(0.5f, discScale / 4.0f);
if (discSizeInPixels > maxSize)
glareAlpha = min(glareAlpha, (maxSize - discSizeInPixels) / maxSize + 1.0f);
glareSize = pointSize * 3.0f;
alpha = 1.0f;
}
}
else
{
if (alpha > 1.0f)
{
float discScale = min(100.0f, satPoint - appMag + 2.0f);
glareAlpha = min(GlareOpacity, (discScale - 2.0f) / 4.0f);
glareSize = pointSize * discScale * 2.0f ;
if (emissive)
glareSize = max(glareSize, pointSize * discSizeInPixels / (screenDpi / 96.0f) * 3.0f);
}
}
alpha *= fade; alpha *= fade;
if (!emissive) if (!emissive)
{
glareSize = max(glareSize, pointSize * discSizeInPixels / (screenDpi / 96.0f) * 3.0f);
glareAlpha *= fade; glareAlpha *= fade;
}
Matrix3f m = m_cameraOrientation.conjugate().toRotationMatrix(); if (glareSize != 0.0f)
Vector3f center = position; glareSize = std::max(glareSize, pointSize * discSizeInPixels / scale * 3.0f);
// Offset the glare sprite so that it lies in front of the object
Vector3f direction = center.normalized();
// Position the sprite on the the line between the viewer and the
// object, and on a plane normal to the view direction.
center = center + direction * (radius / (m * Vector3f::UnitZ()).dot(direction));
enableDepthTest(); enableDepthTest();
disableDepthMask(); disableDepthMask();
bool useSprites = starStyle != PointStars; if (starStyle != PointStars)
if (useSprites)
gaussianDiscTex->bind(); gaussianDiscTex->bind();
if (pointSize > gl::maxPointSize) if (pointSize > gl::maxPointSize)
renderLargePoint(*this, center, {color, alpha}, pointSize, mvp); renderLargePoint(*this, position, {color, alpha}, pointSize, mvp);
else else
renderPoint(*this, center, {color, alpha}, pointSize, useSprites, mvp); pointStarVertexBuffer->addStar(position, {color, alpha}, pointSize);
// If the object is brighter than magnitude 1, add a halo around it to // If the object is brighter than magnitude 1, add a halo around it to
// make it appear more brilliant. This is a hack to compensate for the // make it appear more brilliant. This is a hack to compensate for the
@ -1849,11 +1832,12 @@ void Renderer::renderObjectAsPoint(const Vector3f& position,
// with halos. // with halos.
if (useHalos && glareAlpha > 0.0f) if (useHalos && glareAlpha > 0.0f)
{ {
Eigen::Vector3f center = calculateQuadCenter(m_cameraOrientation, position, radius);
gaussianGlareTex->bind(); gaussianGlareTex->bind();
if (glareSize > gl::maxPointSize) if (glareSize > gl::maxPointSize)
renderLargePoint(*this, center, {color, glareAlpha}, glareSize, mvp); renderLargePoint(*this, center, {color, glareAlpha}, glareSize, mvp);
else else
renderPoint(*this, center, {color, glareAlpha}, glareSize, true, mvp); glareVertexBuffer->addStar(center, {color, glareAlpha}, glareSize);
} }
} }
} }
@ -2586,14 +2570,14 @@ void Renderer::renderObject(const Vector3f& pos,
geometryScale = obj.radius; geometryScale = obj.radius;
scaleFactors = obj.radius * obj.semiAxes; scaleFactors = obj.radius * obj.semiAxes;
ringsScaleFactor = obj.radius * obj.semiAxes.maxCoeff(); ringsScaleFactor = obj.radius * obj.semiAxes.maxCoeff();
ri.pointScale = 2.0f * obj.radius / pixelSize * screenDpi / 96.0f; ri.pointScale = 2.0f * obj.radius / pixelSize;
} }
else else
{ {
geometryScale = obj.geometryScale; geometryScale = obj.geometryScale;
scaleFactors = Vector3f::Constant(geometryScale); scaleFactors = Vector3f::Constant(geometryScale);
ringsScaleFactor = geometryScale; ringsScaleFactor = geometryScale;
ri.pointScale = 2.0f * geometryScale / pixelSize * screenDpi / 96.0f; ri.pointScale = 2.0f * geometryScale / pixelSize;
} }
// Apply the modelview transform for the object // Apply the modelview transform for the object
Affine3f transform = Translation3f(pos) * obj.orientation.conjugate(); Affine3f transform = Translation3f(pos) * obj.orientation.conjugate();
@ -3317,7 +3301,6 @@ void Renderer::renderPlanet(Body& body,
renderObjectAsPoint(pos, renderObjectAsPoint(pos,
body.getRadius(), body.getRadius(),
appMag, appMag,
faintestMag,
discSizeInPixels, discSizeInPixels,
body.getSurface().color, body.getSurface().color,
false, false, m); false, false, m);
@ -3396,7 +3379,6 @@ void Renderer::renderStar(const Star& star,
renderObjectAsPoint(pos, renderObjectAsPoint(pos,
star.getRadius(), star.getRadius(),
appMag, appMag,
faintestMag,
discSizeInPixels, discSizeInPixels,
color, color,
star.hasCorona(), true, star.hasCorona(), true,
@ -4371,11 +4353,7 @@ void Renderer::renderPointStars(const StarDatabase& starDB,
starRenderer.cosFOV = (float) cos(degToRad(calcMaxFOV(fov, getAspectRatio())) / 2.0f); starRenderer.cosFOV = (float) cos(degToRad(calcMaxFOV(fov, getAspectRatio())) / 2.0f);
starRenderer.pixelSize = pixelSize; starRenderer.pixelSize = pixelSize;
starRenderer.brightnessScale = brightnessScale * corrFac;
starRenderer.brightnessBias = brightnessBias;
starRenderer.faintestMag = faintestMag; starRenderer.faintestMag = faintestMag;
starRenderer.faintestMagNight = faintestMagNight;
starRenderer.saturationMag = saturationMag;
starRenderer.distanceLimit = distanceLimit; starRenderer.distanceLimit = distanceLimit;
starRenderer.labelMode = labelMode; starRenderer.labelMode = labelMode;
starRenderer.SolarSystemMaxDistance = SolarSystemMaxDistance; starRenderer.SolarSystemMaxDistance = SolarSystemMaxDistance;
@ -4384,18 +4362,6 @@ void Renderer::renderPointStars(const StarDatabase& starDB,
float effDistanceToScreen = mmToInches((float) REF_DISTANCE_TO_SCREEN) * pixelSize * getScreenDpi(); float effDistanceToScreen = mmToInches((float) REF_DISTANCE_TO_SCREEN) * pixelSize * getScreenDpi();
starRenderer.labelThresholdMag = 1.2f * max(1.0f, (faintestMag - 4.0f) * (1.0f - 0.5f * (float) log10(effDistanceToScreen))); starRenderer.labelThresholdMag = 1.2f * max(1.0f, (faintestMag - 4.0f) * (1.0f - 0.5f * (float) log10(effDistanceToScreen)));
starRenderer.size = BaseStarDiscSize * screenDpi / 96.0f;
if (starStyle == ScaledDiscStars)
{
starRenderer.useScaledDiscs = true;
starRenderer.brightnessScale *= 2.0f;
starRenderer.maxDiscSize = starRenderer.size * MaxScaledDiscStarSize;
}
else if (starStyle == FuzzyPointStars)
{
starRenderer.brightnessScale *= 1.0f;
}
starRenderer.colorTemp = colorTemp; starRenderer.colorTemp = colorTemp;
gaussianDiscTex->bind(); gaussianDiscTex->bind();
@ -4455,17 +4421,11 @@ void Renderer::renderDeepSkyObjects(const Universe& universe,
dsoRenderer.orientationMatrix= observer.getOrientationf().conjugate().toRotationMatrix(); dsoRenderer.orientationMatrix= observer.getOrientationf().conjugate().toRotationMatrix();
dsoRenderer.observer = &observer; dsoRenderer.observer = &observer;
dsoRenderer.obsPos = obsPos; dsoRenderer.obsPos = obsPos;
dsoRenderer.viewNormal = observer.getOrientationf().conjugate() * -Vector3f::UnitZ();
dsoRenderer.fov = fov; dsoRenderer.fov = fov;
// size/pixelSize =0.86 at 120deg, 1.43 at 45deg and 1.6 at 0deg. // size/pixelSize =0.86 at 120deg, 1.43 at 45deg and 1.6 at 0deg.
dsoRenderer.size = pixelSize * 1.6f / corrFac;
dsoRenderer.pixelSize = pixelSize; dsoRenderer.pixelSize = pixelSize;
dsoRenderer.brightnessScale = brightnessScale * corrFac;
dsoRenderer.brightnessBias = brightnessBias;
dsoRenderer.avgAbsMag = dsoDB->getAverageAbsoluteMagnitude(); dsoRenderer.avgAbsMag = dsoDB->getAverageAbsoluteMagnitude();
dsoRenderer.faintestMag = faintestMag; dsoRenderer.faintestMag = faintestMag;
dsoRenderer.faintestMagNight = faintestMagNight;
dsoRenderer.saturationMag = saturationMag;
dsoRenderer.renderFlags = renderFlags; dsoRenderer.renderFlags = renderFlags;
dsoRenderer.labelMode = labelMode; dsoRenderer.labelMode = labelMode;
dsoRenderer.wWidth = windowWidth; dsoRenderer.wWidth = windowWidth;
@ -5988,6 +5948,8 @@ Renderer::renderSolarSystemObjects(const Observer &observer,
proj = Perspective(fov, aspectRatio, nearPlaneDistance, farPlaneDistance); proj = Perspective(fov, aspectRatio, nearPlaneDistance, farPlaneDistance);
Matrices m = { &proj, &m_modelMatrix }; Matrices m = { &proj, &m_modelMatrix };
setCurrentProjectionMatrix(proj);
Frustum intervalFrustum(degToRad(fov), Frustum intervalFrustum(degToRad(fov),
aspectRatio, aspectRatio,
nearPlaneDistance, nearPlaneDistance,
@ -6050,6 +6012,18 @@ Renderer::renderSolarSystemObjects(const Observer &observer,
i--; i--;
} }
PointStarVertexBuffer::enable();
glareVertexBuffer->startSprites();
glareVertexBuffer->render();
glareVertexBuffer->finish();
if (starStyle == PointStars)
pointStarVertexBuffer->startBasicPoints();
else
pointStarVertexBuffer->startSprites();
pointStarVertexBuffer->render();
pointStarVertexBuffer->finish();
PointStarVertexBuffer::disable();
// Render annotations in this interval // Render annotations in this interval
enableSmoothLines(); enableSmoothLines();
annotation = renderSortedAnnotations(annotation, annotation = renderSortedAnnotations(annotation,
@ -6062,4 +6036,5 @@ Renderer::renderSolarSystemObjects(const Observer &observer,
// reset the depth range // reset the depth range
glDepthRange(0, 1); glDepthRange(0, 1);
setDefaultProjectionMatrix();
} }

View File

@ -318,10 +318,12 @@ class Renderer
{ {
return m_modelMatrix; return m_modelMatrix;
} }
const Eigen::Matrix4f& getProjectionMatrix() const const Eigen::Matrix4f& getProjectionMatrix() const
{ {
return m_projMatrix; return m_projMatrix;
} }
const Eigen::Matrix4f& getOrthoProjectionMatrix() const const Eigen::Matrix4f& getOrthoProjectionMatrix() const
{ {
return m_orthoProjMatrix; return m_orthoProjMatrix;
@ -337,6 +339,11 @@ class Renderer
m_modelViewPtr = &m; m_modelViewPtr = &m;
} }
void setDefaultModelViewMatrix()
{
m_modelViewPtr = &m_modelMatrix;
}
const Eigen::Matrix4f& getCurrentProjectionMatrix() const const Eigen::Matrix4f& getCurrentProjectionMatrix() const
{ {
return *m_projectionPtr; return *m_projectionPtr;
@ -347,6 +354,11 @@ class Renderer
m_projectionPtr = &m; m_projectionPtr = &m;
} }
void setDefaultProjectionMatrix()
{
m_projectionPtr = &m_projMatrix;
}
void setStarStyle(StarStyle); void setStarStyle(StarStyle);
StarStyle getStarStyle() const; StarStyle getStarStyle() const;
void setResolution(unsigned int resolution); void setResolution(unsigned int resolution);
@ -618,10 +630,16 @@ class Renderer
float discSizeInPixels, float discSizeInPixels,
const Matrices&); const Matrices&);
void calculatePointSize(float appMag,
float size,
float &discSize,
float &alpha,
float &glareSize,
float &glareAlpha) const;
void renderObjectAsPoint(const Eigen::Vector3f& center, void renderObjectAsPoint(const Eigen::Vector3f& center,
float radius, float radius,
float appMag, float appMag,
float _faintestMag,
float discSizeInPixels, float discSizeInPixels,
const Color& color, const Color& color,
bool useHalos, bool useHalos,
@ -840,6 +858,9 @@ class Renderer
std::array<celgl::VertexObject*, static_cast<size_t>(VOType::Count)> m_VertexObjects; std::array<celgl::VertexObject*, static_cast<size_t>(VOType::Count)> m_VertexObjects;
// Saturation magnitude used to calculate a point star size
float satPoint;
// Location markers // Location markers
public: public:
celestia::MarkerRepresentation mountainRep; celestia::MarkerRepresentation mountainRep;
@ -897,6 +918,8 @@ class Renderer
static Color EclipticColor; static Color EclipticColor;
static Color SelectionCursorColor; static Color SelectionCursorColor;
friend class PointStarRenderer;
}; };

View File

@ -32,6 +32,7 @@
#include "renderglsl.h" #include "renderglsl.h"
#include "renderinfo.h" #include "renderinfo.h"
#include "shadermanager.h" #include "shadermanager.h"
#include "shadowmap.h" // GL_ONLY_SHADOWS definition
#include "texture.h" #include "texture.h"
#include "vecgl.h" #include "vecgl.h"

View File

@ -387,7 +387,7 @@ static float rotperiod_M[3][10] =
const char* LumClassNames[StellarClass::Lum_Count] = { const char* LumClassNames[StellarClass::Lum_Count] = {
"I-a0", "I-a", "I-b", "II", "III", "IV", "V", "VI", "" "Ia-0", "Ia", "Ib", "II", "III", "IV", "V", "VI", ""
}; };
const char* SubclassNames[11] = { const char* SubclassNames[11] = {

View File

@ -17,59 +17,43 @@
using namespace Eigen; using namespace Eigen;
using namespace std; using namespace std;
// TODO: More of the functions in this module should be converted to
// methods of the StarBrowser class.
struct CloserStarPredicate struct CloserStarPredicate
{ {
Vector3f pos; Vector3f pos;
bool operator()(const Star* star0, const Star* star1) const bool operator()(const Star* star0, const Star* star1) const
{ {
Vector3f p0 = star0->getPosition(); return (pos - star0->getPosition()).squaredNorm() < (pos - star1->getPosition()).squaredNorm();
Vector3f p1 = star1->getPosition();
#if 0
Vector3f v0(p0.x * 1e6 - pos.x, p0.y * 1e6 - pos.y, p0.z * 1e6 - pos.z);
Vector3f v1(p1.x * 1e6 - pos.x, p1.y * 1e6 - pos.y, p1.z * 1e6 - pos.z);
#endif
Vector3f v0 = p0 * 1.0e6f - pos;
Vector3f v1 = p1 * 1.0e6f - pos;
return (v0.squaredNorm() < v1.squaredNorm());
} }
}; };
struct BrighterStarPredicate struct BrighterStarPredicate
{ {
Vector3f pos; Vector3f pos;
UniversalCoord ucPos; UniversalCoord ucPos;
bool operator()(const Star* star0, const Star* star1) const bool operator()(const Star* star0, const Star* star1) const
{ {
Vector3f p0 = star0->getPosition(); float d0 = (pos - star0->getPosition()).norm();
Vector3f p1 = star1->getPosition(); float d1 = (pos - star1->getPosition()).norm();
Vector3f v0 = p0 * 1.0e6f - pos;
Vector3f v1 = p1 * 1.0e6f - pos;
float d0 = v0.norm();
float d1 = v1.norm();
return (star0->getApparentMagnitude(d0) < // If the stars are closer than one light year, use
star1->getApparentMagnitude(d1)); // a more precise distance estimate.
if (d0 < 1.0f)
d0 = ucPos.offsetFromLy(star0->getPosition()).norm();
if (d1 < 1.0f)
d1 = ucPos.offsetFromLy(star1->getPosition()).norm();
return star0->getApparentMagnitude(d0) < star1->getApparentMagnitude(d1);
} }
}; };
struct BrightestStarPredicate struct BrightestStarPredicate
{ {
bool operator()(const Star* star0, const Star* star1) const bool operator()(const Star* star0, const Star* star1) const
{ {
return (star0->getAbsoluteMagnitude() < return star0->getAbsoluteMagnitude() < star1->getAbsoluteMagnitude();
star1->getAbsoluteMagnitude());
} }
}; };
struct SolarSystemPredicate struct SolarSystemPredicate
{ {
Vector3f pos; Vector3f pos;
@ -85,11 +69,7 @@ struct SolarSystemPredicate
bool hasPlanets1 = (iter != solarSystems->end()); bool hasPlanets1 = (iter != solarSystems->end());
if (hasPlanets1 == hasPlanets0) if (hasPlanets1 == hasPlanets0)
{ {
Vector3f p0 = star0->getPosition(); return ((pos - star0->getPosition()).squaredNorm() < (pos - star1->getPosition()).squaredNorm());
Vector3f p1 = star1->getPosition();
Vector3f v0 = p0 * 1.0e6f - pos;
Vector3f v1 = p1 * 1.0e6f - pos;
return (v0.squaredNorm() < v1.squaredNorm());
} }
else else
{ {

View File

@ -57,62 +57,6 @@ Color StellarClass::getApparentColor(StellarClass::SpectralClass sc) const
} }
} }
// The << method of converting the stellar class to a string is
// preferred, but it's not always practical, especially when you've
// got a completely broken implementation of stringstreams to
// deal with (*cough* gcc *cough*).
string StellarClass::str() const
{
char s0, s1;
const char* s2 = "";
switch (getStarType())
{
case StellarClass::WhiteDwarf:
return "WD";
case StellarClass::NeutronStar:
return "Q";
case StellarClass::BlackHole:
return "X";
case StellarClass::NormalStar:
s0 = "OBAFGKMRSNWWW?LTYC"[(unsigned int) getSpectralClass()];
s1 = "0123456789"[getSubclass()];
switch (getLuminosityClass())
{
case StellarClass::Lum_Ia0:
s2 = " I-a0";
break;
case StellarClass::Lum_Ia:
s2 = " I-a";
break;
case StellarClass::Lum_Ib:
s2 = " I-b";
break;
case StellarClass::Lum_II:
s2 = " II";
break;
case StellarClass::Lum_III:
s2 = " III";
break;
case StellarClass::Lum_IV:
s2 = " IV";
break;
case StellarClass::Lum_V:
s2 = " V";
break;
case StellarClass::Lum_VI:
s2 = " VI";
break;
default: break; // Do nothing, but prevent GCC4 warnings (Beware: potentially dangerous)
}
return fmt::sprintf("%c%c%s", s0, s1, s2);
}
return "?";
}
uint16_t uint16_t
StellarClass::packV1() const StellarClass::packV1() const
{ {
@ -238,14 +182,6 @@ StellarClass::unpackV2(uint16_t st)
} }
ostream& operator<<(ostream& os, const StellarClass& sc)
{
os << sc.str();
return os;
}
bool operator<(const StellarClass& sc0, const StellarClass& sc1) bool operator<(const StellarClass& sc0, const StellarClass& sc1)
{ {
return sc0.packV2() < sc1.packV2(); return sc0.packV2() < sc1.packV2();
@ -273,6 +209,7 @@ enum ParseState
LumClassVState, LumClassVState,
LumClassIdashState, LumClassIdashState,
LumClassIaState, LumClassIaState,
LumClassIdashaState,
WDTypeState, WDTypeState,
WDExtendedTypeState, WDExtendedTypeState,
WDSubclassState, WDSubclassState,
@ -482,6 +419,8 @@ StellarClass::parse(const string& st)
case 'V': case 'V':
state = LumClassVState; state = LumClassVState;
break; break;
case ' ':
break;
default: default:
state = EndState; state = EndState;
break; break;
@ -535,7 +474,8 @@ StellarClass::parse(const string& st)
switch (c) switch (c)
{ {
case 'a': case 'a':
state = LumClassIaState; state = LumClassIdashaState;
i++;
break; break;
case 'b': case 'b':
lumClass = StellarClass::Lum_Ib; lumClass = StellarClass::Lum_Ib;
@ -549,6 +489,24 @@ StellarClass::parse(const string& st)
break; break;
case LumClassIaState: case LumClassIaState:
switch (c)
{
case '0':
lumClass = StellarClass::Lum_Ia0;
state = EndState;
break;
case '-':
state = LumClassIdashaState;
i++;
break;
default:
lumClass = StellarClass::Lum_Ia;
state = EndState;
break;
}
break;
case LumClassIdashaState:
switch (c) switch (c)
{ {
case '0': case '0':

View File

@ -35,9 +35,9 @@ public:
Spectral_G = 4, Spectral_G = 4,
Spectral_K = 5, Spectral_K = 5,
Spectral_M = 6, Spectral_M = 6,
Spectral_R = 7, // superceded by class C Spectral_R = 7, // superseded by class C
Spectral_S = 8, Spectral_S = 8,
Spectral_N = 9, // superceded by class C Spectral_N = 9, // superseded by class C
Spectral_WC = 10, Spectral_WC = 10,
Spectral_WN = 11, Spectral_WN = 11,
Spectral_WO = 12, Spectral_WO = 12,
@ -98,8 +98,6 @@ public:
Color getApparentColor() const; Color getApparentColor() const;
Color getApparentColor(StellarClass::SpectralClass sc) const; Color getApparentColor(StellarClass::SpectralClass sc) const;
std::string str() const;
static StellarClass parse(const std::string&); static StellarClass parse(const std::string&);
friend bool operator<(const StellarClass& sc0, const StellarClass& sc1); friend bool operator<(const StellarClass& sc0, const StellarClass& sc1);
@ -123,8 +121,6 @@ private:
}; };
std::ostream& operator<<(std::ostream& os, const StellarClass& sc);
// A rough ordering of stellar classes, from 'early' to 'late' . . . // A rough ordering of stellar classes, from 'early' to 'late' . . .
// Useful for organizing a list of stars by spectral class. // Useful for organizing a list of stars by spectral class.
bool operator<(const StellarClass& sc0, const StellarClass& sc1); bool operator<(const StellarClass& sc0, const StellarClass& sc1);

View File

@ -80,6 +80,10 @@ if(ENABLE_FFMPEG)
target_link_libraries(celestia ${FFMPEG_LIBRARIES}) target_link_libraries(celestia ${FFMPEG_LIBRARIES})
endif() endif()
if (HAVE_MESHOPTIMIZER)
target_link_libraries(celestia meshoptimizer::meshoptimizer)
endif()
install(TARGETS celestia LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} NAMELINK_SKIP) install(TARGETS celestia LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} NAMELINK_SKIP)
add_subdirectory(glut) add_subdirectory(glut)

View File

@ -4053,14 +4053,10 @@ bool CelestiaCore::initRenderer()
if (font == nullptr) if (font == nullptr)
cout << _("Error loading font; text will not be visible.\n"); cout << _("Error loading font; text will not be visible.\n");
else
font->buildTexture();
if (!config->titleFont.empty()) if (!config->titleFont.empty())
titleFont = LoadFontHelper(renderer, config->titleFont); titleFont = LoadFontHelper(renderer, config->titleFont);
if (titleFont != nullptr) if (titleFont == nullptr)
titleFont->buildTexture();
else
titleFont = font; titleFont = font;
// Set up the overlay // Set up the overlay
@ -4074,15 +4070,7 @@ bool CelestiaCore::initRenderer()
else else
{ {
auto labelFont = LoadFontHelper(renderer, config->labelFont); auto labelFont = LoadFontHelper(renderer, config->labelFont);
if (labelFont == nullptr) renderer->setFont(Renderer::FontNormal, labelFont == nullptr ? font : labelFont);
{
renderer->setFont(Renderer::FontNormal, font);
}
else
{
labelFont->buildTexture();
renderer->setFont(Renderer::FontNormal, labelFont);
}
} }
renderer->setFont(Renderer::FontLarge, titleFont); renderer->setFont(Renderer::FontLarge, titleFont);
@ -4286,26 +4274,34 @@ CelestiaCore::TextDisplayHandler* CelestiaCore::getTextDisplayHandler() const
return textDisplayHandler; return textDisplayHandler;
} }
void CelestiaCore::setFont(const fs::path& fontPath, int collectionIndex, int fontSize) bool CelestiaCore::setFont(const fs::path& fontPath, int collectionIndex, int fontSize)
{ {
font = LoadTextureFont(renderer, fontPath, collectionIndex, fontSize); if (auto f = LoadTextureFont(renderer, fontPath, collectionIndex, fontSize); f != nullptr)
if (font != nullptr) {
font->buildTexture(); font = f;
return true;
}
return false;
} }
void CelestiaCore::setTitleFont(const fs::path& fontPath, int collectionIndex, int fontSize) bool CelestiaCore::setTitleFont(const fs::path& fontPath, int collectionIndex, int fontSize)
{ {
titleFont = LoadTextureFont(renderer, fontPath, collectionIndex, fontSize); if (auto f = LoadTextureFont(renderer, fontPath, collectionIndex, fontSize); f != nullptr)
if (titleFont != nullptr) {
titleFont->buildTexture(); titleFont = f;
return true;
}
return false;
} }
void CelestiaCore::setRendererFont(const fs::path& fontPath, int collectionIndex, int fontSize, Renderer::FontStyle fontStyle) bool CelestiaCore::setRendererFont(const fs::path& fontPath, int collectionIndex, int fontSize, Renderer::FontStyle fontStyle)
{ {
auto f = LoadTextureFont(renderer, fontPath, collectionIndex, fontSize); if (auto f = LoadTextureFont(renderer, fontPath, collectionIndex, fontSize); f != nullptr)
if (f != nullptr) {
f->buildTexture(); renderer->setFont(fontStyle, f);
renderer->setFont(fontStyle, f); return true;
}
return false;
} }
void CelestiaCore::clearFonts() void CelestiaCore::clearFonts()

View File

@ -368,9 +368,9 @@ class CelestiaCore // : public Watchable<CelestiaCore>
void setTextDisplayHandler(TextDisplayHandler*); void setTextDisplayHandler(TextDisplayHandler*);
TextDisplayHandler* getTextDisplayHandler() const; TextDisplayHandler* getTextDisplayHandler() const;
void setFont(const fs::path& fontPath, int collectionIndex, int fontSize); bool setFont(const fs::path& fontPath, int collectionIndex, int fontSize);
void setTitleFont(const fs::path& fontPath, int collectionIndex, int fontSize); bool setTitleFont(const fs::path& fontPath, int collectionIndex, int fontSize);
void setRendererFont(const fs::path& fontPath, int collectionIndex, int fontSize, Renderer::FontStyle fontStyle); bool setRendererFont(const fs::path& fontPath, int collectionIndex, int fontSize, Renderer::FontStyle fontStyle);
void clearFonts(); void clearFonts();
void toggleReferenceMark(const std::string& refMark, Selection sel = Selection()); void toggleReferenceMark(const std::string& refMark, Selection sel = Selection());

View File

@ -943,6 +943,11 @@ void actionRenderSpacecrafts(GtkToggleAction* action, AppData* app)
} }
void actionRenderPlanetRings(GtkToggleAction* action, AppData* app)
{
setRenderFlag(app, Renderer::ShowPlanetRings, gtk_toggle_action_get_active(action));
}
void actionRenderRingShadows(GtkToggleAction* action, AppData* app) void actionRenderRingShadows(GtkToggleAction* action, AppData* app)
{ {
setRenderFlag(app, Renderer::ShowRingShadows, gtk_toggle_action_get_active(action)); setRenderFlag(app, Renderer::ShowRingShadows, gtk_toggle_action_get_active(action));
@ -1270,9 +1275,9 @@ void resyncRenderActions(AppData* app)
/* Unlike the other interfaces, which go through each menu item and set /* Unlike the other interfaces, which go through each menu item and set
* the corresponding renderFlag, we go the other way and set the menu * the corresponding renderFlag, we go the other way and set the menu
* based on the renderFlag. Last one is ShowFadingOrbits. */ * based on the renderFlag. Last one is ShowPlanetRings. */
for (uint64_t i = Renderer::ShowStars; i <= Renderer::ShowFadingOrbits; i *= 2) for (uint64_t i = Renderer::ShowStars; i <= Renderer::ShowPlanetRings; i *= 2)
{ {
switch (i) switch (i)
{ {
@ -1294,6 +1299,7 @@ void resyncRenderActions(AppData* app)
case Renderer::ShowAtmospheres: actionName = "RenderAtmospheres"; break; case Renderer::ShowAtmospheres: actionName = "RenderAtmospheres"; break;
case Renderer::ShowSmoothLines: actionName = "RenderAA"; break; case Renderer::ShowSmoothLines: actionName = "RenderAA"; break;
case Renderer::ShowEclipseShadows: actionName = "RenderEclipseShadows"; break; case Renderer::ShowEclipseShadows: actionName = "RenderEclipseShadows"; break;
case Renderer::ShowPlanetRings: actionName = "RenderPlanetRings"; break;
case Renderer::ShowRingShadows: actionName = "RenderRingShadows"; break; case Renderer::ShowRingShadows: actionName = "RenderRingShadows"; break;
case Renderer::ShowBoundaries: actionName = "RenderConstellationBoundaries"; break; case Renderer::ShowBoundaries: actionName = "RenderConstellationBoundaries"; break;
case Renderer::ShowAutoMag: actionName = "RenderAutoMagnitude"; break; case Renderer::ShowAutoMag: actionName = "RenderAutoMagnitude"; break;
@ -1317,7 +1323,7 @@ void resyncRenderActions(AppData* app)
action = gtk_action_group_get_action(app->agRender, actionName); action = gtk_action_group_get_action(app->agRender, actionName);
/* The current i anded with the renderFlags gives state of flag */ /* The current i anded with the renderFlags gives state of flag */
gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), (i & rf)); gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), (i & rf) != 0);
} }
} }
} }

View File

@ -96,6 +96,7 @@ void actionRenderMinorMoons(GtkToggleAction*, AppData*);
void actionRenderAsteroids(GtkToggleAction*, AppData*); void actionRenderAsteroids(GtkToggleAction*, AppData*);
void actionRenderComets(GtkToggleAction*, AppData*); void actionRenderComets(GtkToggleAction*, AppData*);
void actionRenderSpacecrafts(GtkToggleAction*, AppData*); void actionRenderSpacecrafts(GtkToggleAction*, AppData*);
void actionRenderPlanetRings(GtkToggleAction*, AppData*);
void actionRenderRingShadows(GtkToggleAction*, AppData*); void actionRenderRingShadows(GtkToggleAction*, AppData*);
void actionRenderStars(GtkToggleAction*, AppData*); void actionRenderStars(GtkToggleAction*, AppData*);

View File

@ -58,6 +58,7 @@
<menuitem action='RenderAsteroids'/> <menuitem action='RenderAsteroids'/>
<menuitem action='RenderComets'/> <menuitem action='RenderComets'/>
<menuitem action='RenderSpacecrafts'/> <menuitem action='RenderSpacecrafts'/>
<menuitem action='RenderPlanetRings'/>
<menuitem action='RenderRingShadows'/> <menuitem action='RenderRingShadows'/>
<menuitem action='RenderStars'/> <menuitem action='RenderStars'/>
</menu> </menu>

View File

@ -149,9 +149,15 @@ static void addPlanetarySystemToTree(const PlanetarySystem* sys, GtkTreeStore* s
case Body::Planet: case Body::Planet:
type = "Planet"; type = "Planet";
break; break;
case Body::DwarfPlanet:
type = "Dwarf Planet";
break;
case Body::Moon: case Body::Moon:
type = "Moon"; type = "Moon";
break; break;
case Body::MinorMoon:
type = "Minor Moon";
break;
case Body::Asteroid: case Body::Asteroid:
type = "Asteroid"; type = "Asteroid";
break; break;

View File

@ -155,6 +155,7 @@ void applySettingsFileMain(AppData* app, GKeyFile* file)
getFlag64(file, &rf, Renderer::ShowAtmospheres, "RenderFlags", "atmospheres", &errors); getFlag64(file, &rf, Renderer::ShowAtmospheres, "RenderFlags", "atmospheres", &errors);
getFlag64(file, &rf, Renderer::ShowSmoothLines, "RenderFlags", "smoothLines", &errors); getFlag64(file, &rf, Renderer::ShowSmoothLines, "RenderFlags", "smoothLines", &errors);
getFlag64(file, &rf, Renderer::ShowEclipseShadows, "RenderFlags", "eclipseShadows", &errors); getFlag64(file, &rf, Renderer::ShowEclipseShadows, "RenderFlags", "eclipseShadows", &errors);
getFlag64(file, &rf, Renderer::ShowPlanetRings, "RenderFlags", "planetRings", &errors);
getFlag64(file, &rf, Renderer::ShowRingShadows, "RenderFlags", "ringShadows", &errors); getFlag64(file, &rf, Renderer::ShowRingShadows, "RenderFlags", "ringShadows", &errors);
getFlag64(file, &rf, Renderer::ShowBoundaries, "RenderFlags", "boundaries", &errors); getFlag64(file, &rf, Renderer::ShowBoundaries, "RenderFlags", "boundaries", &errors);
getFlag64(file, &rf, Renderer::ShowAutoMag, "RenderFlags", "autoMag", &errors); getFlag64(file, &rf, Renderer::ShowAutoMag, "RenderFlags", "autoMag", &errors);
@ -267,6 +268,7 @@ void saveSettingsFile(AppData* app)
g_key_file_set_boolean(file, "RenderFlags", "atmospheres", (rf & Renderer::ShowAtmospheres) != 0); g_key_file_set_boolean(file, "RenderFlags", "atmospheres", (rf & Renderer::ShowAtmospheres) != 0);
g_key_file_set_boolean(file, "RenderFlags", "smoothLines", (rf & Renderer::ShowSmoothLines) != 0); g_key_file_set_boolean(file, "RenderFlags", "smoothLines", (rf & Renderer::ShowSmoothLines) != 0);
g_key_file_set_boolean(file, "RenderFlags", "eclipseShadows", (rf & Renderer::ShowEclipseShadows) != 0); g_key_file_set_boolean(file, "RenderFlags", "eclipseShadows", (rf & Renderer::ShowEclipseShadows) != 0);
g_key_file_set_boolean(file, "RenderFlags", "planetRings", (rf & Renderer::ShowPlanetRings) != 0);
g_key_file_set_boolean(file, "RenderFlags", "ringShadows", (rf & Renderer::ShowRingShadows) != 0); g_key_file_set_boolean(file, "RenderFlags", "ringShadows", (rf & Renderer::ShowRingShadows) != 0);
g_key_file_set_boolean(file, "RenderFlags", "boundaries", (rf & Renderer::ShowBoundaries) != 0); g_key_file_set_boolean(file, "RenderFlags", "boundaries", (rf & Renderer::ShowBoundaries) != 0);
g_key_file_set_boolean(file, "RenderFlags", "autoMag", (rf & Renderer::ShowAutoMag) != 0); g_key_file_set_boolean(file, "RenderFlags", "autoMag", (rf & Renderer::ShowAutoMag) != 0);

View File

@ -155,6 +155,7 @@ static const GtkToggleActionEntry actionsRenderFlags[] = {
{ "RenderComets", NULL, "Comets", NULL, NULL, G_CALLBACK(actionRenderComets), FALSE }, { "RenderComets", NULL, "Comets", NULL, NULL, G_CALLBACK(actionRenderComets), FALSE },
{ "RenderAsteroids", NULL, "Asteroids", NULL, NULL, G_CALLBACK(actionRenderAsteroids), FALSE }, { "RenderAsteroids", NULL, "Asteroids", NULL, NULL, G_CALLBACK(actionRenderAsteroids), FALSE },
{ "RenderSpacecrafts", NULL, "Spacecraft", NULL, NULL, G_CALLBACK(actionRenderSpacecrafts), FALSE }, { "RenderSpacecrafts", NULL, "Spacecraft", NULL, NULL, G_CALLBACK(actionRenderSpacecrafts), FALSE },
{ "RenderPlanetRings", NULL, "Planet Rings", NULL, NULL, G_CALLBACK(actionRenderPlanetRings), FALSE },
{ "RenderRingShadows", NULL, "Ring Shadows", NULL, NULL, G_CALLBACK(actionRenderRingShadows), FALSE }, { "RenderRingShadows", NULL, "Ring Shadows", NULL, NULL, G_CALLBACK(actionRenderRingShadows), FALSE },
{ "RenderStars", NULL, "Stars", NULL, NULL, G_CALLBACK(actionRenderStars), FALSE }, { "RenderStars", NULL, "Stars", NULL, NULL, G_CALLBACK(actionRenderStars), FALSE },
}; };

View File

@ -10,7 +10,11 @@ if(APPLE AND EXISTS /usr/local/opt/qt5)
list(APPEND CMAKE_PREFIX_PATH "/usr/local/opt/qt5") list(APPEND CMAKE_PREFIX_PATH "/usr/local/opt/qt5")
endif() endif()
find_package(Qt5 COMPONENTS Widgets OpenGL CONFIG REQUIRED) if(USE_QT6)
find_package(Qt6 COMPONENTS Widgets OpenGLWidgets Core5Compat CONFIG REQUIRED)
else()
find_package(Qt5 COMPONENTS Widgets CONFIG REQUIRED)
endif()
set(QT_SOURCES set(QT_SOURCES
qtappwin.cpp qtappwin.cpp
@ -58,7 +62,11 @@ set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOUIC ON)
# Find includes in corresponding build directories # Find includes in corresponding build directories
set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_INCLUDE_CURRENT_DIR ON)
qt5_add_resources(RC_SRC "icons.qrc") if(USE_QT6)
qt6_add_resources(RC_SRC "icons.qrc")
else()
qt5_add_resources(RC_SRC "icons.qrc")
endif()
if(WIN32) if(WIN32)
set (RES celestia.rc) set (RES celestia.rc)
@ -66,7 +74,11 @@ endif()
add_executable(celestia-qt WIN32 ${QT_SOURCES} ${RC_SRC} ${RES}) add_executable(celestia-qt WIN32 ${QT_SOURCES} ${RC_SRC} ${RES})
add_dependencies(celestia-qt celestia) add_dependencies(celestia-qt celestia)
target_link_libraries(celestia-qt Qt5::Widgets Qt5::OpenGL celestia) if(USE_QT6)
target_link_libraries(celestia-qt Qt6::Widgets Qt6::OpenGLWidgets Qt6::Core5Compat celestia)
else()
target_link_libraries(celestia-qt Qt5::Widgets celestia)
endif()
if(APPLE) if(APPLE)
set_property(TARGET celestia-qt APPEND_STRING PROPERTY LINK_FLAGS " -framework CoreFoundation") set_property(TARGET celestia-qt APPEND_STRING PROPERTY LINK_FLAGS " -framework CoreFoundation")
set_property(TARGET celestia-qt APPEND_STRING PROPERTY LINK_FLAGS " -framework CoreServices") set_property(TARGET celestia-qt APPEND_STRING PROPERTY LINK_FLAGS " -framework CoreServices")

View File

@ -271,12 +271,11 @@ void CelestiaAppWindow::init(const QString& qConfigFileName,
// Enable antialiasing if requested in the config file. // Enable antialiasing if requested in the config file.
// TODO: Make this settable via the GUI // TODO: Make this settable via the GUI
QGLFormat glformat = QGLFormat::defaultFormat(); QSurfaceFormat glformat = QSurfaceFormat::defaultFormat();
if (m_appCore->getConfig()->aaSamples > 1) if (m_appCore->getConfig()->aaSamples > 1)
{ {
glformat.setSampleBuffers(true);
glformat.setSamples(m_appCore->getConfig()->aaSamples); glformat.setSamples(m_appCore->getConfig()->aaSamples);
QGLFormat::setDefaultFormat(glformat); QSurfaceFormat::setDefaultFormat(glformat);
} }
glWidget = new CelestiaGlWidget(nullptr, "Celestia", m_appCore); glWidget = new CelestiaGlWidget(nullptr, "Celestia", m_appCore);
@ -495,6 +494,7 @@ void CelestiaAppWindow::writeSettings()
QSettings settings; QSettings settings;
settings.beginGroup("MainWindow"); settings.beginGroup("MainWindow");
#ifndef _WIN32
if (isFullScreen()) if (isFullScreen())
{ {
// Save the normal size, not the fullscreen size; fullscreen will // Save the normal size, not the fullscreen size; fullscreen will
@ -503,6 +503,7 @@ void CelestiaAppWindow::writeSettings()
settings.setValue("Pos", normalGeometry().topLeft()); settings.setValue("Pos", normalGeometry().topLeft());
} }
else else
#endif
{ {
settings.setValue("Size", size()); settings.setValue("Size", size());
settings.setValue("Pos", pos()); settings.setValue("Pos", pos());
@ -591,7 +592,7 @@ void CelestiaAppWindow::saveBookmarks()
void CelestiaAppWindow::celestia_tick() void CelestiaAppWindow::celestia_tick()
{ {
m_appCore->tick(); m_appCore->tick();
glWidget->updateGL(); glWidget->update();
} }
@ -621,8 +622,8 @@ void CelestiaAppWindow::slotGrabImage()
if (!saveAsName.isEmpty()) if (!saveAsName.isEmpty())
{ {
m_appCore->saveScreenShot(saveAsName.toStdString()); QImage grabbedImage = glWidget->grabFramebuffer();
settings.setValue("GrabImageDir", QFileInfo(saveAsName).absolutePath()); grabbedImage.save(saveAsName);
} }
settings.endGroup(); settings.endGroup();
} }
@ -750,17 +751,9 @@ static QImage::Format toQFormat(PixelFormat format)
void CelestiaAppWindow::slotCopyImage() void CelestiaAppWindow::slotCopyImage()
{ {
//glWidget->repaint(); QImage grabbedImage = glWidget->grabFramebuffer();
std::array<int, 4> viewport; QApplication::clipboard()->setImage(grabbedImage);
celestia::PixelFormat format; m_appCore->flash(_("Captured screen shot to clipboard"));
m_appCore->getCaptureInfo(viewport, format);
QImage grabbedImage = QImage(viewport[2], viewport[3],
toQFormat(format));
if (m_appCore->captureImage(grabbedImage.bits(), viewport, format))
{
QApplication::clipboard()->setImage(grabbedImage);
m_appCore->flash(_("Captured screen shot to clipboard"));
}
} }
@ -944,7 +937,13 @@ void CelestiaAppWindow::slotShowTimeDialog()
void CelestiaAppWindow::slotToggleFullScreen() void CelestiaAppWindow::slotToggleFullScreen()
{ {
#ifdef _WIN32
// On Windows, we don't actually use showFullscreen(), so use the presence
// of the FramelessWindowHint as an alternative to isFullScreen()
if (windowFlags().testFlag(Qt::FramelessWindowHint))
#else
if (isFullScreen()) if (isFullScreen())
#endif
{ {
switchToNormal(); switchToNormal();
} }
@ -966,7 +965,13 @@ void CelestiaAppWindow::switchToNormal()
{ {
// Switch to window // Switch to window
menuBar()->setFixedHeight(menuBar()->sizeHint().height()); menuBar()->setFixedHeight(menuBar()->sizeHint().height());
#ifdef _WIN32
Qt::WindowFlags flags = windowFlags().setFlag(Qt::FramelessWindowHint, false);
setWindowFlags(flags);
show();
#else
showNormal(); showNormal();
#endif
QSettings settings; QSettings settings;
settings.beginGroup("MainWindow"); settings.beginGroup("MainWindow");
@ -994,7 +999,31 @@ void CelestiaAppWindow::switchToFullscreen()
timeToolBar->setVisible(false); timeToolBar->setVisible(false);
guidesToolBar->setVisible(false); guidesToolBar->setVisible(false);
m_bookmarkToolBar->setVisible(false); m_bookmarkToolBar->setVisible(false);
#ifdef _WIN32
// On Windows, we can't use showFullScreen as this prevents widgets
// (e.g. context menus) being drawn on top of the window. Instead, draw a
// borderless window 1 pixel wider than the screen.
QRect newGeometry = QApplication::primaryScreen()->geometry();
int intersectionArea = 0;
foreach (const QScreen *screen, QGuiApplication::screens())
{
QRect intersection = screen->geometry().intersected(geometry());
int newIntersectionArea = intersection.width() * intersection.height();
if (newIntersectionArea > intersectionArea)
{
newGeometry = screen->geometry();
intersectionArea = newIntersectionArea;
}
}
Qt::WindowFlags flags = windowFlags().setFlag(Qt::FramelessWindowHint, true);
setWindowFlags(flags);
show();
setGeometry(newGeometry.adjusted(-1, -1, 1, 1));
#else
showFullScreen(); showFullScreen();
#endif
} }
@ -1030,7 +1059,7 @@ void CelestiaAppWindow::slotAddBookmark()
appState.captureState(); appState.captureState();
// Capture the current frame buffer to use as a bookmark icon. // Capture the current frame buffer to use as a bookmark icon.
QImage grabbedImage = glWidget->grabFrameBuffer(); QImage grabbedImage = glWidget->grabFramebuffer();
int width = grabbedImage.width(); int width = grabbedImage.width();
int height = grabbedImage.height(); int height = grabbedImage.height();
@ -1593,7 +1622,7 @@ void CelestiaAppWindow::setCustomFPS()
void CelestiaAppWindow::requestContextMenu(float x, float y, Selection sel) void CelestiaAppWindow::requestContextMenu(float x, float y, Selection sel)
{ {
float scale = devicePixelRatioF(); qreal scale = devicePixelRatioF();
SelectionPopup* menu = new SelectionPopup(sel, m_appCore, this); SelectionPopup* menu = new SelectionPopup(sel, m_appCore, this);
connect(menu, SIGNAL(selectionInfoRequested(Selection&)), connect(menu, SIGNAL(selectionInfoRequested(Selection&)),
this, SLOT(slotShowObjectInfo(Selection&))); this, SLOT(slotShowObjectInfo(Selection&)));

View File

@ -60,7 +60,7 @@ const unsigned int DEFAULT_TEXTURE_RESOLUTION = medres;
CelestiaGlWidget::CelestiaGlWidget(QWidget* parent, const char* /* name */, CelestiaCore* core) : CelestiaGlWidget::CelestiaGlWidget(QWidget* parent, const char* /* name */, CelestiaCore* core) :
QGLWidget(parent) QOpenGLWidget(parent)
{ {
setFocusPolicy(Qt::ClickFocus); setFocusPolicy(Qt::ClickFocus);
@ -96,7 +96,7 @@ void CelestiaGlWidget::initializeGL()
using namespace celestia; using namespace celestia;
if (!gl::init(appCore->getConfig()->ignoreGLExtensions) || !gl::checkVersion(gl::GL_2_1)) if (!gl::init(appCore->getConfig()->ignoreGLExtensions) || !gl::checkVersion(gl::GL_2_1))
{ {
QMessageBox::critical(0, "Celestia", _("Celestia was unable to initialize OpenGL 2.1.")); QMessageBox::critical(0, "Celestia", _("Celestia was unable to initialize OpenGL 2.1."));
exit(1); exit(1);
} }
@ -133,15 +133,18 @@ void CelestiaGlWidget::initializeGL()
void CelestiaGlWidget::resizeGL(int w, int h) void CelestiaGlWidget::resizeGL(int w, int h)
{ {
appCore->resize(w, h); qreal scale = devicePixelRatioF();
auto width = static_cast<int>(w * scale);
auto height = static_cast<int>(h * scale);
appCore->resize(width, height);
} }
void CelestiaGlWidget::mouseMoveEvent(QMouseEvent* m) void CelestiaGlWidget::mouseMoveEvent(QMouseEvent* m)
{ {
float scale = devicePixelRatioF(); qreal scale = devicePixelRatioF();
int x = (int)(m->x() * scale); auto x = static_cast<int>(m->x() * scale);
int y = (int)(m->y() * scale); auto y = static_cast<int>(m->y() * scale);
int buttons = 0; int buttons = 0;
if (m->buttons() & LeftButton) if (m->buttons() & LeftButton)
@ -198,9 +201,9 @@ void CelestiaGlWidget::mouseMoveEvent(QMouseEvent* m)
void CelestiaGlWidget::mousePressEvent( QMouseEvent* m ) void CelestiaGlWidget::mousePressEvent( QMouseEvent* m )
{ {
float scale = devicePixelRatioF(); qreal scale = devicePixelRatioF();
int x = (int)(m->x() * scale); auto x = static_cast<int>(m->x() * scale);
int y = (int)(m->y() * scale); auto y = static_cast<int>(m->y() * scale);
if (m->button() == LeftButton) if (m->button() == LeftButton)
appCore->mouseButtonDown(x, y, CelestiaCore::LeftButton); appCore->mouseButtonDown(x, y, CelestiaCore::LeftButton);
@ -213,9 +216,9 @@ void CelestiaGlWidget::mousePressEvent( QMouseEvent* m )
void CelestiaGlWidget::mouseReleaseEvent( QMouseEvent* m ) void CelestiaGlWidget::mouseReleaseEvent( QMouseEvent* m )
{ {
float scale = devicePixelRatioF(); qreal scale = devicePixelRatioF();
int x = (int)(m->x() * scale); auto x = static_cast<int>(m->x() * scale);
int y = (int)(m->y() * scale); auto y = static_cast<int>(m->y() * scale);
if (m->button() == LeftButton) if (m->button() == LeftButton)
{ {

View File

@ -14,7 +14,7 @@
#ifndef QTGLWIDGET_H #ifndef QTGLWIDGET_H
#define QTGLWIDGET_H #define QTGLWIDGET_H
#include <QGLWidget> #include <QOpenGLWidget>
#include "celestia/celestiacore.h" #include "celestia/celestiacore.h"
#include "celengine/simulation.h" #include "celengine/simulation.h"
@ -26,7 +26,7 @@
*@author Christophe Teyssier *@author Christophe Teyssier
*/ */
class CelestiaGlWidget : public QGLWidget, public CelestiaCore::CursorHandler class CelestiaGlWidget : public QOpenGLWidget, public CelestiaCore::CursorHandler
{ {
Q_OBJECT Q_OBJECT

View File

@ -28,7 +28,6 @@
#include <QLibraryInfo> #include <QLibraryInfo>
#include <vector> #include <vector>
#include "qtappwin.h" #include "qtappwin.h"
#include <qtextcodec.h>
#include <fmt/printf.h> #include <fmt/printf.h>
using namespace std; using namespace std;

View File

@ -1,9 +1,20 @@
//#define GL_ES // sdlmain.cpp
//
// Copyright (C) 2020-present, the Celestia Development Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#include <cctype> #include <cctype>
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
#include <memory> #include <memory>
#include <string_view>
#include <system_error>
#include <fmt/printf.h> #include <fmt/printf.h>
#include <celcompat/filesystem.h>
#include <celengine/glsupport.h> #include <celengine/glsupport.h>
#include <celutil/gettext.h> #include <celutil/gettext.h>
#include <celutil/tzutil.h> #include <celutil/tzutil.h>
@ -13,8 +24,8 @@
#else #else
#include <SDL_opengl.h> #include <SDL_opengl.h>
#endif #endif
#include <unistd.h>
#include <celestia/celestiacore.h> #include <celestia/celestiacore.h>
#include <celestia/url.h>
namespace celestia namespace celestia
{ {
@ -36,7 +47,7 @@ class SDL_Application
{ {
public: public:
SDL_Application() = delete; SDL_Application() = delete;
SDL_Application(const std::string name, int w, int h) : SDL_Application(std::string_view name, int w, int h) :
m_appName { name }, m_appName { name },
m_windowWidth { w }, m_windowWidth { w },
m_windowHeight { h } m_windowHeight { h }
@ -44,13 +55,13 @@ class SDL_Application
} }
~SDL_Application(); ~SDL_Application();
static std::shared_ptr<SDL_Application> init(const std::string, int, int); static std::shared_ptr<SDL_Application> init(std::string_view, int, int);
bool createOpenGLWindow(); bool createOpenGLWindow();
bool initCelestiaCore(); bool initCelestiaCore();
void run(); void run();
const char* getError() const; std::string_view getError() const;
private: private:
void display(); void display();
@ -67,6 +78,9 @@ class SDL_Application
// aux functions // aux functions
void toggleFullscreen(); void toggleFullscreen();
void copyURL();
void pasteURL();
void configure() const;
// state variables // state variables
std::string m_appName; std::string m_appName;
@ -84,7 +98,7 @@ class SDL_Application
}; };
std::shared_ptr<SDL_Application> std::shared_ptr<SDL_Application>
SDL_Application::init(const std::string name, int w, int h) SDL_Application::init(std::string_view name, int w, int h)
{ {
if (SDL_Init(SDL_INIT_VIDEO) < 0) if (SDL_Init(SDL_INIT_VIDEO) < 0)
return nullptr; return nullptr;
@ -96,7 +110,7 @@ SDL_Application::init(const std::string name, int w, int h)
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
#endif #endif
return std::shared_ptr<SDL_Application>(new SDL_Application(std::move(name), w, h)); return std::make_shared<SDL_Application>(name, w, h);
} }
SDL_Application::~SDL_Application() SDL_Application::~SDL_Application()
@ -132,7 +146,7 @@ SDL_Application::createOpenGLWindow()
return true; return true;
} }
const char* std::string_view
SDL_Application::getError() const SDL_Application::getError() const
{ {
return SDL_GetError(); return SDL_GetError();
@ -154,11 +168,22 @@ SDL_Application::initCelestiaCore()
return ret; return ret;
} }
void
SDL_Application::configure() const
{
auto *renderer = m_appCore->getRenderer();
const auto *config = m_appCore->getConfig();
renderer->setRenderFlags(Renderer::DefaultRenderFlags);
renderer->setShadowMapSize(config->ShadowMapSize);
renderer->setSolarSystemMaxDistance(config->SolarSystemMaxDistance);
}
void void
SDL_Application::run() SDL_Application::run()
{ {
m_appCore->initRenderer(); m_appCore->initRenderer();
m_appCore->getRenderer()->setRenderFlags(Renderer::DefaultRenderFlags); configure();
m_appCore->start(); m_appCore->start();
std::string tzName; std::string tzName;
@ -294,8 +319,18 @@ SDL_Application::handleKeyPressEvent(const SDL_KeyboardEvent &event)
int k = tolower(key); int k = tolower(key);
if (k >= 'a' && k <= 'z') if (k >= 'a' && k <= 'z')
{ {
key = k + 1 - 'a'; switch (k)
m_appCore->charEntered(key, mod); {
case 'c':
copyURL();
break;
case 'v':
pasteURL();
break;
default:
key = k + 1 - 'a';
m_appCore->charEntered(key, mod);
}
return; return;
} }
mod |= CelestiaCore::ControlKey; mod |= CelestiaCore::ControlKey;
@ -471,6 +506,29 @@ SDL_Application::toggleFullscreen()
m_fullscreen = true; m_fullscreen = true;
} }
} }
void
SDL_Application::copyURL()
{
CelestiaState appState(m_appCore);
appState.captureState();
if (SDL_SetClipboardText(Url(appState).getAsString().c_str()) == 0)
m_appCore->flash(_("Copied URL"));
}
void
SDL_Application::pasteURL()
{
if (SDL_HasClipboardText() != SDL_TRUE)
return;
// on error SDL_GetClipboardText returns a new empty string
char *str = SDL_GetClipboardText(); // don't add const due to SDL_free
if (*str != '\0' && m_appCore->goToUrl(str))
m_appCore->flash(_("Pasting URL"));
SDL_free(str);
} }
void void
@ -484,7 +542,8 @@ FatalError(const std::string &message)
std::cerr << message << std::endl; std::cerr << message << std::endl;
} }
void DumpGLInfo() void
DumpGLInfo()
{ {
const char* s; const char* s;
s = reinterpret_cast<const char*>(glGetString(GL_VERSION)); s = reinterpret_cast<const char*>(glGetString(GL_VERSION));
@ -504,10 +563,8 @@ void DumpGLInfo()
std::cout << s << '\n'; std::cout << s << '\n';
} }
int
using namespace celestia; sdlmain(int /* argc */, char ** /* argv */)
int main(int argc, char **argv)
{ {
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
setlocale(LC_NUMERIC, "C"); setlocale(LC_NUMERIC, "C");
@ -515,10 +572,16 @@ int main(int argc, char **argv)
bind_textdomain_codeset(PACKAGE, "UTF-8"); bind_textdomain_codeset(PACKAGE, "UTF-8");
textdomain(PACKAGE); textdomain(PACKAGE);
if (chdir(CONFIG_DATA_DIR) == -1) const char *dataDir = getenv("CELESTIA_DATA_DIR");
if (dataDir == nullptr)
dataDir = CONFIG_DATA_DIR;
std::error_code ec;
fs::current_path(dataDir, ec);
if (ec)
{ {
FatalError(fmt::sprintf("Cannot chdir to '%s', probably due to improper installation", FatalError(fmt::sprintf("Cannot chdir to '%s', probably due to improper installation",
CONFIG_DATA_DIR)); dataDir));
return 1; return 1;
} }
@ -557,3 +620,10 @@ int main(int argc, char **argv)
return 0; return 0;
} }
} // namespace
int
main(int argc, char **argv)
{
return celestia::sdlmain(argc, argv);
}

View File

@ -39,6 +39,8 @@ set(WIN32_HEADERS
winviewoptsdlg.h winviewoptsdlg.h
) )
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MANIFEST:NO")
add_library(resources OBJECT res/celestia.rc) add_library(resources OBJECT res/celestia.rc)
target_include_directories(resources PRIVATE "${CMAKE_SOURCE_DIR}/src/celestia/win32/res") target_include_directories(resources PRIVATE "${CMAKE_SOURCE_DIR}/src/celestia/win32/res")
set(RESOURCES $<TARGET_OBJECTS:resources>) set(RESOURCES $<TARGET_OBJECTS:resources>)

View File

@ -2,8 +2,10 @@
// //
#include "odmenu.h" #include "odmenu.h"
#include "winuiutils.h"
using namespace std; using namespace std;
using namespace celestia::win32;
ODMenu::ODMenu() ODMenu::ODMenu()
{ {
@ -38,14 +40,6 @@ ODMenu::ODMenu()
if(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncms, 0)) if(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncms, 0))
m_hFont = CreateFontIndirect(&ncms.lfMenuFont); m_hFont = CreateFontIndirect(&ncms.lfMenuFont);
//Set menu metrics
m_iconBarMargin = 3;
m_textLeftMargin = 6;
m_textRightMargin = 3;
m_iconWidth = GetSystemMetrics(SM_CXSMICON);
m_iconHeight = GetSystemMetrics(SM_CYSMICON);
m_verticalSpacing = 6;
//Create GDI objects //Create GDI objects
m_hItemBackground = CreateSolidBrush(m_clrItemBackground); m_hItemBackground = CreateSolidBrush(m_clrItemBackground);
m_hIconBarBrush = CreateSolidBrush(m_clrIconBar); m_hIconBarBrush = CreateSolidBrush(m_clrIconBar);
@ -86,6 +80,16 @@ bool ODMenu::Init(HWND hOwnerWnd, HMENU hMenu)
{ {
m_hRootMenu = hMenu; m_hRootMenu = hMenu;
auto iconDimension = GetSystemMetricsForWindow(SM_CXSMICON, hOwnerWnd);
m_iconWidth = iconDimension;
m_iconHeight = iconDimension;
// Set menu metrics
m_iconBarMargin = DpToPixels(3, hOwnerWnd);
m_textLeftMargin = DpToPixels(6, hOwnerWnd);
m_textRightMargin = DpToPixels(3, hOwnerWnd);
m_verticalSpacing = DpToPixels(6, hOwnerWnd);
//Traverse through all menu items to allocate a map of ODMENUITEM which //Traverse through all menu items to allocate a map of ODMENUITEM which
//will be subsequently used to measure and draw menu items. //will be subsequently used to measure and draw menu items.
@ -227,7 +231,7 @@ void ODMenu::DrawItemText(DRAWITEMSTRUCT* lpdis, ODMENUITEM& item)
&rectText, DT_RIGHT | DT_SINGLELINE | DT_VCENTER); &rectText, DT_RIGHT | DT_SINGLELINE | DT_VCENTER);
} }
void ODMenu::DrawIconBar(DRAWITEMSTRUCT* lpdis, ODMENUITEM& item) void ODMenu::DrawIconBar(HWND hWnd, DRAWITEMSTRUCT* lpdis, ODMENUITEM& item)
{ {
RECT rectBar; RECT rectBar;
memcpy(&rectBar, &lpdis->rcItem, sizeof(RECT)); memcpy(&rectBar, &lpdis->rcItem, sizeof(RECT));
@ -253,27 +257,27 @@ void ODMenu::DrawIconBar(DRAWITEMSTRUCT* lpdis, ODMENUITEM& item)
//Draw icon for menu item if handle is valid //Draw icon for menu item if handle is valid
if(item.hBitmap) if(item.hBitmap)
{ {
x = m_iconBarMargin; x = rectBar.left + m_iconBarMargin + m_iconWidth / 2;
y = rectBar.top + ((rectBar.bottom - rectBar.top - 16) / 2); y = rectBar.top + (rectBar.bottom - rectBar.top) / 2;
if(lpdis->itemState & ODS_DISABLED || lpdis->itemState & ODS_GRAYED) if(lpdis->itemState & ODS_DISABLED || lpdis->itemState & ODS_GRAYED)
{ {
//Draw disabled icon in normal position //Draw disabled icon in normal position
DrawTransparentBitmap(lpdis->hDC, item.hBitmap, x, y, m_clrTranparent, eDisabled); DrawTransparentBitmap(hWnd, lpdis->hDC, item.hBitmap, x, y, m_clrTranparent, eDisabled);
} }
else if(lpdis->itemState & ODS_SELECTED) else if(lpdis->itemState & ODS_SELECTED)
{ {
//Draw icon "raised" //Draw icon "raised"
//Draw shadow right one pixel and down one pixel from normal position //Draw shadow right one pixel and down one pixel from normal position
DrawTransparentBitmap(lpdis->hDC, item.hBitmap, x+1, y+1, m_clrTranparent, eShadow); DrawTransparentBitmap(hWnd, lpdis->hDC, item.hBitmap, x+1, y+1, m_clrTranparent, eShadow);
//Draw normal left one pixel and up one pixel from normal position //Draw normal left one pixel and up one pixel from normal position
DrawTransparentBitmap(lpdis->hDC, item.hBitmap, x-1, y-1, m_clrTranparent); DrawTransparentBitmap(hWnd, lpdis->hDC, item.hBitmap, x-1, y-1, m_clrTranparent);
} }
else else
{ {
//Draw faded icon in normal position //Draw faded icon in normal position
DrawTransparentBitmap(lpdis->hDC, item.hBitmap, x, y, m_clrTranparent, eFaded); DrawTransparentBitmap(hWnd, lpdis->hDC, item.hBitmap, x, y, m_clrTranparent, eFaded);
} }
} }
else if(lpdis->itemState & ODS_CHECKED) else if(lpdis->itemState & ODS_CHECKED)
@ -289,17 +293,17 @@ void ODMenu::DrawIconBar(DRAWITEMSTRUCT* lpdis, ODMENUITEM& item)
hPrevBrush = (HBRUSH)SelectObject(lpdis->hDC, m_hCheckMarkBackgroundBrush); hPrevBrush = (HBRUSH)SelectObject(lpdis->hDC, m_hCheckMarkBackgroundBrush);
hPrevPen = (HPEN)SelectObject(lpdis->hDC, m_hSelectionOutlinePen); hPrevPen = (HPEN)SelectObject(lpdis->hDC, m_hSelectionOutlinePen);
rect.left = m_iconBarMargin; rect.left = m_iconBarMargin;
rect.right = m_iconBarMargin + m_iconWidth; rect.right = rect.left + m_iconWidth;
rect.top = rectBar.top + (rectBar.bottom - rectBar.top - m_iconHeight) / 2; rect.top = rectBar.top + (rectBar.bottom - rectBar.top - m_iconHeight) / 2;
rect.bottom = rect.top + m_iconHeight; rect.bottom = rect.top + m_iconHeight;
Rectangle(lpdis->hDC, rect.left, rect.top, rect.right, rect.bottom); Rectangle(lpdis->hDC, rect.left, rect.top, rect.right, rect.bottom);
SelectObject(lpdis->hDC, hPrevBrush); SelectObject(lpdis->hDC, hPrevBrush);
SelectObject(lpdis->hDC, hPrevPen); SelectObject(lpdis->hDC, hPrevPen);
//Draw check mark // Draw check mark
x = (m_iconWidth + 2*m_iconBarMargin - 6) / 2; x = rectBar.left + m_iconBarMargin + m_iconWidth / 2;
y = rectBar.top + ((rectBar.bottom - rectBar.top - 7) / 2) + 1; y = rectBar.top + (rectBar.bottom - rectBar.top) / 2;
DrawCheckMark(lpdis->hDC, x, y, true); DrawCheckMark(hWnd, lpdis->hDC, x, y, true);
} }
} }
@ -321,8 +325,8 @@ void ODMenu::ComputeMenuTextPos(DRAWITEMSTRUCT* lpdis, ODMENUITEM& item, int& x,
} }
} }
void ODMenu::DrawTransparentBitmap(HDC hDC, HBITMAP hBitmap, short xStart, void ODMenu::DrawTransparentBitmap(HWND hWnd, HDC hDC, HBITMAP hBitmap, short centerX,
short yStart, COLORREF cTransparentColor, short centerY, COLORREF cTransparentColor,
bitmapType eType) bitmapType eType)
{ {
BITMAP bm; BITMAP bm;
@ -333,8 +337,6 @@ void ODMenu::DrawTransparentBitmap(HDC hDC, HBITMAP hBitmap, short xStart,
POINT ptSize; POINT ptSize;
HBRUSH hOldBrush; HBRUSH hOldBrush;
BOOL bRC;
hdcTemp = CreateCompatibleDC(hDC); hdcTemp = CreateCompatibleDC(hDC);
SelectObject(hdcTemp, hBitmap); // Select the bitmap SelectObject(hdcTemp, hBitmap); // Select the bitmap
@ -344,6 +346,9 @@ void ODMenu::DrawTransparentBitmap(HDC hDC, HBITMAP hBitmap, short xStart,
DPtoLP(hdcTemp, &ptSize, 1); // Convert from device DPtoLP(hdcTemp, &ptSize, 1); // Convert from device
// to logical points // to logical points
auto iconWidth = DpToPixels(ptSize.x, hWnd);
auto iconHeight = DpToPixels(ptSize.y, hWnd);
// Create some DCs to hold temporary data. // Create some DCs to hold temporary data.
hdcBack = CreateCompatibleDC(hDC); hdcBack = CreateCompatibleDC(hDC);
hdcObject = CreateCompatibleDC(hDC); hdcObject = CreateCompatibleDC(hDC);
@ -359,7 +364,7 @@ void ODMenu::DrawTransparentBitmap(HDC hDC, HBITMAP hBitmap, short xStart,
// Monochrome DC // Monochrome DC
bmAndObject = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL); bmAndObject = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);
bmAndMem = CreateCompatibleBitmap(hDC, ptSize.x, ptSize.y); bmAndMem = CreateCompatibleBitmap(hDC, iconWidth, iconHeight);
bmSave = CreateCompatibleBitmap(hDC, ptSize.x, ptSize.y); bmSave = CreateCompatibleBitmap(hDC, ptSize.x, ptSize.y);
// Each DC must select a bitmap object to store pixel data. // Each DC must select a bitmap object to store pixel data.
@ -372,7 +377,7 @@ void ODMenu::DrawTransparentBitmap(HDC hDC, HBITMAP hBitmap, short xStart,
SetMapMode(hdcTemp, GetMapMode(hDC)); SetMapMode(hdcTemp, GetMapMode(hDC));
// Save the bitmap sent here, because it will be overwritten. // Save the bitmap sent here, because it will be overwritten.
bRC = BitBlt(hdcSave, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCCOPY); BitBlt(hdcSave, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCCOPY);
// Create an "AND mask" that contains the mask of the colors to draw // Create an "AND mask" that contains the mask of the colors to draw
// (the nontransparent portions of the image). // (the nontransparent portions of the image).
@ -383,21 +388,21 @@ void ODMenu::DrawTransparentBitmap(HDC hDC, HBITMAP hBitmap, short xStart,
// Create the object mask for the bitmap by performing a BitBlt // Create the object mask for the bitmap by performing a BitBlt
// from the source bitmap to a monochrome bitmap. // from the source bitmap to a monochrome bitmap.
bRC = BitBlt(hdcObject, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCCOPY); BitBlt(hdcObject, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCCOPY);
// Set the background color of the source DC back to the original color. // Set the background color of the source DC back to the original color.
SetBkColor(hdcTemp, cColor); SetBkColor(hdcTemp, cColor);
// Create the inverse of the object mask. // Create the inverse of the object mask.
bRC = BitBlt(hdcBack, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, NOTSRCCOPY); BitBlt(hdcBack, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, NOTSRCCOPY);
// Copy the background of the main DC to the destination. // Copy the background of the main DC to the destination.
bRC = BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hDC, xStart, yStart, SRCCOPY); BitBlt(hdcMem, 0, 0, iconWidth, iconHeight, hDC, centerX - iconWidth / 2, centerY - iconHeight / 2, SRCCOPY);
// Mask out the places where the bitmap will be placed. // Mask out the places where the bitmap will be placed.
// hdcMem then contains the background color of hDC only in the places // hdcMem then contains the background color of hDC only in the places
// where the transparent pixels reside. // where the transparent pixels reside.
bRC = BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, SRCAND); StretchBlt(hdcMem, 0, 0, iconWidth, iconHeight, hdcObject, 0, 0, ptSize.x, ptSize.y, SRCAND);
if(eType == eNormal) if(eType == eNormal)
{ {
@ -407,7 +412,7 @@ void ODMenu::DrawTransparentBitmap(HDC hDC, HBITMAP hBitmap, short xStart,
// XOR the bitmap with the background on the destination DC. // XOR the bitmap with the background on the destination DC.
// hdcMem then contains the required result. // hdcMem then contains the required result.
BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCPAINT); StretchBlt(hdcMem, 0, 0, iconWidth, iconHeight, hdcTemp, 0, 0, ptSize.x, ptSize.y, SRCPAINT);
} }
else if(eType == eShadow) else if(eType == eShadow)
{ {
@ -415,11 +420,11 @@ void ODMenu::DrawTransparentBitmap(HDC hDC, HBITMAP hBitmap, short xStart,
hOldBrush = (HBRUSH)SelectObject(hdcTemp, m_hIconShadowBrush); hOldBrush = (HBRUSH)SelectObject(hdcTemp, m_hIconShadowBrush);
//Copy shadow brush pixels for all non-transparent pixels to hdcTemp //Copy shadow brush pixels for all non-transparent pixels to hdcTemp
bRC = BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcBack, 0, 0, MERGECOPY); BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcBack, 0, 0, MERGECOPY);
// XOR the bitmap with the background on the destination DC. // XOR the bitmap with the background on the destination DC.
// hdcMem then contains the required result. // hdcMem then contains the required result.
bRC = BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCPAINT); StretchBlt(hdcMem, 0, 0, iconWidth, iconHeight, hdcTemp, 0, 0, ptSize.x, ptSize.y, SRCPAINT);
//Restore the brush in hdcTemp //Restore the brush in hdcTemp
SelectObject(hdcTemp, hOldBrush); SelectObject(hdcTemp, hOldBrush);
@ -446,7 +451,7 @@ void ODMenu::DrawTransparentBitmap(HDC hDC, HBITMAP hBitmap, short xStart,
// XOR the bitmap with the background on the destination DC. // XOR the bitmap with the background on the destination DC.
// hdcMem then contains the required result. // hdcMem then contains the required result.
BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCPAINT); StretchBlt(hdcMem, 0, 0, iconWidth, iconHeight, hdcTemp, 0, 0, ptSize.x, ptSize.y, SRCPAINT);
} }
else if(eType == eDisabled) else if(eType == eDisabled)
{ {
@ -479,14 +484,14 @@ void ODMenu::DrawTransparentBitmap(HDC hDC, HBITMAP hBitmap, short xStart,
// XOR the bitmap with the background on the destination DC. // XOR the bitmap with the background on the destination DC.
// hdcMem then contains the required result. // hdcMem then contains the required result.
BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCPAINT); StretchBlt(hdcMem, 0, 0, iconWidth, iconHeight, hdcTemp, 0, 0, ptSize.x, ptSize.y, SRCPAINT);
} }
// Copy the destination to the screen. // Copy the destination to the screen.
bRC = BitBlt(hDC, xStart, yStart, ptSize.x, ptSize.y, hdcMem, 0, 0, SRCCOPY); BitBlt(hDC, centerX - iconWidth / 2, centerY - iconHeight / 2, iconWidth, iconHeight, hdcMem, 0, 0, SRCCOPY);
// Place the original bitmap back into the bitmap sent here. // Place the original bitmap back into the bitmap sent here.
bRC = BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcSave, 0, 0, SRCCOPY); BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcSave, 0, 0, SRCCOPY);
// Delete the memory bitmaps. // Delete the memory bitmaps.
DeleteObject(SelectObject(hdcBack, bmBackOld)); DeleteObject(SelectObject(hdcBack, bmBackOld));
@ -502,7 +507,7 @@ void ODMenu::DrawTransparentBitmap(HDC hDC, HBITMAP hBitmap, short xStart,
DeleteDC(hdcTemp); DeleteDC(hdcTemp);
} }
void ODMenu::DrawCheckMark(HDC hDC, short x, short y, bool bNarrow) void ODMenu::DrawCheckMark(HWND hWnd, HDC hDC, short centerX, short centerY, bool bNarrow)
{ {
HPEN hOldPen; HPEN hOldPen;
int dp = 0; int dp = 0;
@ -510,30 +515,26 @@ void ODMenu::DrawCheckMark(HDC hDC, short x, short y, bool bNarrow)
if(bNarrow) if(bNarrow)
dp = 1; dp = 1;
//Select check mark pen // Select check mark pen
hOldPen = (HPEN)SelectObject(hDC, m_hCheckMarkPen); hOldPen = (HPEN)SelectObject(hDC, m_hCheckMarkPen);
//Draw the check mark // Draw the check mark
MoveToEx(hDC, x, y + 2, NULL); auto minLeftX = centerX - DpToPixels(4, hWnd);
LineTo(hDC, x, y + 5 - dp); auto maxLeftX = centerX - DpToPixels(1, hWnd);
auto x = minLeftX;
auto y = centerY - DpToPixels(2, hWnd);
for (; x < maxLeftX; x += 1, y += 1)
{
MoveToEx(hDC, x, y, NULL);
LineTo(hDC, x, y + DpToPixels(3 - dp, hWnd));
}
MoveToEx(hDC, x + 1, y + 3, NULL); auto maxRightX = centerX + DpToPixels(4, hWnd);
LineTo(hDC, x + 1, y + 6 - dp); for (; x < maxRightX; x += 1, y -= 1)
{
MoveToEx(hDC, x + 2, y + 4, NULL); MoveToEx(hDC, x, y, NULL);
LineTo(hDC, x + 2, y + 7 - dp); LineTo(hDC, x, y + DpToPixels(3 - dp, hWnd));
}
MoveToEx(hDC, x + 3, y + 3, NULL);
LineTo(hDC, x + 3, y + 6 - dp);
MoveToEx(hDC, x + 4, y + 2, NULL);
LineTo(hDC, x + 4, y + 5 - dp);
MoveToEx(hDC, x + 5, y + 1, NULL);
LineTo(hDC, x + 5, y + 4 - dp);
MoveToEx(hDC, x + 6, y, NULL);
LineTo(hDC, x + 6, y + 3 - dp);
//Restore original DC pen //Restore original DC pen
SelectObject(hDC, hOldPen); SelectObject(hDC, hOldPen);
@ -622,6 +623,7 @@ void ODMenu::MeasureItem(HWND hWnd, LPARAM lParam)
DrawText(hDC, item.rawText.c_str(), item.rawText.length(), &rect, DrawText(hDC, item.rawText.c_str(), item.rawText.length(), &rect,
DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT); DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT);
lpmis->itemWidth = rect.right - rect.left; lpmis->itemWidth = rect.right - rect.left;
lpmis->itemHeight = m_iconHeight;
if(!item.topMost) if(!item.topMost)
{ {
@ -727,7 +729,7 @@ void ODMenu::DrawItem(HWND hWnd, LPARAM lParam)
} }
//Draw the left icon bar //Draw the left icon bar
DrawIconBar(lpdis, item); DrawIconBar(hWnd, lpdis, item);
//Draw selection outline if drawing a selected item //Draw selection outline if drawing a selected item
if(lpdis->itemState & ODS_SELECTED && !(lpdis->itemState & ODS_GRAYED || lpdis->itemState & ODS_DISABLED)) if(lpdis->itemState & ODS_SELECTED && !(lpdis->itemState & ODS_GRAYED || lpdis->itemState & ODS_DISABLED))

View File

@ -68,11 +68,11 @@ class ODMenu
void SetMenuItemOwnerDrawn(HMENU hMenu, UINT item, UINT type); void SetMenuItemOwnerDrawn(HMENU hMenu, UINT item, UINT type);
void GenerateDisplayText(ODMENUITEM& item); void GenerateDisplayText(ODMENUITEM& item);
void DrawItemText(DRAWITEMSTRUCT* lpdis, ODMENUITEM& item); void DrawItemText(DRAWITEMSTRUCT* lpdis, ODMENUITEM& item);
void DrawIconBar(DRAWITEMSTRUCT* lpdis, ODMENUITEM& item); void DrawIconBar(HWND hWnd, DRAWITEMSTRUCT* lpdis, ODMENUITEM& item);
void ComputeMenuTextPos(DRAWITEMSTRUCT* lpdis, ODMENUITEM& item, int& x, int& y, SIZE& size); void ComputeMenuTextPos(DRAWITEMSTRUCT* lpdis, ODMENUITEM& item, int& x, int& y, SIZE& size);
void DrawTransparentBitmap(HDC hDC, HBITMAP hBitmap, short xStart, short yStart, void DrawTransparentBitmap(HWND hWnd, HDC hDC, HBITMAP hBitmap, short centerX, short centerY,
COLORREF cTransparentColor, bitmapType eType=eNormal); COLORREF cTransparentColor, bitmapType eType=eNormal);
void DrawCheckMark(HDC hDC, short x, short y, bool bNarrow=true); void DrawCheckMark(HWND hWnd, HDC hDC, short centerX, short centerY, bool bNarrow=true);
COLORREF LightenColor(COLORREF col, double factor); COLORREF LightenColor(COLORREF col, double factor);
COLORREF DarkenColor(COLORREF col, double factor); COLORREF DarkenColor(COLORREF col, double factor);
COLORREF AverageColor(COLORREF col1, COLORREF col2, double weight1=0.5); COLORREF AverageColor(COLORREF col1, COLORREF col2, double weight1=0.5);

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<assemblyIdentity <assemblyIdentity
version="1.0.0.0" version="1.0.0.0"
processorArchitecture="X86" processorArchitecture="*"
name="Celestia" name="Celestia"
type="win32" type="win32"
/> />
@ -19,4 +19,10 @@
/> />
</dependentAssembly> </dependentAssembly>
</dependency> </dependency>
</assembly> <asmv3:application>
<asmv3:windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>

View File

@ -16,6 +16,8 @@
#define NC_(c, s) s #define NC_(c, s) s
#endif #endif
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "celestia.exe.manifest"
// //
// Bitmap resources // Bitmap resources
// //

View File

@ -29,11 +29,10 @@
using namespace Eigen; using namespace Eigen;
using namespace std; using namespace std;
using namespace celmath; using namespace celmath;
using namespace celestia::win32;
static vector<Eclipse> eclipseList; static vector<Eclipse> eclipseList;
extern void SetMouseCursor(LPCTSTR lpCursor);
const char* MonthNames[12] = const char* MonthNames[12] =
{ {
"Jan", "Feb", "Mar", "Apr", "Jan", "Feb", "Mar", "Apr",
@ -63,15 +62,15 @@ bool InitEclipseFinderColumns(HWND listView)
string header4 = UTF8ToCurrentCP(_("Duration")); string header4 = UTF8ToCurrentCP(_("Duration"));
columns[0].pszText = const_cast<char*>(header0.c_str()); columns[0].pszText = const_cast<char*>(header0.c_str());
columns[0].cx = 65; columns[0].cx = DpToPixels(65, listView);
columns[1].pszText = const_cast<char*>(header1.c_str()); columns[1].pszText = const_cast<char*>(header1.c_str());
columns[1].cx = 65; columns[1].cx = DpToPixels(65, listView);
columns[2].pszText = const_cast<char*>(header2.c_str()); columns[2].pszText = const_cast<char*>(header2.c_str());
columns[2].cx = 80; columns[2].cx = DpToPixels(80, listView);
columns[3].pszText = const_cast<char*>(header3.c_str()); columns[3].pszText = const_cast<char*>(header3.c_str());
columns[3].cx = 55; columns[3].cx = DpToPixels(55, listView);
columns[4].pszText = const_cast<char*>(header4.c_str()); columns[4].pszText = const_cast<char*>(header4.c_str());
columns[4].cx = 135; columns[4].cx = DpToPixels(135, listView);
for (i = 0; i < nColumns; i++) for (i = 0; i < nColumns; i++)
{ {

View File

@ -68,6 +68,7 @@
using namespace celestia; using namespace celestia;
using namespace celestia::util; using namespace celestia::util;
using namespace std; using namespace std;
using namespace celestia::win32;
typedef pair<int,string> IntStrPair; typedef pair<int,string> IntStrPair;
typedef vector<IntStrPair> IntStrPairVec; typedef vector<IntStrPair> IntStrPairVec;
@ -988,7 +989,7 @@ BOOL APIENTRY AddBookmarkProc(HWND hDlg,
if (strstr(text, ">>")) if (strstr(text, ">>"))
{ {
//Increase size of dialog //Increase size of dialog
int height = treeRect.bottom - dlgRect.top + 12; int height = treeRect.bottom - dlgRect.top + DpToPixels(12, hDlg);
SetWindowPos(hDlg, HWND_TOP, 0, 0, width, height, SetWindowPos(hDlg, HWND_TOP, 0, 0, width, height,
SWP_NOMOVE | SWP_NOZORDER); SWP_NOMOVE | SWP_NOZORDER);
//Change text in button //Change text in button
@ -3186,8 +3187,8 @@ int APIENTRY WinMain(HINSTANCE hInstance,
LoadPreferencesFromRegistry(CelestiaRegKey, prefs); LoadPreferencesFromRegistry(CelestiaRegKey, prefs);
// Adjust window dimensions for screen dimensions // Adjust window dimensions for screen dimensions
int screenWidth = GetSystemMetrics(SM_CXSCREEN); int screenWidth = GetSystemMetricsForWindow(SM_CXSCREEN, nullptr);
int screenHeight = GetSystemMetrics(SM_CYSCREEN); int screenHeight = GetSystemMetricsForWindow(SM_CYSCREEN, nullptr);
if (prefs.winWidth > screenWidth) if (prefs.winWidth > screenWidth)
prefs.winWidth = screenWidth; prefs.winWidth = screenWidth;
if (prefs.winHeight > screenHeight) if (prefs.winHeight > screenHeight)
@ -3386,6 +3387,8 @@ int APIENTRY WinMain(HINSTANCE hInstance,
extern void RegisterDatePicker(); extern void RegisterDatePicker();
RegisterDatePicker(); RegisterDatePicker();
appCore->setScreenDpi(GetDPIForWindow(hWnd));
if (!appCore->initRenderer()) if (!appCore->initRenderer())
{ {
return 1; return 1;

View File

@ -10,6 +10,7 @@
// of the License, or (at your option) any later version. // of the License, or (at your option) any later version.
#include "winsplash.h" #include "winsplash.h"
#include "winuiutils.h"
#include <celutil/gettext.h> #include <celutil/gettext.h>
#include <celutil/winutil.h> #include <celutil/winutil.h>
#include <string> #include <string>
@ -20,6 +21,7 @@
using namespace std; using namespace std;
using namespace celestia::win32;
// Required for transparent Windows, but not present in VC6 headers. Only present // Required for transparent Windows, but not present in VC6 headers. Only present
@ -61,7 +63,9 @@ SplashWindow::SplashWindow(const string& _imageFileName) :
hCompositionBitmap(0), hCompositionBitmap(0),
useLayeredWindow(false), useLayeredWindow(false),
winWidth(640), winWidth(640),
winHeight(480) winHeight(480),
imageWidth(0),
imageHeight(0)
{ {
init(); init();
} }
@ -108,7 +112,7 @@ SplashWindow::paint(HDC hDC)
HDC hMemDC = ::CreateCompatibleDC(hDC); HDC hMemDC = ::CreateCompatibleDC(hDC);
HBITMAP hOldBitmap = (HBITMAP) ::SelectObject(hMemDC, hBitmap); HBITMAP hOldBitmap = (HBITMAP) ::SelectObject(hMemDC, hBitmap);
BitBlt(hDC, 0, 0, winWidth, winHeight, hMemDC, 0, 0, SRCCOPY); StretchBlt(hDC, 0, 0, winWidth, winHeight, hMemDC, 0, 0, imageWidth, imageHeight, SRCCOPY);
::SelectObject(hMemDC, hOldBitmap); ::SelectObject(hMemDC, hOldBitmap);
::DeleteDC(hMemDC); ::DeleteDC(hMemDC);
@ -126,10 +130,10 @@ SplashWindow::paint(HDC hDC)
// Show the message text // Show the message text
RECT r; RECT r;
r.left = rect.right - 250; r.left = rect.right - DpToPixels(250, hwnd);
r.top = rect.bottom - 70; r.top = rect.bottom - DpToPixels(70, hwnd);
r.right = rect.right; r.right = rect.right;
r.bottom = r.top + 30; r.bottom = r.top + DpToPixels(30, hwnd);
HFONT hFont = reinterpret_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT)); HFONT hFont = reinterpret_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT));
SelectObject(hDC, hFont); SelectObject(hDC, hFont);
@ -212,15 +216,18 @@ SplashWindow::createWindow()
if (!RegisterClassEx(&wndclass)) if (!RegisterClassEx(&wndclass))
return NULL; return NULL;
if (image != NULL) if (image != nullptr)
{ {
winWidth = image->getWidth(); imageWidth = image->getWidth();
winHeight = image->getHeight(); imageHeight = image->getHeight();
winWidth = DpToPixels(imageWidth, nullptr);
winHeight = DpToPixels(imageHeight, nullptr);
} }
// Create the application window centered in the middle of the screen // Create the application window centered in the middle of the screen
DWORD nScrWidth = ::GetSystemMetrics(SM_CXFULLSCREEN); DWORD nScrWidth = GetSystemMetricsForWindow(SM_CXFULLSCREEN, nullptr);
DWORD nScrHeight = ::GetSystemMetrics(SM_CYFULLSCREEN); DWORD nScrHeight = GetSystemMetricsForWindow(SM_CYFULLSCREEN, nullptr);
int x = (nScrWidth - winWidth) / 2; int x = (nScrWidth - winWidth) / 2;
int y = (nScrHeight - winHeight) / 2; int y = (nScrHeight - winHeight) / 2;
@ -304,7 +311,7 @@ SplashWindow::createBitmap()
// layered window support.) // layered window support.)
if (hBitmap) if (hBitmap)
{ {
hCompositionBitmap = CreateCompatibleBitmap(hwndDC, image->getWidth(), image->getHeight()); hCompositionBitmap = CreateCompatibleBitmap(hwndDC, winWidth, winHeight);
} }
} }

View File

@ -43,4 +43,6 @@ private:
std::string message; std::string message;
unsigned int winWidth; unsigned int winWidth;
unsigned int winHeight; unsigned int winHeight;
unsigned int imageWidth;
unsigned int imageHeight;
}; };

View File

@ -21,11 +21,11 @@
#include <celmath/mathlib.h> #include <celmath/mathlib.h>
#include "winstarbrowser.h" #include "winstarbrowser.h"
#include "res/resource.h" #include "res/resource.h"
#include "winuiutils.h"
extern void SetMouseCursor(LPCTSTR lpCursor);
using namespace Eigen; using namespace Eigen;
using namespace std; using namespace std;
using namespace celestia::win32;
static const int MinListStars = 10; static const int MinListStars = 10;
static const int MaxListStars = 500; static const int MaxListStars = 500;
@ -49,7 +49,7 @@ bool InitStarBrowserColumns(HWND listView)
lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvc.fmt = LVCFMT_LEFT; lvc.fmt = LVCFMT_LEFT;
lvc.cx = 60; lvc.cx = DpToPixels(60, listView);
lvc.pszText = const_cast<char*>(""); lvc.pszText = const_cast<char*>("");
int nColumns = sizeof(columns) / sizeof(columns[0]); int nColumns = sizeof(columns) / sizeof(columns[0]);
@ -65,16 +65,16 @@ bool InitStarBrowserColumns(HWND listView)
string header4 = UTF8ToCurrentCP(_("Type")); string header4 = UTF8ToCurrentCP(_("Type"));
columns[0].pszText = const_cast<char*>(header0.c_str()); columns[0].pszText = const_cast<char*>(header0.c_str());
columns[0].cx = 100; columns[0].cx = DpToPixels(100, listView);
columns[1].pszText = const_cast<char*>(header1.c_str()); columns[1].pszText = const_cast<char*>(header1.c_str());
columns[1].fmt = LVCFMT_RIGHT; columns[1].fmt = LVCFMT_RIGHT;
columns[1].cx = 115; columns[1].cx = DpToPixels(115, listView);
columns[2].pszText = const_cast<char*>(header2.c_str()); columns[2].pszText = const_cast<char*>(header2.c_str());
columns[2].fmt = LVCFMT_RIGHT; columns[2].fmt = LVCFMT_RIGHT;
columns[2].cx = 65; columns[2].cx = DpToPixels(65, listView);
columns[3].pszText = const_cast<char*>(header3.c_str()); columns[3].pszText = const_cast<char*>(header3.c_str());
columns[3].fmt = LVCFMT_RIGHT; columns[3].fmt = LVCFMT_RIGHT;
columns[3].cx = 65; columns[3].cx = DpToPixels(65, listView);
columns[4].pszText = const_cast<char*>(header4.c_str()); columns[4].pszText = const_cast<char*>(header4.c_str());
for (i = 0; i < nColumns; i++) for (i = 0; i < nColumns; i++)

View File

@ -12,6 +12,34 @@
#include "winuiutils.h" #include "winuiutils.h"
namespace
{
using GetDpiForWindowFn = UINT STDAPICALLTYPE(HWND hWnd);
using GetDpiForSystemFn = UINT STDAPICALLTYPE();
using GetSystemMetricsForDpiFn = UINT STDAPICALLTYPE(int nIndex, UINT dpi);
GetDpiForWindowFn *pfnGetDpiForWindow = nullptr;
GetDpiForSystemFn *pfnGetDpiForSystem = nullptr;
GetSystemMetricsForDpiFn *pfnGetSystemMetricsForDpi = nullptr;
bool dpiFunctionPointersInitialized = false;
void InitializeDPIFunctionPointersIfNeeded()
{
if (dpiFunctionPointersInitialized)
return;
HMODULE hUser = GetModuleHandle("user32.dll");
if (!hUser)
return;
pfnGetDpiForWindow = reinterpret_cast<GetDpiForWindowFn *>(GetProcAddress(hUser, "GetDpiForWindow"));
pfnGetDpiForSystem = reinterpret_cast<GetDpiForSystemFn *>(GetProcAddress(hUser, "GetDpiForSystem"));
pfnGetSystemMetricsForDpi = reinterpret_cast<GetSystemMetricsForDpiFn *>(GetProcAddress(hUser, "GetSystemMetricsForDpi"));
dpiFunctionPointersInitialized = true;
}
}
namespace celestia::win32
{
void SetMouseCursor(LPCTSTR lpCursor) void SetMouseCursor(LPCTSTR lpCursor)
{ {
HCURSOR hNewCrsr; HCURSOR hNewCrsr;
@ -53,3 +81,44 @@ void AddButtonDefaultStyle(HWND hWnd)
::GetWindowLong(hWnd, GWL_STYLE) | BS_DEFPUSHBUTTON); ::GetWindowLong(hWnd, GWL_STYLE) | BS_DEFPUSHBUTTON);
InvalidateRect(hWnd, nullptr, TRUE); InvalidateRect(hWnd, nullptr, TRUE);
} }
UINT GetBaseDPI()
{
return 96;
}
UINT GetDPIForWindow(HWND hWnd)
{
InitializeDPIFunctionPointersIfNeeded();
if (hWnd && pfnGetDpiForWindow)
return pfnGetDpiForWindow(hWnd);
if (pfnGetDpiForSystem)
return pfnGetDpiForSystem();
HDC hDC = GetDC(hWnd);
if (hDC)
{
auto dpi = GetDeviceCaps(hDC, LOGPIXELSX);
ReleaseDC(hWnd, hDC);
return dpi;
}
return GetBaseDPI();
}
int DpToPixels(int dp, HWND hWnd)
{
return dp * GetDPIForWindow(hWnd) / GetBaseDPI();
}
int GetSystemMetricsForWindow(int index, HWND hWnd)
{
InitializeDPIFunctionPointersIfNeeded();
auto dpi = GetDPIForWindow(hWnd);
if (pfnGetSystemMetricsForDpi)
{
return pfnGetSystemMetricsForDpi(index, dpi);
}
auto systemDpi = GetDPIForWindow(nullptr);
return GetSystemMetrics(index) * dpi / systemDpi;
}
}

View File

@ -15,7 +15,15 @@
#include <windows.h> #include <windows.h>
#include <commctrl.h> #include <commctrl.h>
namespace celestia::win32
{
void SetMouseCursor(LPCTSTR lpCursor); void SetMouseCursor(LPCTSTR lpCursor);
void CenterWindow(HWND hParent, HWND hWnd); void CenterWindow(HWND hParent, HWND hWnd);
void RemoveButtonDefaultStyle(HWND hWnd); void RemoveButtonDefaultStyle(HWND hWnd);
void AddButtonDefaultStyle(HWND hWnd); void AddButtonDefaultStyle(HWND hWnd);
int DpToPixels(int dp, HWND hWnd);
UINT GetDPIForWindow(HWND hWnd);
int GetSystemMetricsForWindow(int index, HWND hWnd);
}

View File

@ -332,88 +332,59 @@ void ViewOptionsDialog::SetControls(HWND hDlg)
int orbitMask = appCore->getRenderer()->getOrbitMask(); int orbitMask = appCore->getRenderer()->getOrbitMask();
//Set checkboxes and radiobuttons //Set checkboxes and radiobuttons
SendDlgItemMessage(hDlg, IDC_SHOWATMOSPHERES, BM_SETCHECK, dlgCheck64(hDlg, IDC_SHOWATMOSPHERES, renderFlags, Renderer::ShowAtmospheres);
(renderFlags & Renderer::ShowAtmospheres)? BST_CHECKED:BST_UNCHECKED, 0); dlgCheck64(hDlg, IDC_SHOWCELESTIALGRID, renderFlags, Renderer::ShowCelestialSphere);
SendDlgItemMessage(hDlg, IDC_SHOWCELESTIALGRID, BM_SETCHECK, dlgCheck64(hDlg, IDC_SHOWHORIZONGRID, renderFlags, Renderer::ShowHorizonGrid);
(renderFlags & Renderer::ShowCelestialSphere)? BST_CHECKED:BST_UNCHECKED, 0); dlgCheck64(hDlg, IDC_SHOWGALACTICGRID, renderFlags, Renderer::ShowGalacticGrid);
SendDlgItemMessage(hDlg, IDC_SHOWHORIZONGRID, BM_SETCHECK, dlgCheck64(hDlg, IDC_SHOWECLIPTICGRID, renderFlags, Renderer::ShowEclipticGrid);
(renderFlags & Renderer::ShowHorizonGrid)? BST_CHECKED:BST_UNCHECKED, 0); dlgCheck64(hDlg, IDC_SHOWECLIPTIC, renderFlags, Renderer::ShowEcliptic);
SendDlgItemMessage(hDlg, IDC_SHOWGALACTICGRID, BM_SETCHECK, dlgCheck64(hDlg, IDC_SHOWCLOUDS, renderFlags, Renderer::ShowCloudMaps);
(renderFlags & Renderer::ShowGalacticGrid)? BST_CHECKED:BST_UNCHECKED, 0); dlgCheck64(hDlg, IDC_SHOWCLOUDSHADOWS, renderFlags, Renderer::ShowCloudShadows);
SendDlgItemMessage(hDlg, IDC_SHOWECLIPTICGRID, BM_SETCHECK, dlgCheck64(hDlg, IDC_SHOWCONSTELLATIONS, renderFlags, Renderer::ShowDiagrams);
(renderFlags & Renderer::ShowEclipticGrid)? BST_CHECKED:BST_UNCHECKED, 0); dlgCheck64(hDlg, IDC_SHOWECLIPSESHADOWS, renderFlags, Renderer::ShowEclipseShadows);
SendDlgItemMessage(hDlg, IDC_SHOWECLIPTIC, BM_SETCHECK, dlgCheck64(hDlg, IDC_SHOWGALAXIES, renderFlags, Renderer::ShowGalaxies);
(renderFlags & Renderer::ShowEcliptic)? BST_CHECKED:BST_UNCHECKED, 0); dlgCheck64(hDlg, IDC_SHOWGLOBULARS, renderFlags, Renderer::ShowGlobulars);
SendDlgItemMessage(hDlg, IDC_SHOWCLOUDS, BM_SETCHECK, dlgCheck64(hDlg, IDC_SHOWNEBULAE, renderFlags, Renderer::ShowNebulae);
(renderFlags & Renderer::ShowCloudMaps)? BST_CHECKED:BST_UNCHECKED, 0); dlgCheck64(hDlg, IDC_SHOWOPENCLUSTERS, renderFlags, Renderer::ShowOpenClusters);
SendDlgItemMessage(hDlg, IDC_SHOWCLOUDSHADOWS, BM_SETCHECK, dlgCheck64(hDlg, IDC_SHOWNIGHTSIDELIGHTS, renderFlags, Renderer::ShowNightMaps);
(renderFlags & Renderer::ShowCloudShadows)? BST_CHECKED:BST_UNCHECKED, 0); dlgCheck64(hDlg, IDC_SHOWORBITS, renderFlags, Renderer::ShowOrbits);
SendDlgItemMessage(hDlg, IDC_SHOWCONSTELLATIONS, BM_SETCHECK,
(renderFlags & Renderer::ShowDiagrams)? BST_CHECKED:BST_UNCHECKED, 0);
SendDlgItemMessage(hDlg, IDC_SHOWECLIPSESHADOWS, BM_SETCHECK,
(renderFlags & Renderer::ShowEclipseShadows)? BST_CHECKED:BST_UNCHECKED, 0);
SendDlgItemMessage(hDlg, IDC_SHOWGALAXIES, BM_SETCHECK,
(renderFlags & Renderer::ShowGalaxies)? BST_CHECKED:BST_UNCHECKED, 0);
SendDlgItemMessage(hDlg, IDC_SHOWGLOBULARS, BM_SETCHECK,
(renderFlags & Renderer::ShowGlobulars)? BST_CHECKED:BST_UNCHECKED, 0);
SendDlgItemMessage(hDlg, IDC_SHOWNEBULAE, BM_SETCHECK,
(renderFlags & Renderer::ShowNebulae)? BST_CHECKED:BST_UNCHECKED, 0);
SendDlgItemMessage(hDlg, IDC_SHOWOPENCLUSTERS, BM_SETCHECK,
(renderFlags & Renderer::ShowOpenClusters)? BST_CHECKED:BST_UNCHECKED, 0);
SendDlgItemMessage(hDlg, IDC_SHOWNIGHTSIDELIGHTS, BM_SETCHECK,
(renderFlags & Renderer::ShowNightMaps)? BST_CHECKED:BST_UNCHECKED, 0);
dlgCheck64(hDlg, IDC_SHOWORBITS, renderFlags, Renderer::ShowOrbits);
dlgCheck64(hDlg, IDC_SHOWFADINGORBITS, renderFlags, Renderer::ShowFadingOrbits); dlgCheck64(hDlg, IDC_SHOWFADINGORBITS, renderFlags, Renderer::ShowFadingOrbits);
dlgCheck64(hDlg, IDC_SHOWPARTIALTRAJECTORIES, renderFlags, Renderer::ShowPartialTrajectories); dlgCheck64(hDlg, IDC_SHOWPARTIALTRAJECTORIES, renderFlags, Renderer::ShowPartialTrajectories);
dlgCheck(hDlg, IDC_PLANETORBITS, orbitMask, Body::Planet); dlgCheck(hDlg, IDC_PLANETORBITS, orbitMask, Body::Planet);
dlgCheck(hDlg, IDC_DWARFPLANETORBITS,orbitMask, Body::DwarfPlanet); dlgCheck(hDlg, IDC_DWARFPLANETORBITS,orbitMask, Body::DwarfPlanet);
dlgCheck(hDlg, IDC_MOONORBITS, orbitMask, Body::Moon); dlgCheck(hDlg, IDC_MOONORBITS, orbitMask, Body::Moon);
dlgCheck(hDlg, IDC_MINORMOONORBITS, orbitMask, Body::MinorMoon); dlgCheck(hDlg, IDC_MINORMOONORBITS, orbitMask, Body::MinorMoon);
dlgCheck(hDlg, IDC_ASTEROIDORBITS, orbitMask, Body::Asteroid); dlgCheck(hDlg, IDC_ASTEROIDORBITS, orbitMask, Body::Asteroid);
dlgCheck(hDlg, IDC_COMETORBITS, orbitMask, Body::Comet); dlgCheck(hDlg, IDC_COMETORBITS, orbitMask, Body::Comet);
dlgCheck(hDlg, IDC_SPACECRAFTORBITS, orbitMask, Body::Spacecraft); dlgCheck(hDlg, IDC_SPACECRAFTORBITS, orbitMask, Body::Spacecraft);
dlgCheck(hDlg, IDC_STARORBITS, orbitMask, Body::Stellar); dlgCheck(hDlg, IDC_STARORBITS, orbitMask, Body::Stellar);
SendDlgItemMessage(hDlg, IDC_SHOWPLANETS, BM_SETCHECK, dlgCheck64(hDlg, IDC_SHOWPLANETS, renderFlags, Renderer::ShowPlanets);
(renderFlags & Renderer::ShowPlanets) != 0 ? BST_CHECKED : BST_UNCHECKED, 0); dlgCheck64(hDlg, IDC_SHOWDWARFPLANETS, renderFlags, Renderer::ShowDwarfPlanets);
SendDlgItemMessage(hDlg, IDC_SHOWDWARFPLANETS, BM_SETCHECK, dlgCheck64(hDlg, IDC_SHOWMOONS, renderFlags, Renderer::ShowMoons);
((renderFlags ^ Renderer::ShowDwarfPlanets) != 0) ? BST_CHECKED : BST_UNCHECKED, 0); dlgCheck64(hDlg, IDC_SHOWMINORMOONS, renderFlags, Renderer::ShowMinorMoons);
SendDlgItemMessage(hDlg, IDC_SHOWMOONS, BM_SETCHECK, dlgCheck64(hDlg, IDC_SHOWASTEROIDS, renderFlags, Renderer::ShowAsteroids);
((renderFlags ^ Renderer::ShowMoons) != 0) ? BST_CHECKED : BST_UNCHECKED, 0); dlgCheck64(hDlg, IDC_SHOWCOMETS, renderFlags, Renderer::ShowComets);
SendDlgItemMessage(hDlg, IDC_SHOWMINORMOONS, BM_SETCHECK, dlgCheck64(hDlg, IDC_SHOWSPACECRAFTS, renderFlags, Renderer::ShowSpacecrafts);
((renderFlags ^ Renderer::ShowMinorMoons) != 0) ? BST_CHECKED : BST_UNCHECKED, 0); dlgCheck64(hDlg, IDC_SHOWSTARS, renderFlags, Renderer::ShowStars);
SendDlgItemMessage(hDlg, IDC_SHOWASTEROIDS, BM_SETCHECK, dlgCheck64(hDlg, IDC_SHOWCONSTELLATIONBORDERS, renderFlags, Renderer::ShowBoundaries);
((renderFlags ^ Renderer::ShowAsteroids) != 0) ? BST_CHECKED : BST_UNCHECKED, 0); dlgCheck64(hDlg, IDC_SHOWRINGSHADOWS, renderFlags, Renderer::ShowRingShadows);
SendDlgItemMessage(hDlg, IDC_SHOWCOMETS, BM_SETCHECK, dlgCheck64(hDlg, IDC_SHOWRINGS, renderFlags, Renderer::ShowPlanetRings);
((renderFlags ^ Renderer::ShowComets) != 0) ? BST_CHECKED : BST_UNCHECKED, 0); dlgCheck64(hDlg, IDC_SHOWCOMETTAILS, renderFlags, Renderer::ShowCometTails);
SendDlgItemMessage(hDlg, IDC_SHOWSPACECRAFTS, BM_SETCHECK, dlgCheck64(hDlg, IDC_SHOWMARKERS, renderFlags, Renderer::ShowMarkers);
((renderFlags ^ Renderer::ShowSpacecrafts) != 0) ? BST_CHECKED : BST_UNCHECKED, 0);
SendDlgItemMessage(hDlg, IDC_SHOWSTARS, BM_SETCHECK,
(renderFlags & Renderer::ShowStars)? BST_CHECKED:BST_UNCHECKED, 0);
SendDlgItemMessage(hDlg, IDC_SHOWCONSTELLATIONBORDERS, BM_SETCHECK,
(renderFlags & Renderer::ShowBoundaries)? BST_CHECKED:BST_UNCHECKED, 0);
SendDlgItemMessage(hDlg, IDC_SHOWRINGSHADOWS, BM_SETCHECK,
(renderFlags & Renderer::ShowRingShadows)? BST_CHECKED:BST_UNCHECKED, 0);
SendDlgItemMessage(hDlg, IDC_SHOWRINGS, BM_SETCHECK,
(renderFlags & Renderer::ShowPlanetRings)? BST_CHECKED:BST_UNCHECKED, 0);
SendDlgItemMessage(hDlg, IDC_SHOWCOMETTAILS, BM_SETCHECK,
(renderFlags & Renderer::ShowCometTails)? BST_CHECKED:BST_UNCHECKED, 0);
SendDlgItemMessage(hDlg, IDC_SHOWMARKERS, BM_SETCHECK,
(renderFlags & Renderer::ShowMarkers)? BST_CHECKED:BST_UNCHECKED, 0);
dlgCheck(hDlg, IDC_LABELCONSTELLATIONS, labelMode, Renderer::ConstellationLabels); dlgCheck(hDlg, IDC_LABELCONSTELLATIONS, labelMode, Renderer::ConstellationLabels);
SendDlgItemMessage(hDlg, IDC_LABELCONSTELLATIONSLATIN, BM_SETCHECK, dlgCheck(hDlg, IDC_LABELCONSTELLATIONSLATIN, ~labelMode, Renderer::I18nConstellationLabels); // check box if flag unset
((labelMode & Renderer::I18nConstellationLabels) == 0) ? BST_CHECKED : BST_UNCHECKED, 0); dlgCheck(hDlg, IDC_LABELGALAXIES, labelMode, Renderer::GalaxyLabels);
dlgCheck(hDlg, IDC_LABELGALAXIES, labelMode, Renderer::GalaxyLabels);
dlgCheck(hDlg, IDC_LABELGLOBULARS, labelMode, Renderer::GlobularLabels); dlgCheck(hDlg, IDC_LABELGLOBULARS, labelMode, Renderer::GlobularLabels);
dlgCheck(hDlg, IDC_LABELNEBULAE, labelMode, Renderer::NebulaLabels); dlgCheck(hDlg, IDC_LABELNEBULAE, labelMode, Renderer::NebulaLabels);
dlgCheck(hDlg, IDC_LABELOPENCLUSTERS, labelMode, Renderer::OpenClusterLabels); dlgCheck(hDlg, IDC_LABELOPENCLUSTERS, labelMode, Renderer::OpenClusterLabels);
dlgCheck(hDlg, IDC_LABELSTARS, labelMode, Renderer::StarLabels); dlgCheck(hDlg, IDC_LABELSTARS, labelMode, Renderer::StarLabels);
dlgCheck(hDlg, IDC_LABELPLANETS, labelMode, Renderer::PlanetLabels); dlgCheck(hDlg, IDC_LABELPLANETS, labelMode, Renderer::PlanetLabels);
dlgCheck(hDlg, IDC_LABELDWARFPLANETS, labelMode, Renderer::DwarfPlanetLabels); dlgCheck(hDlg, IDC_LABELDWARFPLANETS, labelMode, Renderer::DwarfPlanetLabels);
dlgCheck(hDlg, IDC_LABELMOONS, labelMode, Renderer::MoonLabels); dlgCheck(hDlg, IDC_LABELMOONS, labelMode, Renderer::MoonLabels);
dlgCheck(hDlg, IDC_LABELMINORMOONS, labelMode, Renderer::MinorMoonLabels); dlgCheck(hDlg, IDC_LABELMINORMOONS, labelMode, Renderer::MinorMoonLabels);
dlgCheck(hDlg, IDC_LABELASTEROIDS, labelMode, Renderer::AsteroidLabels); dlgCheck(hDlg, IDC_LABELASTEROIDS, labelMode, Renderer::AsteroidLabels);
dlgCheck(hDlg, IDC_LABELCOMETS, labelMode, Renderer::CometLabels); dlgCheck(hDlg, IDC_LABELCOMETS, labelMode, Renderer::CometLabels);
dlgCheck(hDlg, IDC_LABELSPACECRAFT, labelMode, Renderer::SpacecraftLabels); dlgCheck(hDlg, IDC_LABELSPACECRAFT, labelMode, Renderer::SpacecraftLabels);
CheckRadioButton(hDlg, IDC_INFOTEXT0, IDC_INFOTEXT2, IDC_INFOTEXT0 + hudDetail); CheckRadioButton(hDlg, IDC_INFOTEXT0, IDC_INFOTEXT2, IDC_INFOTEXT0 + hudDetail);

View File

@ -209,11 +209,11 @@ float fractalsum(const Eigen::Vector2f& p, float freq)
float fractalsum(const Eigen::Vector3f& p, float freq) float fractalsum(const Eigen::Vector3f& p, float freq)
{ {
float t = 0.0f; float t = 0.0f;
while (freq >= 1.0f)
for (t = 0.0f; freq >= 1.0f; freq *= 0.5f)
{ {
Eigen::Vector3f vec = freq * p; Eigen::Vector3f vec = freq * p;
t += noise(vec) / freq; t += noise(vec) / freq;
freq *= 0.5f;
} }
return t; return t;

View File

@ -14,9 +14,15 @@
#include <iterator> #include <iterator>
#include <tuple> #include <tuple>
#include <utility> #include <utility>
#include <celutil/logger.h>
#ifdef HAVE_MESHOPTIMIZER
#include <meshoptimizer.h>
#endif
#include "mesh.h" #include "mesh.h"
using celestia::util::GetLogger;
namespace cmod namespace cmod
{ {
@ -38,6 +44,13 @@ VertexDescription appendingAttributes(const VertexDescription& desc, It begin, I
return VertexDescription(std::move(allAttributes)); return VertexDescription(std::move(allAttributes));
} }
bool
isOpaqueMaterial(const Material &material)
{
return (!(material.opacity > 0.01f && material.opacity < 1.0f)) &&
material.blend != BlendMode::AdditiveBlend;
}
} // end unnamed namespace } // end unnamed namespace
@ -320,13 +333,7 @@ Mesh::addGroup(PrimitiveGroupType prim,
{ {
PrimitiveGroup g; PrimitiveGroup g;
if (prim == PrimitiveGroupType::LineStrip || prim == PrimitiveGroupType::LineList) if (prim == PrimitiveGroupType::LineStrip || prim == PrimitiveGroupType::LineList)
{
g = createLinePrimitiveGroup(prim == PrimitiveGroupType::LineStrip, indices); g = createLinePrimitiveGroup(prim == PrimitiveGroupType::LineStrip, indices);
}
else
{
g.primOverride = prim;
}
g.indices = std::move(indices); g.indices = std::move(indices);
g.prim = prim; g.prim = prim;
@ -393,9 +400,80 @@ Mesh::aggregateByMaterial()
{ {
return g0.materialIndex < g1.materialIndex; return g0.materialIndex < g1.materialIndex;
}); });
mergePrimitiveGroups();
} }
void
Mesh::mergePrimitiveGroups()
{
if (groups.size() < 2)
return;
std::vector<PrimitiveGroup> newGroups;
for (size_t i = 0; i < groups.size(); i++)
{
auto &g = groups[i];
if (g.vertexCountOverride == 0 && g.prim == PrimitiveGroupType::TriStrip)
{
std::vector<Index32> newIndices;
newIndices.reserve(g.indices.size() * 2);
for (size_t j = 0, e = g.indices.size() - 2; j < e; j++)
{
auto x = g.indices[j + 0];
auto y = g.indices[j + 1];
auto z = g.indices[j + 2];
// skip degenerated triangles
if (x == y || y == z || z == x)
continue;
if ((j & 1) != 0) // FIXME: CCW hardcoded
std::swap(y, z);
newIndices.push_back(x);
newIndices.push_back(y);
newIndices.push_back(z);
}
g.indices = std::move(newIndices);
g.prim = PrimitiveGroupType::TriList;
}
if (i == 0 || g.vertexCountOverride != 0 || g.prim != PrimitiveGroupType::TriList)
{
newGroups.push_back(std::move(g));
}
else
{
auto &p = newGroups.back();
if (p.prim != g.prim || p.materialIndex != g.materialIndex)
{
newGroups.push_back(std::move(g));
}
else
{
p.indices.reserve(p.indices.size() + g.indices.size());
p.indices.insert(p.indices.end(), g.indices.begin(), g.indices.end());
}
}
}
GetLogger()->info("Optimized mesh groups: had {} groups, now: {} of them.\n", groups.size(), newGroups.size());
groups = std::move(newGroups);
}
void
Mesh::optimize()
{
#ifdef HAVE_MESHOPTIMIZER
if (groups.size() > 1)
return;
auto &g = groups.front();
meshopt_optimizeVertexCache(g.indices.data(), g.indices.data(), g.indices.size(), nVertices);
meshopt_optimizeOverdraw(g.indices.data(), g.indices.data(), g.indices.size(), reinterpret_cast<float*>(vertices.data()), nVertices, vertexDesc.strideBytes, 1.05f);
meshopt_optimizeVertexFetch(vertices.data(), g.indices.data(), g.indices.size(), vertices.data(), nVertices, vertexDesc.strideBytes);
#endif
}
bool bool
Mesh::pick(const Eigen::Vector3d& rayOrigin, const Eigen::Vector3d& rayDirection, PickResult* result) const Mesh::pick(const Eigen::Vector3d& rayOrigin, const Eigen::Vector3d& rayDirection, PickResult* result) const
{ {
@ -663,4 +741,52 @@ Mesh::getPrimitiveCount() const
return count; return count;
} }
void
Mesh::merge(const Mesh &other)
{
auto &ti = groups.front().indices;
const auto &oi = other.groups.front().indices;
ti.reserve(ti.size() + oi.size());
for (auto i : oi)
ti.push_back(i + nVertices);
vertices.reserve(vertices.size() + other.vertices.size());
vertices.insert(vertices.end(), other.vertices.begin(), other.vertices.end());
nVertices += other.nVertices;
}
bool
Mesh::canMerge(const Mesh &other, const std::vector<Material> &materials) const
{
if (getGroupCount() != 1 || other.getGroupCount() != 1)
return false;
const auto &tg = groups.front();
const auto &og = other.groups.front();
if (tg.vertexCountOverride != 0 || og.vertexCountOverride != 0 || tg.prim != PrimitiveGroupType::TriList)
return false;
if (std::tie(tg.materialIndex, tg.prim, vertexDesc.strideBytes) !=
std::tie(og.materialIndex, og.prim, other.vertexDesc.strideBytes))
return false;
if (!isOpaqueMaterial(materials[tg.materialIndex]) || !isOpaqueMaterial(materials[og.materialIndex]))
return false;
for (auto i = VertexAttributeSemantic::Position;
i < VertexAttributeSemantic::SemanticMax;
i = static_cast<VertexAttributeSemantic>(1 + static_cast<uint16_t>(i)))
{
auto &ta = vertexDesc.getAttribute(i);
auto &oa = other.vertexDesc.getAttribute(i);
if (ta.format != oa.format || ta.offsetWords != oa.offsetWords)
return false;
}
return true;
}
} // end namespace cmod } // end namespace cmod

View File

@ -237,8 +237,13 @@ class Mesh
unsigned int getVertexStrideWords() const { return vertexDesc.strideBytes / sizeof(cmod::VWord); } unsigned int getVertexStrideWords() const { return vertexDesc.strideBytes / sizeof(cmod::VWord); }
unsigned int getPrimitiveCount() const; unsigned int getPrimitiveCount() const;
void merge(const Mesh&);
bool canMerge(const Mesh&, const std::vector<Material> &materials) const;
void optimize();
private: private:
PrimitiveGroup createLinePrimitiveGroup(bool lineStrip, const std::vector<Index32>& indices); PrimitiveGroup createLinePrimitiveGroup(bool lineStrip, const std::vector<Index32>& indices);
void mergePrimitiveGroups();
VertexDescription vertexDesc{ }; VertexDescription vertexDesc{ };

View File

@ -15,8 +15,11 @@
#include <Eigen/Geometry> #include <Eigen/Geometry>
#include <celutil/logger.h>
#include "model.h" #include "model.h"
using celestia::util::GetLogger;
namespace cmod namespace cmod
{ {
@ -315,7 +318,6 @@ Model::usesTextureType(TextureSemantic t) const
} }
bool bool
Model::OpacityComparator::operator()(const Mesh& a, const Mesh& b) const Model::OpacityComparator::operator()(const Mesh& a, const Mesh& b) const
{ {
@ -335,6 +337,25 @@ Model::sortMeshes(const MeshComparator& comparator)
// Sort the meshes so that completely opaque ones are first // Sort the meshes so that completely opaque ones are first
std::sort(meshes.begin(), meshes.end(), std::ref(comparator)); std::sort(meshes.begin(), meshes.end(), std::ref(comparator));
std::vector<Mesh> newMeshes;
newMeshes.push_back(meshes[0].clone());
for (size_t i = 1; i < meshes.size(); i++)
{
auto &p = newMeshes.back();
if (!p.canMerge(meshes[i], materials))
{
newMeshes.push_back(meshes[i].clone());
continue;
}
p.merge(meshes[i]);
}
GetLogger()->info("Merged similar meshes: {} -> {}.\n", meshes.size(), newMeshes.size());
for (auto &mesh : newMeshes)
mesh.optimize();
meshes = std::move(newMeshes);
} }
} // end namespace cmod } // end namespace cmod

View File

@ -266,6 +266,9 @@ static void checkTimeslice(lua_State* l, lua_Debug* /*ar*/)
// allow the script to perform cleanup // allow the script to perform cleanup
void LuaState::cleanup() void LuaState::cleanup()
{ {
if (!costate)
return;
if (ioMode == Asking) if (ioMode == Asking)
{ {
// Restore renderflags: // Restore renderflags:

View File

@ -2296,7 +2296,6 @@ static int celestia_loadfont(lua_State* l)
CelestiaCore* appCore = getAppCore(l, AllErrors); CelestiaCore* appCore = getAppCore(l, AllErrors);
auto font = LoadTextureFont(appCore->getRenderer(), s); auto font = LoadTextureFont(appCore->getRenderer(), s);
if (font == nullptr) return 0; if (font == nullptr) return 0;
font->buildTexture();
return celx.pushClass(font); return celx.pushClass(font);
} }

View File

@ -1,6 +1,6 @@
// truetypefont.cpp // truetypefont.cpp
// //
// Copyright (C) 2019, Celestia Development Team // Copyright (C) 2019-2022, Celestia Development Team
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License
@ -9,13 +9,15 @@
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <iostream> #include <celcompat/charconv.h>
#include <vector>
#include <celutil/logger.h>
#include <celutil/utf8.h>
#include <celengine/glsupport.h> #include <celengine/glsupport.h>
#include <celengine/render.h> #include <celengine/render.h>
#include <celutil/logger.h>
#include <celutil/utf8.h>
#include <ft2build.h> #include <ft2build.h>
#include <map>
#include <system_error>
#include <vector>
#include FT_FREETYPE_H #include FT_FREETYPE_H
#include "truetypefont.h" #include "truetypefont.h"
@ -25,26 +27,24 @@
#include <fstream> #include <fstream>
#endif #endif
using namespace std; using celestia::compat::from_chars;
using celestia::util::GetLogger; using celestia::util::GetLogger;
static FT_Library ft = nullptr;
struct Glyph struct Glyph
{ {
wchar_t ch; wchar_t ch;
int ax; // advance.x int ax; // advance.x
int ay; // advance.y int ay; // advance.y
int bw; // bitmap.width; unsigned int bw; // bitmap.width;
int bh; // bitmap.height; unsigned int bh; // bitmap.height;
int bl; // bitmap_left; int bl; // bitmap_left;
int bt; // bitmap_top; int bt; // bitmap_top;
float tx; // x offset of glyph in texture coordinates float tx; // x offset of glyph in texture coordinates
float ty; // y offset of glyph in texture coordinates float ty; // y offset of glyph in texture coordinates
}; };
struct UnicodeBlock struct UnicodeBlock
@ -56,75 +56,82 @@ struct TextureFontPrivate
{ {
struct FontVertex struct FontVertex
{ {
FontVertex(float _x, float _y, float _u, float _v) : FontVertex(float _x, float _y, float _u, float _v) : x(_x), y(_y), u(_u), v(_v)
x(_x), y(_y), u(_u), v(_v) {
{} }
float x, y; float x, y;
float u, v; float u, v;
}; };
TextureFontPrivate() = delete;
TextureFontPrivate(const Renderer *renderer); TextureFontPrivate(const Renderer *renderer);
~TextureFontPrivate(); ~TextureFontPrivate();
TextureFontPrivate(const TextureFontPrivate&) = default; TextureFontPrivate() = delete;
TextureFontPrivate(TextureFontPrivate&&) = default; TextureFontPrivate(const TextureFontPrivate &) = default;
TextureFontPrivate& operator=(const TextureFontPrivate&) = default; TextureFontPrivate(TextureFontPrivate &&) = default;
TextureFontPrivate& operator=(TextureFontPrivate&&) = default; TextureFontPrivate &operator=(const TextureFontPrivate &) = default;
TextureFontPrivate &operator=(TextureFontPrivate &&) = default;
float render(const string &s, float x, float y); float render(std::string_view s, float x, float y);
float render(wchar_t ch, float xoffset, float yoffset); float render(wchar_t ch, float xoffset, float yoffset);
bool buildAtlas(); bool buildAtlas();
void computeTextureSize(); void computeTextureSize();
bool loadGlyphInfo(wchar_t, Glyph&); bool loadGlyphInfo(wchar_t /*ch*/, Glyph & /*c*/) const;
void initCommonGlyphs(); void initCommonGlyphs();
int getCommonGlyphsCount(); int getCommonGlyphsCount();
Glyph& getGlyph(wchar_t); Glyph & getGlyph(wchar_t /*ch*/);
Glyph& getGlyph(wchar_t, wchar_t); Glyph & getGlyph(wchar_t /*ch*/, wchar_t /*fallback*/);
int toPos(wchar_t) const; [[nodiscard]] int toPos(wchar_t /*ch*/) const;
void optimize(); void optimize();
CelestiaGLProgram* getProgram(); CelestiaGLProgram *getProgram();
void flush(); void flush();
const Renderer *m_renderer; const Renderer *m_renderer;
CelestiaGLProgram *m_prog { nullptr }; CelestiaGLProgram *m_prog{ nullptr };
FT_Face m_face; // font face FT_Face m_face; // font face
int m_maxAscent; int m_maxAscent{ 0 };
int m_maxDescent; int m_maxDescent{ 0 };
int m_maxWidth; int m_maxWidth{ 0 };
int m_texWidth; int m_texWidth{ 0 };
int m_texHeight; int m_texHeight{ 0 };
GLuint m_texName { 0 }; // texture object GLuint m_texName{ 0 }; // texture object
vector<Glyph> m_glyphs; // character information std::vector<Glyph> m_glyphs; // character information
GLint m_maxTextureSize; // max supported texture size GLint m_maxTextureSize; // max supported texture size
array<UnicodeBlock, 2> m_unicodeBlocks; std::array<UnicodeBlock, 2> m_unicodeBlocks;
int m_commonGlyphsCount { 0 }; int m_commonGlyphsCount{ 0 };
int m_inserted { 0 }; int m_inserted{ 0 };
Eigen::Matrix4f m_projection; Eigen::Matrix4f m_projection;
Eigen::Matrix4f m_modelView; Eigen::Matrix4f m_modelView;
bool m_shaderInUse { false }; bool m_shaderInUse{ false };
vector<FontVertex> m_fontVertices; std::vector<FontVertex> m_fontVertices;
}; };
inline float pt_to_px(float pt, int dpi = 96) namespace
{ {
return dpi == 0 ? pt : pt / 72.0 * dpi;
inline float
pt_to_px(float pt, int dpi = 96)
{
return dpi == 0 ? pt : pt / 72.0f * static_cast<float>(dpi);
} }
Glyph g_badGlyph = { 0, 0, 0, 0, 0, 0, 0, 0.0f, 0.0f };
} // namespace
/* /*
first = ((c / 32) + 1) * 32 == c & ~0xdf first = ((c / 32) + 1) * 32 == c & ~0xdf
last = first + 32 last = first + 32
*/ */
TextureFontPrivate::TextureFontPrivate(const Renderer *renderer) : TextureFontPrivate::TextureFontPrivate(const Renderer *renderer) : m_renderer(renderer)
m_renderer(renderer)
{ {
m_unicodeBlocks[0] = { 0x0020, 0x007E }; // Basic Latin m_unicodeBlocks[0] = { 0x0020, 0x007E }; // Basic Latin
m_unicodeBlocks[1] = { 0x03B1, 0x03CF }; // Lower case Greek m_unicodeBlocks[1] = { 0x03B1, 0x03CF }; // Lower case Greek
@ -134,13 +141,12 @@ TextureFontPrivate::TextureFontPrivate(const Renderer *renderer) :
TextureFontPrivate::~TextureFontPrivate() TextureFontPrivate::~TextureFontPrivate()
{ {
if (m_face) if (m_face != nullptr) FT_Done_Face(m_face);
FT_Done_Face(m_face); if (m_texName != 0) glDeleteTextures(1, &m_texName);
if (m_texName != 0)
glDeleteTextures(1, &m_texName);
} }
bool TextureFontPrivate::loadGlyphInfo(wchar_t ch, Glyph &c) bool
TextureFontPrivate::loadGlyphInfo(wchar_t ch, Glyph &c) const
{ {
FT_GlyphSlot g = m_face->glyph; FT_GlyphSlot g = m_face->glyph;
if (FT_Load_Char(m_face, ch, FT_LOAD_RENDER) != 0) if (FT_Load_Char(m_face, ch, FT_LOAD_RENDER) != 0)
@ -159,10 +165,10 @@ bool TextureFontPrivate::loadGlyphInfo(wchar_t ch, Glyph &c)
return true; return true;
} }
void TextureFontPrivate::initCommonGlyphs() void
TextureFontPrivate::initCommonGlyphs()
{ {
if (m_glyphs.size() > 0) if (!m_glyphs.empty()) return;
return;
m_glyphs.reserve(256); m_glyphs.reserve(256);
@ -178,12 +184,13 @@ void TextureFontPrivate::initCommonGlyphs()
} }
} }
void TextureFontPrivate::computeTextureSize() void
TextureFontPrivate::computeTextureSize()
{ {
int roww = 0; int roww = 0;
int rowh = 0; int rowh = 0;
int w = 0; int w = 0;
int h = 0; int h = 0;
// Find minimum size for a texture holding all visible ASCII characters // Find minimum size for a texture holding all visible ASCII characters
for (const auto &c : m_glyphs) for (const auto &c : m_glyphs)
@ -192,23 +199,24 @@ void TextureFontPrivate::computeTextureSize()
if (roww + c.bw + 1 >= m_maxTextureSize) if (roww + c.bw + 1 >= m_maxTextureSize)
{ {
w = max(w, roww); w = std::max(w, roww);
h += rowh; h += rowh;
roww = 0; roww = 0;
rowh = 0; rowh = 0;
} }
roww += c.bw + 1; roww += c.bw + 1;
rowh = max(rowh, (int)c.bh); rowh = std::max(rowh, static_cast<int>(c.bh));
} }
w = max(w, roww); w = std::max(w, roww);
h += rowh; h += rowh;
m_texWidth = w; m_texWidth = w;
m_texHeight = h; m_texHeight = h;
} }
bool TextureFontPrivate::buildAtlas() bool
TextureFontPrivate::buildAtlas()
{ {
FT_GlyphSlot g = m_face->glyph; FT_GlyphSlot g = m_face->glyph;
@ -217,14 +225,20 @@ bool TextureFontPrivate::buildAtlas()
// Create a texture that will be used to hold all glyphs // Create a texture that will be used to hold all glyphs
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
if (m_texName != 0) if (m_texName != 0) glDeleteTextures(1, &m_texName);
glDeleteTextures(1, &m_texName);
glGenTextures(1, &m_texName); glGenTextures(1, &m_texName);
if (m_texName == 0) if (m_texName == 0) return false;
return false;
glBindTexture(GL_TEXTURE_2D, m_texName); glBindTexture(GL_TEXTURE_2D, m_texName);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, m_texWidth, m_texHeight, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0); glTexImage2D(GL_TEXTURE_2D,
0,
GL_ALPHA,
m_texWidth,
m_texHeight,
0,
GL_ALPHA,
GL_UNSIGNED_BYTE,
nullptr);
// We require 1 byte alignment when uploading texture data // We require 1 byte alignment when uploading texture data
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
@ -247,42 +261,53 @@ bool TextureFontPrivate::buildAtlas()
{ {
if (c.ch == 0) continue; // skip bad glyphs if (c.ch == 0) continue; // skip bad glyphs
if (FT_Load_Char(m_face, c.ch, FT_LOAD_RENDER)) if (FT_Load_Char(m_face, c.ch, FT_LOAD_RENDER) != 0)
{ {
GetLogger()->warn("Loading character {:x} failed!\n", static_cast<unsigned>(c.ch)); GetLogger()->warn("Loading character {:x} failed!\n", static_cast<unsigned>(c.ch));
c.ch = 0; c.ch = 0;
continue; continue;
} }
if (ox + int(g->bitmap.width) > int(m_texWidth)) if (ox + int(g->bitmap.width) > int(m_texWidth))
{ {
oy += rowh; oy += rowh;
rowh = 0; rowh = 0;
ox = 0; ox = 0;
} }
glTexSubImage2D(GL_TEXTURE_2D, 0, ox, oy, g->bitmap.width, g->bitmap.rows, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer); glTexSubImage2D(GL_TEXTURE_2D,
c.tx = (float)ox / (float)m_texWidth; 0,
c.ty = (float)oy / (float)m_texHeight; ox,
oy,
g->bitmap.width,
g->bitmap.rows,
GL_ALPHA,
GL_UNSIGNED_BYTE,
g->bitmap.buffer);
c.tx = static_cast<float>(ox) / static_cast<float>(m_texWidth);
c.ty = static_cast<float>(oy) / static_cast<float>(m_texHeight);
rowh = max(rowh, (int)g->bitmap.rows); rowh = std::max(rowh, static_cast<int>(g->bitmap.rows));
ox += g->bitmap.width + 1; ox += g->bitmap.width + 1;
} }
#if DUMP_TEXTURE #if DUMP_TEXTURE
fmt::printf(cout/*cerr*/, "Generated a {} x {} ({} kb) texture atlas\n", m_texWidth, m_texHeight, m_texWidth * m_texHeight / 1024); fmt::print("Generated a {} x {} ({} kb) texture atlas\n",
size_t img_size = sizeof(uint8_t) * m_texWidth * m_texHeight * 4; m_texWidth, m_texHeight,
uint8_t *raw_img = new uint8_t[img_size]; m_texWidth * m_texHeight / 1024);
size_t img_size = sizeof(uint8_t) * m_texWidth * m_texHeight * 4;
uint8_t *raw_img = new uint8_t[img_size];
glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, raw_img); glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, raw_img);
ofstream f(fmt::format("/tmp/texture_{}x{}.data", m_texWidth, m_texHeight), ios::binary); ofstream f(fmt::format("/tmp/texture_{}x{}.data", m_texWidth, m_texHeight), ios::binary);
f.write(reinterpret_cast<char*>(raw_img), img_size); f.write(reinterpret_cast<char *>(raw_img), img_size);
f.close(); f.close();
delete[] raw_img; delete[] raw_img;
#endif #endif
return true; return true;
} }
int TextureFontPrivate::getCommonGlyphsCount() int
TextureFontPrivate::getCommonGlyphsCount()
{ {
if (m_commonGlyphsCount == 0) if (m_commonGlyphsCount == 0)
{ {
@ -292,17 +317,16 @@ int TextureFontPrivate::getCommonGlyphsCount()
return m_commonGlyphsCount; return m_commonGlyphsCount;
} }
int TextureFontPrivate::toPos(wchar_t ch) const int
TextureFontPrivate::toPos(wchar_t ch) const
{ {
int pos = 0; int pos = 0;
if (ch > m_unicodeBlocks.back().last) if (ch > m_unicodeBlocks.back().last) return -1;
return -1;
for (const auto &r : m_unicodeBlocks) for (const auto &r : m_unicodeBlocks)
{ {
if (ch < r.first) if (ch < r.first) return -1;
return -1;
if (ch <= r.last) if (ch <= r.last)
{ {
@ -314,22 +338,22 @@ int TextureFontPrivate::toPos(wchar_t ch) const
return -1; return -1;
} }
Glyph& TextureFontPrivate::getGlyph(wchar_t ch, wchar_t fallback) Glyph &
TextureFontPrivate::getGlyph(wchar_t ch, wchar_t fallback)
{ {
auto &g = getGlyph(ch); auto &g = getGlyph(ch);
return g.ch == ch ? g : getGlyph(fallback); return g.ch == ch ? g : getGlyph(fallback);
} }
Glyph g_badGlyph = {0, 0, 0, 0, 0, 0, 0, 0.0f, 0.0f}; Glyph &
Glyph& TextureFontPrivate::getGlyph(wchar_t ch) TextureFontPrivate::getGlyph(wchar_t ch)
{ {
auto pos = toPos(ch); if (auto pos = toPos(ch); pos != -1)
if (pos != -1)
return m_glyphs[pos]; return m_glyphs[pos];
auto it = find_if(m_glyphs.begin() + getCommonGlyphsCount(), auto it = find_if(m_glyphs.begin() + getCommonGlyphsCount(),
m_glyphs.end(), m_glyphs.end(),
[ch](Glyph &g) { return g.ch == ch; }); [ch](const Glyph &g) { return g.ch == ch; });
if (it != m_glyphs.end()) if (it != m_glyphs.end())
return *it; return *it;
@ -341,14 +365,14 @@ Glyph& TextureFontPrivate::getGlyph(wchar_t ch)
flush(); // render text to avoid garbled output due to changed texture flush(); // render text to avoid garbled output due to changed texture
m_glyphs.push_back(c); m_glyphs.push_back(c);
if (++m_inserted == 10) if (++m_inserted == 10) optimize();
optimize();
buildAtlas(); buildAtlas();
return m_glyphs.back(); return m_glyphs.back();
} }
void TextureFontPrivate::optimize() void
TextureFontPrivate::optimize()
{ {
m_inserted = 0; m_inserted = 0;
} }
@ -358,34 +382,33 @@ void TextureFontPrivate::optimize()
* Rendering starts at coordinates (x, y), z is always 0. * Rendering starts at coordinates (x, y), z is always 0.
* The pixel coordinates that the FreeType2 library uses are scaled by (sx, sy). * The pixel coordinates that the FreeType2 library uses are scaled by (sx, sy).
*/ */
float TextureFontPrivate::render(const string &s, float x, float y) float
TextureFontPrivate::render(std::string_view s, float x, float y)
{ {
if (m_texName == 0) if (m_texName == 0) return 0;
return 0;
// Use the texture containing the atlas // Use the texture containing the atlas
glBindTexture(GL_TEXTURE_2D, m_texName); glBindTexture(GL_TEXTURE_2D, m_texName);
// Loop through all characters // Loop through all characters
int len = s.length(); int len = s.length();
bool validChar = true; bool validChar = true;
int i = 0; int i = 0;
while (i < len && validChar) while (i < len && validChar)
{ {
wchar_t ch = 0; wchar_t ch = 0;
validChar = UTF8Decode(s, i, ch); validChar = UTF8Decode(s, i, ch);
if (!validChar) if (!validChar) break;
break;
i += UTF8EncodedSize(ch); i += UTF8EncodedSize(ch);
auto& g = getGlyph(ch, L'?'); auto &g = getGlyph(ch, L'?');
// Calculate the vertex and texture coordinates // Calculate the vertex and texture coordinates
const float x1 = x + g.bl; const float x1 = x + g.bl;
const float y1 = y + g.bt - g.bh; const float y1 = y + g.bt - g.bh;
const float w = g.bw; const float w = g.bw;
const float h = g.bh; const float h = g.bh;
const float x2 = x1 + w; const float x2 = x1 + w;
const float y2 = y1 + h; const float y2 = y1 + h;
@ -394,27 +417,26 @@ float TextureFontPrivate::render(const string &s, float x, float y)
y += g.ay; y += g.ay;
// Skip glyphs that have no pixels // Skip glyphs that have no pixels
if (g.bw == 0 || g.bh == 0) if (g.bw == 0 || g.bh == 0) continue;
continue;
const float tx1 = g.tx; const float tx1 = g.tx;
const float ty1 = g.ty; const float ty1 = g.ty;
const float tx2 = tx1 + w / m_texWidth; const float tx2 = tx1 + w / m_texWidth;
const float ty2 = ty1 + h / m_texHeight; const float ty2 = ty1 + h / m_texHeight;
m_fontVertices.emplace_back(FontVertex(x1, y1, tx1, ty2)); m_fontVertices.emplace_back(x1, y1, tx1, ty2);
m_fontVertices.emplace_back(FontVertex(x2, y1, tx2, ty2)); m_fontVertices.emplace_back(x2, y1, tx2, ty2);
m_fontVertices.emplace_back(FontVertex(x1, y2, tx1, ty1)); m_fontVertices.emplace_back(x1, y2, tx1, ty1);
m_fontVertices.emplace_back(FontVertex(x2, y2, tx2, ty1)); m_fontVertices.emplace_back(x2, y2, tx2, ty1);
} }
return x; return x;
} }
float TextureFontPrivate::render(wchar_t ch, float xoffset, float yoffset) float
TextureFontPrivate::render(wchar_t ch, float xoffset, float yoffset)
{ {
auto &g = getGlyph(ch, L'?');
auto& g = getGlyph(ch, L'?');
// Calculate the vertex and texture coordinates // Calculate the vertex and texture coordinates
const float x1 = xoffset + g.bl; const float x1 = xoffset + g.bl;
@ -427,32 +449,30 @@ float TextureFontPrivate::render(wchar_t ch, float xoffset, float yoffset)
const float tx2 = tx1 + static_cast<float>(g.bw) / m_texWidth; const float tx2 = tx1 + static_cast<float>(g.bw) / m_texWidth;
const float ty2 = ty1 + static_cast<float>(g.bh) / m_texHeight; const float ty2 = ty1 + static_cast<float>(g.bh) / m_texHeight;
m_fontVertices.emplace_back(FontVertex(x1, y1, tx1, ty2)); m_fontVertices.emplace_back(x1, y1, tx1, ty2);
m_fontVertices.emplace_back(FontVertex(x2, y1, tx2, ty2)); m_fontVertices.emplace_back(x2, y1, tx2, ty2);
m_fontVertices.emplace_back(FontVertex(x1, y2, tx1, ty1)); m_fontVertices.emplace_back(x1, y2, tx1, ty1);
m_fontVertices.emplace_back(FontVertex(x2, y2, tx2, ty1)); m_fontVertices.emplace_back(x2, y2, tx2, ty1);
return g.ax; return g.ax;
} }
CelestiaGLProgram* TextureFontPrivate::getProgram() CelestiaGLProgram *
TextureFontPrivate::getProgram()
{ {
if (m_prog != nullptr) if (m_prog != nullptr) return m_prog;
return m_prog;
m_prog = m_renderer->getShaderManager().getShader("text"); m_prog = m_renderer->getShaderManager().getShader("text");
return m_prog; return m_prog;
} }
void TextureFontPrivate::flush() void
TextureFontPrivate::flush()
{ {
if (m_fontVertices.size() < 4) if (m_fontVertices.size() < 4) return;
return;
vector<unsigned short> indexes; std::vector<unsigned short> indexes;
indexes.reserve(m_fontVertices.size() / 4 * 6); indexes.reserve(m_fontVertices.size() / 4 * 6);
for (unsigned short index = 0; for (unsigned short index = 0; index < static_cast<unsigned short>(m_fontVertices.size()); index += 4)
index < (unsigned short) m_fontVertices.size();
index += 4)
{ {
indexes.push_back(index + 0); indexes.push_back(index + 0);
indexes.push_back(index + 1); indexes.push_back(index + 1);
@ -465,9 +485,17 @@ void TextureFontPrivate::flush()
glEnableVertexAttribArray(CelestiaGLProgram::VertexCoordAttributeIndex); glEnableVertexAttribArray(CelestiaGLProgram::VertexCoordAttributeIndex);
glEnableVertexAttribArray(CelestiaGLProgram::TextureCoord0AttributeIndex); glEnableVertexAttribArray(CelestiaGLProgram::TextureCoord0AttributeIndex);
glVertexAttribPointer(CelestiaGLProgram::VertexCoordAttributeIndex, glVertexAttribPointer(CelestiaGLProgram::VertexCoordAttributeIndex,
2, GL_FLOAT, GL_FALSE, sizeof(FontVertex), &m_fontVertices[0].x); 2,
GL_FLOAT,
GL_FALSE,
sizeof(FontVertex),
&m_fontVertices[0].x);
glVertexAttribPointer(CelestiaGLProgram::TextureCoord0AttributeIndex, glVertexAttribPointer(CelestiaGLProgram::TextureCoord0AttributeIndex,
2, GL_FLOAT, GL_FALSE, sizeof(FontVertex), &m_fontVertices[0].u); 2,
GL_FLOAT,
GL_FALSE,
sizeof(FontVertex),
&m_fontVertices[0].u);
glDrawElements(GL_TRIANGLES, indexes.size(), GL_UNSIGNED_SHORT, indexes.data()); glDrawElements(GL_TRIANGLES, indexes.size(), GL_UNSIGNED_SHORT, indexes.data());
glDisableVertexAttribArray(CelestiaGLProgram::VertexCoordAttributeIndex); glDisableVertexAttribArray(CelestiaGLProgram::VertexCoordAttributeIndex);
glDisableVertexAttribArray(CelestiaGLProgram::TextureCoord0AttributeIndex); glDisableVertexAttribArray(CelestiaGLProgram::TextureCoord0AttributeIndex);
@ -475,17 +503,11 @@ void TextureFontPrivate::flush()
m_fontVertices.clear(); m_fontVertices.clear();
} }
TextureFont::TextureFont(const Renderer *renderer) : TextureFont::TextureFont(const Renderer *renderer) :
impl(new TextureFontPrivate(renderer)) impl(std::make_unique<TextureFontPrivate>(renderer))
{ {
} }
TextureFont::~TextureFont()
{
delete impl;
}
/** /**
* Render a single character of the font with offset * Render a single character of the font with offset
* *
@ -496,7 +518,8 @@ TextureFont::~TextureFont()
* @param xoffset -- horizontal offset * @param xoffset -- horizontal offset
* @param yoffset -- vertical offset * @param yoffset -- vertical offset
*/ */
float TextureFont::render(wchar_t ch, float xoffset, float yoffset) const float
TextureFont::render(wchar_t ch, float xoffset, float yoffset) const
{ {
return impl->render(ch, xoffset, yoffset); return impl->render(ch, xoffset, yoffset);
} }
@ -511,7 +534,8 @@ float TextureFont::render(wchar_t ch, float xoffset, float yoffset) const
* @param xoffset -- horizontal offset * @param xoffset -- horizontal offset
* @param yoffset -- vertical offset * @param yoffset -- vertical offset
*/ */
float TextureFont::render(const string &s, float xoffset, float yoffset) const float
TextureFont::render(std::string_view s, float xoffset, float yoffset) const
{ {
return impl->render(s, xoffset, yoffset); return impl->render(s, xoffset, yoffset);
} }
@ -524,69 +548,92 @@ float TextureFont::render(const string &s, float xoffset, float yoffset) const
* @param s -- string to calculate width * @param s -- string to calculate width
* @return string width in pixels * @return string width in pixels
*/ */
int TextureFont::getWidth(const string& s) const int
TextureFont::getWidth(std::string_view s) const
{ {
int width = 0; int width = 0;
int len = s.length(); int len = s.length();
bool validChar = true; bool validChar = true;
int i = 0; int i = 0;
while (i < len && validChar) while (i < len && validChar)
{ {
wchar_t ch = 0; wchar_t ch = 0;
validChar = UTF8Decode(s, i, ch); validChar = UTF8Decode(s, i, ch);
if (!validChar) if (!validChar) break;
break;
i += UTF8EncodedSize(ch); i += UTF8EncodedSize(ch);
auto& g = impl->getGlyph(ch, L'?'); auto &g = impl->getGlyph(ch, L'?');
width += g.ax; width += g.ax;
} }
return width; return width;
} }
int TextureFont::getHeight() const /**
* Return line height for the current font as sum of the maximal ascent and the
* maximal descent.
*/
int
TextureFont::getHeight() const
{ {
return impl->m_maxAscent + impl->m_maxDescent; return impl->m_maxAscent + impl->m_maxDescent;
} }
int TextureFont::getMaxWidth() const /**
* Return the maximal character width for the current font.
*/
int
TextureFont::getMaxWidth() const
{ {
return impl->m_maxWidth; return impl->m_maxWidth;
} }
int TextureFont::getMaxAscent() const /**
* Return the maximal ascent for the current font.
*/
int
TextureFont::getMaxAscent() const
{ {
return impl->m_maxAscent; return impl->m_maxAscent;
} }
void TextureFont::setMaxAscent(int _maxAscent) /**
* Set the maximal ascent for the current font.
*/
void
TextureFont::setMaxAscent(int _maxAscent)
{ {
impl->m_maxAscent = _maxAscent; impl->m_maxAscent = _maxAscent;
} }
int TextureFont::getMaxDescent() const /**
* Return the maximal descent for the current font.
*/
int
TextureFont::getMaxDescent() const
{ {
return impl->m_maxDescent; return impl->m_maxDescent;
} }
void TextureFont::setMaxDescent(int _maxDescent) /**
* Set the maximal descent for the current font.
*/
void
TextureFont::setMaxDescent(int _maxDescent)
{ {
impl->m_maxDescent = _maxDescent; impl->m_maxDescent = _maxDescent;
} }
int TextureFont::getTextureName() const /**
{ * Use the current font for text rendering.
return impl->m_texName; */
} void
TextureFont::bind()
void TextureFont::bind()
{ {
auto *prog = impl->getProgram(); auto *prog = impl->getProgram();
if (prog == nullptr) if (prog == nullptr) return;
return;
if (impl->m_texName != 0) if (impl->m_texName != 0)
{ {
@ -594,16 +641,20 @@ void TextureFont::bind()
glBindTexture(GL_TEXTURE_2D, impl->m_texName); glBindTexture(GL_TEXTURE_2D, impl->m_texName);
prog->use(); prog->use();
prog->samplerParam("atlasTex") = 0; prog->samplerParam("atlasTex") = 0;
impl->m_shaderInUse = true; impl->m_shaderInUse = true;
prog->setMVPMatrices(impl->m_projection, impl->m_modelView); prog->setMVPMatrices(impl->m_projection, impl->m_modelView);
} }
} }
void TextureFont::setMVPMatrices(const Eigen::Matrix4f& p, const Eigen::Matrix4f& m) /**
* Assign Projection and ModelView matrices for the current font.
*/
void
TextureFont::setMVPMatrices(const Eigen::Matrix4f &p, const Eigen::Matrix4f &m)
{ {
impl->m_projection = p; impl->m_projection = p;
impl->m_modelView = m; impl->m_modelView = m;
auto *prog = impl->getProgram(); auto *prog = impl->getProgram();
if (prog != nullptr && impl->m_shaderInUse) if (prog != nullptr && impl->m_shaderInUse)
{ {
flush(); flush();
@ -611,29 +662,40 @@ void TextureFont::setMVPMatrices(const Eigen::Matrix4f& p, const Eigen::Matrix4f
} }
} }
void TextureFont::unbind() /**
* Stop the current font usage.
*/
void
TextureFont::unbind()
{ {
flush(); flush();
impl->m_shaderInUse = false; impl->m_shaderInUse = false;
} }
short TextureFont::getAdvance(wchar_t ch) const /**
* Return the advance for the wide character `ch`.
*/
short
TextureFont::getAdvance(wchar_t ch) const
{ {
auto& g = impl->getGlyph(ch, L'?'); auto &g = impl->getGlyph(ch, L'?');
return g.ax; return g.ax;
} }
bool TextureFont::buildTexture() /**
{ * Perform all delayed text rendering operations.
return true; */
} void
TextureFont::flush()
void TextureFont::flush()
{ {
impl->flush(); impl->flush();
} }
TextureFont* TextureFont::load(const Renderer *r, const fs::path &path, int index, int size, int dpi) namespace
{
FT_Face
LoadFontFace(FT_Library ft, const fs::path &path, int index, int size, int dpi)
{ {
FT_Face face; FT_Face face;
@ -646,69 +708,89 @@ TextureFont* TextureFont::load(const Renderer *r, const fs::path &path, int inde
if (!FT_IS_SCALABLE(face)) if (!FT_IS_SCALABLE(face))
{ {
GetLogger()->error("Font is not scalable: {}\n", path); GetLogger()->error("Font is not scalable: {}\n", path);
FT_Done_Face(face);
return nullptr; return nullptr;
} }
if (FT_Set_Char_Size(face, 0, size << 6, dpi, dpi) != 0) if (FT_Set_Char_Size(face, 0, size << 6, dpi, dpi) != 0)
{ {
GetLogger()->error("Could not set font size {}\n", size); GetLogger()->error("Could not set font size {}\n", size);
FT_Done_Face(face);
return nullptr; return nullptr;
} }
auto* font = new TextureFont(r); return face;
font->impl->m_face = face;
if (!font->impl->buildAtlas())
return nullptr;
font->setMaxAscent(face->size->metrics.ascender >> 6);
font->setMaxDescent(-face->size->metrics.descender >> 6);
return font;
} }
// temporary while no fontconfig support // temporary while no fontconfig support
static fs::path ParseFontName(const fs::path &filename, int &collectionIndex, int &size) fs::path
ParseFontName(const fs::path &filename, int &index, int &size)
{ {
// Format with font path/collection index(if any)/font size(if any) // Format with font path/collection index(if any)/font size(if any)
auto fn = filename.string(); auto fn = filename.string();
auto pos = fn.rfind(','); if (auto ps = fn.rfind(','); ps != std::string::npos)
if (pos != string::npos)
{ {
size = (int) stof(fn.substr(pos + 1)); if (from_chars(&fn[ps + 1], &fn[fn.size()], size).ec == std::errc())
auto rest = fn.substr(0, pos);
pos = rest.rfind(',');
if (pos != string::npos)
{ {
collectionIndex = stof(rest.substr(pos + 1)); if (auto pi = fn.rfind(',', ps - 1); pi != std::string::npos)
return rest.substr(0, pos); {
} if (from_chars(&fn[pi + 1], &fn[pi], index).ec == std::errc())
else return fn.substr(0, pi);
{ }
return rest; return fn.substr(0, ps);
} }
} }
else return filename;
{
size = 12;
return filename;
}
} }
std::shared_ptr<TextureFont> LoadTextureFont(const Renderer *r, const fs::path &filename, int index, int size) } // namespace
using FontCache = std::map<fs::path, std::weak_ptr<TextureFont>>;
std::shared_ptr<TextureFont>
LoadTextureFont(const Renderer *r, const fs::path &filename, int index, int size)
{ {
if (ft == nullptr) // Init FreeType library
static FT_Library ftlib = nullptr;
if (ftlib == nullptr && FT_Init_FreeType(&ftlib) != 0)
{ {
if (FT_Init_FreeType(&ft)) GetLogger()->error("Could not init freetype library\n");
return nullptr;
}
// Init FontCache
static FontCache *fontCache = nullptr;
if (fontCache == nullptr)
fontCache = new FontCache;
// Lookup for an existing cached font
std::weak_ptr<TextureFont> &font = (*fontCache)[filename];
std::shared_ptr<TextureFont> ret = font.lock();
if (ret == nullptr)
{
int psize = 12; // default size if missing
int pindex = 0;
auto nameonly = ParseFontName(filename, pindex, psize);
auto face = LoadFontFace(ftlib, nameonly,
index > 0 ? index : pindex,
size > 0 ? size : psize,
r->getScreenDpi());
if (face == nullptr)
return nullptr;
ret = std::make_shared<TextureFont>(r);
ret->impl->m_face = face;
if (!ret->impl->buildAtlas())
{ {
GetLogger()->error("Could not init freetype library\n"); FT_Done_Face(face);
return nullptr; return nullptr;
} }
}
int psize = 0; ret->setMaxAscent(static_cast<int>(face->size->metrics.ascender >> 6));
int pcollectionIndex = 0; ret->setMaxDescent(static_cast<int>(-face->size->metrics.descender >> 6));
auto nameonly = ParseFontName(filename, pcollectionIndex, psize);
return std::shared_ptr<TextureFont>(TextureFont::load(r, nameonly, index > 0 ? index : pcollectionIndex, size > 0 ? size : psize, r->getScreenDpi())); font = ret;
}
return ret;
} }

View File

@ -1,6 +1,6 @@
// truetypefont.h // truetypefont.h
// //
// Copyright (C) 2019, Celestia Development Team // Copyright (C) 2019-2022, Celestia Development Team
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License
@ -9,51 +9,53 @@
#pragma once #pragma once
#include <string>
#include <celcompat/filesystem.h>
#include <Eigen/Core> #include <Eigen/Core>
#include <celcompat/filesystem.h>
#include <string_view>
class Renderer; class Renderer;
class TextureFont;
std::shared_ptr<TextureFont>
LoadTextureFont(const Renderer *, const fs::path &, int index = 0, int size = 0);
struct TextureFontPrivate; struct TextureFontPrivate;
class TextureFont class TextureFont
{ {
TextureFont(const Renderer*);
public: public:
TextureFont(const Renderer *);
TextureFont() = delete; TextureFont() = delete;
~TextureFont(); ~TextureFont() = default;
TextureFont(const TextureFont&) = delete; TextureFont(const TextureFont &) = delete;
TextureFont(TextureFont&&) = delete; TextureFont(TextureFont &&) = delete;
TextureFont& operator=(const TextureFont&) = delete; TextureFont &operator=(const TextureFont &) = delete;
TextureFont& operator=(TextureFont&&) = delete; TextureFont &operator=(TextureFont &&) = delete;
void setMVPMatrices(const Eigen::Matrix4f& p, const Eigen::Matrix4f& m = Eigen::Matrix4f::Identity()); void setMVPMatrices(const Eigen::Matrix4f &p,
const Eigen::Matrix4f &m = Eigen::Matrix4f::Identity());
float render(wchar_t c, float xoffset = 0.0f, float yoffset = 0.0f) const; float render(wchar_t c, float xoffset = 0.0f, float yoffset = 0.0f) const;
float render(const std::string& str, float xoffset = 0.0f, float yoffset = 0.0f) const; float render(std::string_view str, float xoffset = 0.0f, float yoffset = 0.0f) const;
int getWidth(const std::string&) const; int getWidth(std::string_view) const;
int getWidth(int c) const; int getWidth(int c) const;
int getMaxWidth() const; int getMaxWidth() const;
int getHeight() const; int getHeight() const;
int getMaxAscent() const; int getMaxAscent() const;
void setMaxAscent(int); void setMaxAscent(int);
int getMaxDescent() const; int getMaxDescent() const;
void setMaxDescent(int); void setMaxDescent(int);
short getAdvance(wchar_t c) const; short getAdvance(wchar_t c) const;
int getTextureName() const;
void bind(); void bind();
void unbind(); void unbind();
bool buildTexture();
void flush(); void flush();
static TextureFont* load(const Renderer*, const fs::path&, int index, int size, int dpi);
private: private:
TextureFontPrivate *impl; std::unique_ptr<TextureFontPrivate> impl;
};
std::shared_ptr<TextureFont> LoadTextureFont(const Renderer*, const fs::path&, int index = 0, int size = 0); friend std::shared_ptr<TextureFont>
LoadTextureFont(const Renderer*, const fs::path&, int, int);
};

View File

@ -7,6 +7,7 @@
// as published by the Free Software Foundation; either version 2 // as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version. // of the License, or (at your option) any later version.
#include <cassert>
#include <cmath> #include <cmath>
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
@ -15,6 +16,7 @@
// HACK: MS Visual C++ has _snprintf declared in stdio.h but not snprintf // HACK: MS Visual C++ has _snprintf declared in stdio.h but not snprintf
#ifdef _WIN32 #ifdef _WIN32
#include <celutil/winutil.h>
#define snprintf _snprintf #define snprintf _snprintf
#endif #endif
@ -58,9 +60,30 @@ std::ostream& operator<<(std::ostream& out, const FormattedNumber& num)
char obuf[64]; char obuf[64];
int fmtPrecision; int fmtPrecision;
double value = num.getRoundedValue(); double value = num.getRoundedValue();
char *decimal_point = localeconv()->decimal_point; const char *grouping = localeconv()->grouping;
char *thousands_sep = localeconv()->thousands_sep; #ifndef _WIN32
char *grouping = localeconv()->grouping; const char *decimal_point = localeconv()->decimal_point;
const char *thousands_sep = localeconv()->thousands_sep;
#else
static bool initialized = false;
static char decimal_point[8] = {};
static char thousands_sep[8] = {};
if (!initialized)
{
std::string s = CurrentCPToUTF8(localeconv()->decimal_point);
assert(s.length() < 8);
strncpy(decimal_point, s.c_str(), sizeof(decimal_point) - 1);
decimal_point[sizeof(decimal_point) - 1 ] = '\0';
s = CurrentCPToUTF8(localeconv()->thousands_sep);
assert(s.length() < 8);
strncpy(thousands_sep, s.c_str(), sizeof(thousands_sep) - 1);
thousands_sep[sizeof(thousands_sep) - 1] = '\0';
initialized = true;
}
#endif
memset(obuf, 0, sizeof(obuf)); memset(obuf, 0, sizeof(obuf));

View File

@ -15,11 +15,13 @@
#include <cel3ds/3dsread.h> #include <cel3ds/3dsread.h>
#include <celmath/mathlib.h> #include <celmath/mathlib.h>
#include <celutil/logger.h>
#include "cmodops.h" #include "cmodops.h"
#include "convert3ds.h" #include "convert3ds.h"
#include "pathmanager.h" #include "pathmanager.h"
using celestia::util::CreateLogger;
void usage() void usage()
{ {
@ -35,6 +37,8 @@ int main(int argc, char* argv[])
return 1; return 1;
} }
CreateLogger();
std::string inputFileName = argv[1]; std::string inputFileName = argv[1];
std::cerr << "Reading...\n"; std::cerr << "Reading...\n";

View File

@ -1,5 +1,10 @@
if(NOT ENABLE_QT) if(NOT ENABLE_QT)
message("Qt frontend is disabled, not building cmodview.") message("Qt5 frontend is disabled, not building cmodview.")
return()
endif()
if(USE_QT6)
message("Qt tools not supported on Qt6, not building cmodview.")
return() return()
endif() endif()

View File

@ -11,7 +11,9 @@
#include "mainwindow.h" #include "mainwindow.h"
#include <QApplication> #include <QApplication>
#include <QGLFormat> #include <QGLFormat>
#include <celutil/logger.h>
using celestia::util::CreateLogger;
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
@ -51,5 +53,7 @@ main(int argc, char *argv[])
// open events. // open events.
app.installEventFilter(&window); app.installEventFilter(&window);
CreateLogger();
return app.exec(); return app.exec();
} }

View File

@ -363,7 +363,7 @@ joinVertices(std::vector<Face>& faces,
return; return;
// Must have a position // Must have a position
assert(desc.getAttribute(cmod::Mesh::Position).format == cmod::Mesh::Float3); assert(desc.getAttribute(cmod::VertexAttributeSemantic::Position).format == cmod::VertexAttributeFormat::Float3);
std::uint32_t posOffset = desc.getAttribute(cmod::VertexAttributeSemantic::Position).offsetWords; std::uint32_t posOffset = desc.getAttribute(cmod::VertexAttributeSemantic::Position).offsetWords;
const cmod::VWord* vertexPoints = vertexData + posOffset; const cmod::VWord* vertexPoints = vertexData + posOffset;

View File

@ -1,23 +0,0 @@
if(NOT ENABLE_QT)
message("Qt frontend is disabled, not building qttxf.")
return()
endif()
if(APPLE AND EXISTS /usr/local/opt/qt5)
# Homebrew installs Qt5 (up to at least 5.9.1) in
# /usr/local/qt5, ensure it can be found by CMake since
# it is not in the default /usr/local prefix.
list(APPEND CMAKE_PREFIX_PATH "/usr/local/opt/qt5")
endif()
set(QT_LIBS Widgets)
find_package(Qt5 COMPONENTS ${QT_LIBS} CONFIG REQUIRED)
# Instruct CMake to run moc automatically when needed
set(CMAKE_AUTOMOC ON)
# Find includes in corresponding build directories
set(CMAKE_INCLUDE_CURRENT_DIR ON)
add_executable(qttxf WIN32 main.cpp mainwindow.cpp)
install(TARGETS qttxf RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
qt5_use_modules(qttxf ${QT_LIBS})

View File

@ -1,10 +0,0 @@
qttxf is a simple GUI tool for creating bitmap font files for use with
Celestia and other applications. The font files are saved in the TXF format
introduced by Mark Kilgard in his GLUT toolkit.
qttxf is Copyright (C) 2009 by Chris Laurel, and is distributed under the
terms of the GNU General Public License version 2. Please forward comments
and patches to claurel@gmail.com.

View File

@ -1,23 +0,0 @@
// qttxf - a Qt-based application to generate GLUT txf files from
// system fonts
//
// Copyright (C) 2009, Chris Laurel <claurel@gmail.com>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#include <QApplication>
#include "mainwindow.h"
int
main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow window;
window.show();
return app.exec();
}

View File

@ -1,391 +0,0 @@
// qttxf - a Qt-based application to generate GLUT txf files from
// system fonts
//
// Copyright (C) 2009, Chris Laurel <claurel@gmail.com>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#include "mainwindow.h"
#include <QComboBox>
#include <QFontComboBox>
#include <QScrollArea>
#include <QLabel>
#include <QFont>
#include <QDataStream>
#include <QDebug>
#include <QMessageBox>
#include <QFile>
#include <QAction>
#include <QMenuBar>
#include <QMenu>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QFileDialog>
#include <QPainter>
// TXF format constants
const char* TXF_HEADER_BYTES = "\377txf";
const quint32 TXF_ENDIANNESS_TEST = 0x12345678;
MainWindow::MainWindow() :
m_scrollArea(nullptr),
m_imageWidget(nullptr),
m_fontCombo(nullptr),
m_sizeCombo(nullptr),
m_styleCombo(nullptr),
m_saveAction(nullptr)
{
QWidget *centralWidget = new QWidget();
QLabel *fontLabel = new QLabel(tr("Font:"));
m_fontCombo = new QFontComboBox;
QLabel *sizeLabel = new QLabel(tr("Size:"));
m_sizeCombo = new QComboBox;
QLabel *styleLabel = new QLabel(tr("Style:"));
m_styleCombo = new QComboBox;
m_scrollArea = new QScrollArea();
m_imageWidget = new QLabel();
m_scrollArea->setWidget(m_imageWidget);
findStyles(m_fontCombo->currentFont());
findSizes(m_fontCombo->currentFont());
connect(m_fontCombo, SIGNAL(currentFontChanged(const QFont &)),
this, SLOT(findStyles(const QFont &)));
connect(m_fontCombo, SIGNAL(currentFontChanged(const QFont &)),
this, SLOT(findSizes(const QFont &)));
connect(m_fontCombo, SIGNAL(currentFontChanged(const QFont &)),
this, SLOT(updateFont(const QFont &)));
connect(m_sizeCombo, SIGNAL(currentIndexChanged(const QString &)),
this, SLOT(updateSize(const QString &)));
connect(m_styleCombo, SIGNAL(currentIndexChanged(const QString &)),
this, SLOT(updateStyle(const QString &)));
QHBoxLayout *controlsLayout = new QHBoxLayout;
controlsLayout->addWidget(fontLabel);
controlsLayout->addWidget(m_fontCombo, 1);
controlsLayout->addWidget(sizeLabel);
controlsLayout->addWidget(m_sizeCombo, 1);
controlsLayout->addWidget(styleLabel);
controlsLayout->addWidget(m_styleCombo, 1);
QVBoxLayout *centralLayout = new QVBoxLayout();
centralLayout->addLayout(controlsLayout);
centralLayout->addWidget(m_scrollArea, 1);
centralWidget->setLayout(centralLayout);
setCentralWidget(centralWidget);
setWindowTitle("QtTXF");
QMenuBar* menuBar = new QMenuBar(this);
QMenu* fileMenu = new QMenu(tr("File"));
m_saveAction = new QAction(tr("&Save..."), this);
QAction* quitAction = new QAction(tr("&Quit"), this);
fileMenu->addAction(m_saveAction);
fileMenu->addAction(quitAction);
menuBar->addMenu(fileMenu);
setMenuBar(menuBar);
m_saveAction->setShortcut(QKeySequence::Save);
connect(m_saveAction, SIGNAL(triggered()), this, SLOT(saveFont()));
quitAction->setShortcut(QKeySequence("Ctrl+Q"));
connect(quitAction, SIGNAL(triggered()), this, SLOT(close()));
buildTxf();
}
void MainWindow::findStyles(const QFont &font)
{
QFontDatabase fontDatabase;
QString currentItem = m_styleCombo->currentText();
m_styleCombo->clear();
QString style;
foreach (style, fontDatabase.styles(font.family()))
{
m_styleCombo->addItem(style);
}
int styleIndex = m_styleCombo->findText(currentItem);
if (styleIndex == -1)
m_styleCombo->setCurrentIndex(0);
else
m_styleCombo->setCurrentIndex(styleIndex);
}
void MainWindow::findSizes(const QFont &font)
{
QFontDatabase fontDatabase;
QString currentSize = m_sizeCombo->currentText();
m_sizeCombo->blockSignals(true);
m_sizeCombo->clear();
int size;
if (fontDatabase.isSmoothlyScalable(font.family(), fontDatabase.styleString(font)))
{
foreach(size, QFontDatabase::standardSizes())
{
m_sizeCombo->addItem(QVariant(size).toString());
m_sizeCombo->setEditable(true);
}
}
else
{
foreach (size, fontDatabase.smoothSizes(font.family(), fontDatabase.styleString(font)))
{
m_sizeCombo->addItem(QVariant(size).toString());
m_sizeCombo->setEditable(false);
}
}
m_sizeCombo->blockSignals(false);
int sizeIndex = m_sizeCombo->findText(currentSize);
if (sizeIndex == -1)
{
m_sizeCombo->setCurrentIndex(qMax(0, m_sizeCombo->count() / 3));
}
else
{
m_sizeCombo->setCurrentIndex(sizeIndex);
}
}
void
MainWindow::updateFont(const QFont& font)
{
qDebug() << font.family() << " match: " << font.exactMatch();
m_currentFont.setFamily(font.family());
buildTxf();
}
void
MainWindow::updateSize(const QString& sizeString)
{
m_currentFont.setPointSize(sizeString.toInt());
buildTxf();
}
void
MainWindow::updateStyle(const QString& /* styleName */)
{
buildTxf();
}
void
MainWindow::saveFont()
{
if (!m_fontData.isEmpty())
{
QString fileName = QFileDialog::getSaveFileName(this,
tr("Save Font File"),
"",
tr("Texture Fonts (*.txf)"));
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly))
{
QMessageBox::warning(this, tr("File Error"), tr("Error writing to %1").arg(fileName));
return;
}
QDataStream out(&file);
out.writeRawData(m_fontData.data(), m_fontData.length());
file.close();
}
}
struct BasicGlyphInfo
{
QChar ch;
int height;
};
bool operator<(const BasicGlyphInfo& info0, const BasicGlyphInfo& info1)
{
return info0.height > info1.height;
}
bool
MainWindow::buildTxf()
{
// Build a txf font from the current system font. Attempt to fit it into a 128x128
// texture, progressively increasing the texture size until it fits.
bool fitsInTexture = false;
int textureWidth = 128;
int textureHeight = 128;
while (textureWidth <= 1024 && !fitsInTexture)
{
m_fontData.clear();
QDataStream out(&m_fontData, QIODevice::WriteOnly);
if (buildTxf(m_currentFont, out, textureWidth, textureHeight))
{
fitsInTexture = true;
}
if (textureWidth == textureHeight)
textureWidth *= 2;
else
textureHeight *= 2;
}
if (!fitsInTexture)
{
QMessageBox::warning(this,
tr("Font Error"),
tr("Font is too large to fit in texture"));
m_fontData.clear();
}
m_saveAction->setEnabled(fitsInTexture);
return fitsInTexture;
}
QString characterRange(unsigned int firstChar, unsigned int lastChar)
{
QString s;
for (unsigned int i = firstChar; i <= lastChar; ++i)
{
s += QChar(i);
}
return s;
}
bool
MainWindow::buildTxf(const QFont& font, QDataStream& out, int texWidth, int texHeight)
{
QString charset;
charset += characterRange(0x0020, 0x007e); // ASCII
charset += characterRange(0x00a0, 0x00ff); // Latin-1 supplement
charset += characterRange(0x0100, 0x017f); // Latin Extended-A
charset += characterRange(0x0391, 0x03ce); // Greek
QPixmap pixmap(texWidth, texHeight);
QPainter painter(&pixmap);
QVector<BasicGlyphInfo> glyphInfoList;
QFont devFont(font, &pixmap);
QFontMetrics fm(devFont);
for (int i = 0; i < charset.length(); i++)
{
QChar ch = charset[i];
if (fm.inFont(ch))
{
BasicGlyphInfo info;
info.ch = ch;
info.height = fm.boundingRect(ch).height();
glyphInfoList << info;
}
}
// Sort the glyphs by height so that they pack more compactly
// into the available space.
std::sort(glyphInfoList.begin(), glyphInfoList.end());
if (glyphInfoList.isEmpty())
{
return false;
}
// Write txf file header
int maxAscent = 0;
int maxDescent = 0;
out.writeRawData(TXF_HEADER_BYTES, 4);
out << TXF_ENDIANNESS_TEST;
out << (quint32) 0;
out << (quint32) texWidth << (quint32) texHeight;
out << (quint32) maxAscent << (quint32) maxDescent;
out << (quint32) glyphInfoList.size();
// Clear the image
painter.fillRect(0, 0, texWidth, texHeight, Qt::black);
int rowHeight = glyphInfoList.first().height;
int x = 1;
int y = rowHeight;
int xSpacing = 3;
int ySpacing = 3;
painter.setFont(devFont);
foreach (BasicGlyphInfo info, glyphInfoList)
{
QRect bounds = fm.boundingRect(info.ch);
if (x + bounds.width() >= texWidth)
{
y += rowHeight + ySpacing;
rowHeight = bounds.height();
x = 1;
if (y >= texHeight)
{
qDebug() << "Not enough room in font glyph texture.";
return false;
}
}
painter.setPen(Qt::white);
painter.drawText(x - bounds.left(), y - bounds.bottom(), QString(info.ch));
#if 0
// Show bounding rectangles for debugging
painter.setPen(Qt::red);
QRect glyphRect = bounds;
glyphRect.translate(x - bounds.left(), y - bounds.bottom());
painter.drawRect(glyphRect);
#endif
// Write out the glyph record;
out << (quint16) info.ch.unicode();
out << (quint8) (bounds.width() + 2) << (quint8) (bounds.height() + 2);
out << (qint8) bounds.left() << (qint8) (-bounds.bottom());
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
out << (qint8) fm.horizontalAdvance(info.ch);
#else
out << (qint8) fm.width(info.ch);
#endif
out << (quint8) 0; /* unused */
out << (quint16) (x - 1) << (quint16) (texHeight - y - 2);
x += bounds.width() + xSpacing;
}
// Write out the glyph texture map
QImage glyphImage = pixmap.toImage();
for (int iy = 0; iy < texHeight; iy++)
{
for (int ix = 0; ix < texWidth; ix++)
{
QRgb rgb = glyphImage.pixel(ix, texHeight - iy - 1);
out << (quint8) qGreen(rgb);
}
}
QLabel* label = new QLabel(m_scrollArea);
label->setPixmap(pixmap);
m_scrollArea->setWidget(label);
return true;
}

View File

@ -1,54 +0,0 @@
// qttxf - a Qt-based application to generate GLUT txf files from
// system fonts
//
// Copyright (C) 2009, Chris Laurel <claurel@gmail.com>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#ifndef _QTTXF_MAINWINDOW_H_
#define _QTTXF_MAINWINDOW_H_
#include <QMainWindow>
#include <QString>
class QComboBox;
class QFontComboBox;
class QScrollArea;
class QLabel;
class QFont;
class QDataStream;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow();
bool buildTxf();
bool buildTxf(const QFont& font, QDataStream& out, int texWidth, int texHeight);
public slots:
void findStyles(const QFont& font);
void findSizes(const QFont& font);
void updateFont(const QFont& font);
void updateSize(const QString& sizeString);
void updateStyle(const QString& styleName);
void saveFont();
private:
QScrollArea *m_scrollArea;
QLabel* m_imageWidget;
QFontComboBox* m_fontCombo;
QComboBox* m_sizeCombo;
QComboBox* m_styleCombo;
QAction* m_saveAction;
QFont m_currentFont;
QByteArray m_fontData;
};
#endif // _QTTXF_MAINWINDOW_H_

View File

@ -1,15 +0,0 @@
TEMPLATE = app
TARGET = qttxf
QT += widgets
DESTDIR = build
OBJECTS_DIR = build
MOC_DIR = build
HEADERS = \
mainwindow.h
SOURCES = \
mainwindow.cpp \
main.cpp

View File

@ -161,13 +161,13 @@ void printStellarClass(uint16_t sc, ostream& out)
switch (luminosityClass) //without this questionmark a nullchar is written to the file switch (luminosityClass) //without this questionmark a nullchar is written to the file
{ //causing that a dump of stardb is not a textfile but binary. { //causing that a dump of stardb is not a textfile but binary.
case StellarClass::Lum_Ia0: case StellarClass::Lum_Ia0:
out << "I-a0"; out << "Ia-0";
break; break;
case StellarClass::Lum_Ia: case StellarClass::Lum_Ia:
out << "I-a"; out << "Ia";
break; break;
case StellarClass::Lum_Ib: case StellarClass::Lum_Ib:
out << "I-b"; out << "Ib";
break; break;
case StellarClass::Lum_II: case StellarClass::Lum_II:
out << "II"; out << "II";

View File

@ -111,13 +111,13 @@ void printStellarClass(uint16_t sc, ostream& out)
switch (luminosityClass) switch (luminosityClass)
{ {
case StellarClass::Lum_Ia0: case StellarClass::Lum_Ia0:
out << "I-a0"; out << "Ia-0";
break; break;
case StellarClass::Lum_Ia: case StellarClass::Lum_Ia:
out << "I-a"; out << "Ia";
break; break;
case StellarClass::Lum_Ib: case StellarClass::Lum_Ib:
out << "I-b"; out << "Ib";
break; break;
case StellarClass::Lum_II: case StellarClass::Lum_II:
out << "II"; out << "II";

Binary file not shown.

View File

@ -0,0 +1,37 @@
#include <cstdint>
#include <memory>
#include <catch.hpp>
#include <cel3ds/3dsmodel.h>
#include <cel3ds/3dsread.h>
TEST_CASE("Load a 3DS file", "[3ds] [integration]")
{
std::unique_ptr<M3DScene> scene = Read3DSFile("huygens.3ds");
REQUIRE(scene != nullptr);
REQUIRE(scene->getMaterialCount() == 4);
REQUIRE(scene->getModelCount() == UINT32_C(8));
std::uint32_t meshCount = 0;
std::uint32_t faceCount = 0;
std::uint32_t vertexCount = 0;
for (std::uint32_t i = 0; i < scene->getModelCount(); ++i)
{
const M3DModel* model = scene->getModel(i);
REQUIRE(model != nullptr);
meshCount += model->getTriMeshCount();
for (std::uint32_t j = 0; j < model->getTriMeshCount(); ++j)
{
const M3DTriangleMesh* mesh = model->getTriMesh(j);
REQUIRE(mesh != nullptr);
faceCount += static_cast<std::uint32_t>(mesh->getFaceCount());
vertexCount += static_cast<std::uint32_t>(mesh->getVertexCount());
}
}
REQUIRE(meshCount == 8);
REQUIRE(faceCount == 6098);
REQUIRE(vertexCount == 3263);
}

View File

@ -1,4 +1,7 @@
test_case(3ds_load)
test_case(cmod_bin_ascii_roundtrip) test_case(cmod_bin_ascii_roundtrip)
file(COPY "${CMAKE_SOURCE_DIR}/test/data/huygens.3ds"
DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
file(COPY "${CMAKE_SOURCE_DIR}/test/data/iss/models/iss.cmod" file(COPY "${CMAKE_SOURCE_DIR}/test/data/iss/models/iss.cmod"
DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")

View File

@ -1,4 +1,6 @@
test_case(charconv_compat) if(NOT HAVE_FLOAT_CHARCONV)
test_case(charconv_compat)
endif()
test_case(greek) test_case(greek)
test_case(hash) test_case(hash)
test_case(logger) test_case(logger)

View File

@ -1,22 +1,22 @@
#include <celengine/stellarclass.h> #include <cstdint>
#include <catch.hpp> #include <catch.hpp>
#define CHECK_NORMAL_STAR(u, _class, _str) \ #include <celengine/stellarclass.h>
#define CHECK_NORMAL_STAR(u, _class) \
REQUIRE(u.getStarType() == StellarClass::NormalStar); \ REQUIRE(u.getStarType() == StellarClass::NormalStar); \
REQUIRE(u.getSpectralClass() == _class); \ REQUIRE(u.getSpectralClass() == _class); \
REQUIRE(u.getSubclass() == 5); \ REQUIRE(u.getSubclass() == 5); \
REQUIRE(u.getLuminosityClass() == StellarClass::Lum_Ia0); \ REQUIRE(u.getLuminosityClass() == StellarClass::Lum_Ia0);
REQUIRE(u.str() == _str);
#define CHECK_WHITE_DWARF(u, _class, _str) \ #define CHECK_WHITE_DWARF(u, _class) \
REQUIRE(u.getStarType() == StellarClass::WhiteDwarf); \ REQUIRE(u.getStarType() == StellarClass::WhiteDwarf); \
REQUIRE(u.getSpectralClass() == _class); \ REQUIRE(u.getSpectralClass() == _class); \
REQUIRE(u.getSubclass() == 5); \ REQUIRE(u.getSubclass() == 5); \
REQUIRE(u.getLuminosityClass() == StellarClass::Lum_Unknown); \ REQUIRE(u.getLuminosityClass() == StellarClass::Lum_Unknown);
REQUIRE(u.str() == _str);
TEST_CASE("StellarClass", "[StellarClass]") TEST_CASE("StellarClass packing", "[StellarClass]")
{ {
SECTION("StellarClass::Spectral_WO") SECTION("StellarClass::Spectral_WO")
{ {
@ -25,21 +25,21 @@ TEST_CASE("StellarClass", "[StellarClass]")
5, 5,
StellarClass::Lum_Ia0); StellarClass::Lum_Ia0);
uint16_t packed; std::uint16_t packed;
StellarClass u; StellarClass u;
SECTION("Packed as V1") SECTION("Packed as V1")
{ {
packed = sc.packV1(); packed = sc.packV1();
REQUIRE(u.unpackV1(packed)); REQUIRE(u.unpackV1(packed));
CHECK_NORMAL_STAR(u, StellarClass::Spectral_Unknown, "?5 I-a0"); CHECK_NORMAL_STAR(u, StellarClass::Spectral_Unknown);
} }
SECTION("Packed as V2") SECTION("Packed as V2")
{ {
packed = sc.packV2(); packed = sc.packV2();
REQUIRE(u.unpackV2(packed)); REQUIRE(u.unpackV2(packed));
CHECK_NORMAL_STAR(u, StellarClass::Spectral_WO, "W5 I-a0"); CHECK_NORMAL_STAR(u, StellarClass::Spectral_WO);
} }
} }
@ -50,21 +50,21 @@ TEST_CASE("StellarClass", "[StellarClass]")
5, 5,
StellarClass::Lum_Ia0); StellarClass::Lum_Ia0);
uint16_t packed; std::uint16_t packed;
StellarClass u; StellarClass u;
SECTION("Packed as V1") SECTION("Packed as V1")
{ {
packed = sc.packV1(); packed = sc.packV1();
REQUIRE(u.unpackV1(packed)); REQUIRE(u.unpackV1(packed));
CHECK_NORMAL_STAR(u, StellarClass::Spectral_Unknown, "?5 I-a0"); CHECK_NORMAL_STAR(u, StellarClass::Spectral_Unknown);
} }
SECTION("Packed as V2") SECTION("Packed as V2")
{ {
packed = sc.packV2(); packed = sc.packV2();
REQUIRE(u.unpackV2(packed)); REQUIRE(u.unpackV2(packed));
CHECK_NORMAL_STAR(u, StellarClass::Spectral_Y, "Y5 I-a0"); CHECK_NORMAL_STAR(u, StellarClass::Spectral_Y);
} }
} }
@ -75,21 +75,21 @@ TEST_CASE("StellarClass", "[StellarClass]")
5, 5,
StellarClass::Lum_Ia0); StellarClass::Lum_Ia0);
uint16_t packed; std::uint16_t packed;
StellarClass u; StellarClass u;
SECTION("Packed as V1") SECTION("Packed as V1")
{ {
packed = sc.packV1(); packed = sc.packV1();
REQUIRE(u.unpackV1(packed)); REQUIRE(u.unpackV1(packed));
CHECK_NORMAL_STAR(u, StellarClass::Spectral_Unknown, "?5 I-a0"); CHECK_NORMAL_STAR(u, StellarClass::Spectral_Unknown);
} }
SECTION("Packed as V2") SECTION("Packed as V2")
{ {
packed = sc.packV2(); packed = sc.packV2();
REQUIRE(u.unpackV2(packed)); REQUIRE(u.unpackV2(packed));
CHECK_NORMAL_STAR(u, StellarClass::Spectral_Unknown, "?5 I-a0"); CHECK_NORMAL_STAR(u, StellarClass::Spectral_Unknown);
} }
} }
@ -100,21 +100,21 @@ TEST_CASE("StellarClass", "[StellarClass]")
5, 5,
StellarClass::Lum_Ia0); StellarClass::Lum_Ia0);
uint16_t packed; std::uint16_t packed;
StellarClass u; StellarClass u;
SECTION("Packed as V1") SECTION("Packed as V1")
{ {
packed = sc.packV1(); packed = sc.packV1();
REQUIRE(u.unpackV1(packed)); REQUIRE(u.unpackV1(packed));
CHECK_NORMAL_STAR(u, StellarClass::Spectral_C, "C5 I-a0"); CHECK_NORMAL_STAR(u, StellarClass::Spectral_C);
} }
SECTION("Packed as V2") SECTION("Packed as V2")
{ {
packed = sc.packV2(); packed = sc.packV2();
REQUIRE(u.unpackV2(packed)); REQUIRE(u.unpackV2(packed));
CHECK_NORMAL_STAR(u, StellarClass::Spectral_C, "C5 I-a0"); CHECK_NORMAL_STAR(u, StellarClass::Spectral_C);
} }
} }
@ -125,21 +125,21 @@ TEST_CASE("StellarClass", "[StellarClass]")
5, 5,
StellarClass::Lum_Ia0); StellarClass::Lum_Ia0);
uint16_t packed; std::uint16_t packed;
StellarClass u; StellarClass u;
SECTION("Packed as V1") SECTION("Packed as V1")
{ {
packed = sc.packV1(); packed = sc.packV1();
REQUIRE(u.unpackV1(packed)); REQUIRE(u.unpackV1(packed));
CHECK_NORMAL_STAR(u, StellarClass::Spectral_L, "L5 I-a0"); CHECK_NORMAL_STAR(u, StellarClass::Spectral_L);
} }
SECTION("Packed as V2") SECTION("Packed as V2")
{ {
packed = sc.packV2(); packed = sc.packV2();
REQUIRE(u.unpackV2(packed)); REQUIRE(u.unpackV2(packed));
CHECK_NORMAL_STAR(u, StellarClass::Spectral_L, "L5 I-a0"); CHECK_NORMAL_STAR(u, StellarClass::Spectral_L);
} }
} }
@ -151,21 +151,21 @@ TEST_CASE("StellarClass", "[StellarClass]")
5, 5,
StellarClass::Lum_Ia0); StellarClass::Lum_Ia0);
uint16_t packed; std::uint16_t packed;
StellarClass u; StellarClass u;
SECTION("Packed as V1") SECTION("Packed as V1")
{ {
packed = sc.packV1(); packed = sc.packV1();
REQUIRE(u.unpackV1(packed)); REQUIRE(u.unpackV1(packed));
CHECK_NORMAL_STAR(u, StellarClass::Spectral_T, "T5 I-a0"); CHECK_NORMAL_STAR(u, StellarClass::Spectral_T);
} }
SECTION("Packed as V2") SECTION("Packed as V2")
{ {
packed = sc.packV2(); packed = sc.packV2();
REQUIRE(u.unpackV2(packed)); REQUIRE(u.unpackV2(packed));
CHECK_NORMAL_STAR(u, StellarClass::Spectral_T, "T5 I-a0"); CHECK_NORMAL_STAR(u, StellarClass::Spectral_T);
} }
} }
@ -176,22 +176,87 @@ TEST_CASE("StellarClass", "[StellarClass]")
5, 5,
StellarClass::Lum_Ia0); StellarClass::Lum_Ia0);
uint16_t packed; std::uint16_t packed;
StellarClass u; StellarClass u;
SECTION("Packed as V1") SECTION("Packed as V1")
{ {
packed = sc.packV1(); packed = sc.packV1();
REQUIRE(u.unpackV1(packed)); REQUIRE(u.unpackV1(packed));
CHECK_WHITE_DWARF(u, StellarClass::Spectral_DO, "WD"); CHECK_WHITE_DWARF(u, StellarClass::Spectral_DO);
} }
SECTION("Packed as V2") SECTION("Packed as V2")
{ {
packed = sc.packV2(); packed = sc.packV2();
REQUIRE(u.unpackV2(packed)); REQUIRE(u.unpackV2(packed));
CHECK_WHITE_DWARF(u, StellarClass::Spectral_DO, "WD"); CHECK_WHITE_DWARF(u, StellarClass::Spectral_DO);
} }
} }
}
TEST_CASE("StellarClass parsing", "[StellarClass]")
{
SECTION("Luminosity class I-a0")
{
StellarClass sc = StellarClass::parse("A9I-a0");
REQUIRE(sc.getStarType() == StellarClass::NormalStar);
REQUIRE(sc.getSpectralClass() == StellarClass::Spectral_A);
REQUIRE(sc.getSubclass() == 9);
REQUIRE(sc.getLuminosityClass() == StellarClass::Lum_Ia0);
}
SECTION("Luminosity class Ia-0")
{
StellarClass sc = StellarClass::parse("K Ia-0");
REQUIRE(sc.getStarType() == StellarClass::NormalStar);
REQUIRE(sc.getSpectralClass() == StellarClass::Spectral_K);
REQUIRE(sc.getSubclass() == StellarClass::Subclass_Unknown);
REQUIRE(sc.getLuminosityClass() == StellarClass::Lum_Ia0);
}
SECTION("Luminosity class Ia0")
{
StellarClass sc = StellarClass::parse("M3Ia0");
REQUIRE(sc.getStarType() == StellarClass::NormalStar);
REQUIRE(sc.getSpectralClass() == StellarClass::Spectral_M);
REQUIRE(sc.getSubclass() == 3);
REQUIRE(sc.getLuminosityClass() == StellarClass::Lum_Ia0);
}
SECTION("Luminosity class Ia")
{
StellarClass sc = StellarClass::parse("F7Ia");
REQUIRE(sc.getStarType() == StellarClass::NormalStar);
REQUIRE(sc.getSpectralClass() == StellarClass::Spectral_F);
REQUIRE(sc.getSubclass() == 7);
REQUIRE(sc.getLuminosityClass() == StellarClass::Lum_Ia);
}
SECTION("Luminosity class I-a")
{
StellarClass sc = StellarClass::parse("G4 I-a");
REQUIRE(sc.getStarType() == StellarClass::NormalStar);
REQUIRE(sc.getSpectralClass() == StellarClass::Spectral_G);
REQUIRE(sc.getSubclass() == 4);
REQUIRE(sc.getLuminosityClass() == StellarClass::Lum_Ia);
}
SECTION("Luminosity class Ib")
{
StellarClass sc = StellarClass::parse("B6 Ib");
REQUIRE(sc.getStarType() == StellarClass::NormalStar);
REQUIRE(sc.getSpectralClass() == StellarClass::Spectral_B);
REQUIRE(sc.getSubclass() == 6);
REQUIRE(sc.getLuminosityClass() == StellarClass::Lum_Ib);
}
SECTION("Luminosity class I-b")
{
StellarClass sc = StellarClass::parse("O5I-b");
REQUIRE(sc.getStarType() == StellarClass::NormalStar);
REQUIRE(sc.getSpectralClass() == StellarClass::Spectral_O);
REQUIRE(sc.getSubclass() == 5);
REQUIRE(sc.getLuminosityClass() == StellarClass::Lum_Ib);
}
} }