OpenSceneGraph: Aus Quelle und Hello World erstellen

  • Tutorial


Einleitung


OpenSceneGraph (im Folgenden: OSG) ist ein in C ++ geschriebenes offenes Cross-Plattform-Framework und eine grafische Engine, die dem Programmierer eine Objektschnittstelle für OpenGL zur Verfügung stellt. In unserem Land ist dieser Motor nicht besonders beliebt, selbst auf Habré habe ich nur eine mehr oder weniger anständige Veröffentlichung darüber gesehen . OSG wird häufig im Ausland eingesetzt, wo es beispielsweise die Grundlage für den kostenlosen FlightGear -Flugsimulator bildet. Es gibt eine offene Implementierung des Spiels Morrowind, genannt OpenMW, dessen Entwicklung ebenfalls von der Ogre- Engine an OSG übertragen wird . Die russischsprachige Dokumentation ist verschwindend klein und unter den englischsprachigen Autoren kann nur eine Reihe von Büchern von Entwicklern erwähnt werden: OpenSceneGraph 3.0. Anfängerhandbuchund OpenSceneGraph 3. Kochbuch .

Trotzdem ist der Motor aus folgenden Gründen sehr interessant:

  1. Offene plattformübergreifende Implementierung in C ++.
  2. Modulare Architektur
  3. Erweiterbarkeit durch eingebautes Plugin-System.
  4. Die Möglichkeit der Multithread-Verarbeitung von Grafikdaten und integrierten Tools für deren Implementierung
  5. Dynamische Speicherverwaltung über einen intelligenten Zeigermechanismus

Ich denke, dass Habrs Leser Interesse haben werden, sich mit diesem Projekt vertraut zu machen. Nicht überflüssig sein und die Vervollständigung der russischsprachigen Wissensdatenbank zu OSG. Alle Materialien, die von mir zu diesem Thema veröffentlicht werden, basieren auf dem Buch OpenSceneGraph 3.0. Beginner's Guide , aber nicht die Übersetzung, sondern die kreative Verarbeitung des dort präsentierten Materials. Wenn Sie sich für dieses Thema interessieren, wenden Sie sich bitte an die Katze.

Die einzig sichere Möglichkeit, die neueste Version von OSG auf Ihrem Computer zu erhalten, besteht darin, eine Bibliothek aus dem Quellcode zu erstellen. Das vorhandene binäre Installationsprogramm für Windows ist auf den MS Visual C ++ - Compiler ausgerichtet. Für meine Projekte muss ich den GCC-Compiler bzw. die MinGW32-Version verwenden, die im Lieferumfang der Qt-Framework-Entwicklungstools enthalten ist. Daher brauchen wir:

  1. Qt-Framework installiert und konfiguriert mit MinGW32-Compiler Version 5.3 und IDE QtCreator
  2. Git- Client für Windows
  3. Dienstprogramm für Windows erstellen

Es wird vorausgesetzt, dass der Leser mit der QtCreator-IDE und dem in Qt-Projekten verwendeten qmake-Build-System vertraut ist. Außerdem wird davon ausgegangen, dass der Leser mit den Grundlagen der Verwendung des Git-Versionskontrollsystems vertraut ist und grundsätzlich Programmierkenntnisse besitzt, die nicht Null sind.

1. Abrufen des OpenSceneGraph-Quellcodes


Erstellen Sie auf Ihrer Festplatte ein Verzeichnis, in dem Sie OSG erstellen, beispielsweise unter dem Pfad D: \ OSG.



Wir gehen in dieses Verzeichnis und ziehen die Quelldateien aus dem offiziellen OSG-Repository auf Github

D:\OSG> git clone https://github.com/openscenegraph/OpenSceneGraph.git

Die Dauer des Downloadvorgangs hängt davon ab, wie breit Ihr Internetzugangskanal ist. Früher oder später erhalten wir eine lokale Kopie des OSG-Repositorys.

Nach dem Download der Quellen erstellen wir eine Reihe von Verzeichnissen build-win32-debug



, in denen das OSG-Debugging-Kit erstellt wird. Aber vorher

2. Konfigurieren Sie cmake


Damit cmake korrekt funktioniert, müssen wir die Datei install-cmake \ share \ cmake-3.13 \ Modules \ CMakeMinGWFindMake.cmake bearbeiten . Standardmäßig sieht es so aus.

# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying# file Copyright.txt or https://cmake.org/licensing for details.find_program(CMAKE_MAKE_PROGRAM mingw32-make.exe PATHS
  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MinGW;InstallLocation]/bin"
  c:/MinGW/bin /MinGW/bin
  "[HKEY_CURRENT_USER\\Software\\CodeBlocks;Path]/MinGW/bin"
  )
find_program(CMAKE_SH sh.exe )
if(CMAKE_SH)
  message(FATAL_ERROR "sh.exe was found in your PATH, here:\n${CMAKE_SH}\nFor MinGW make to work correctly sh.exe must NOT be in your path.\nRun cmake from a shell that does not have sh.exe in your PATH.\nIf you want to use a UNIX shell, then use MSYS Makefiles.\n")
  set(CMAKE_MAKE_PROGRAM NOTFOUND)
endif()
mark_as_advanced(CMAKE_MAKE_PROGRAM CMAKE_SH)

Lassen Sie uns einige Zeilen auskommentieren, damit das Dienstprogramm nicht versucht, nach unserer Unix-Shell im System zu suchen, und wenn es nicht gefunden wird, endet es mit einem Fehler

# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying# file Copyright.txt or https://cmake.org/licensing for details.find_program(CMAKE_MAKE_PROGRAM mingw32-make.exe PATHS
  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MinGW;InstallLocation]/bin"
  c:/MinGW/bin /MinGW/bin
  "[HKEY_CURRENT_USER\\Software\\CodeBlocks;Path]/MinGW/bin"
  )
#find_program(CMAKE_SH sh.exe )#if(CMAKE_SH)#  message(FATAL_ERROR "sh.exe was found in your PATH, here:\n${CMAKE_SH}\nFor MinGW make to work correctly sh.exe must NOT be in your path.\nRun cmake from a shell that does not have sh.exe in your PATH.\nIf you want to use a UNIX shell, then use MSYS Makefiles.\n")#  set(CMAKE_MAKE_PROGRAM NOTFOUND)#endif()mark_as_advanced(CMAKE_MAKE_PROGRAM CMAKE_SH)

3. Erstellen und Installieren von Debug- und Release-Versionen der Engine


Nun die cmd Shell ausgeführt, ein Etikett , das auf dem Weg ist , um Start-> Programme-> QT-> Qt 5.11.2-> Qt 5.11.2 für Desktop (MinGW 5.3.0 32bit)



gestartet Eingabeaufforderung die gesamte Umgebung setzt , die für werkzeugmontage mingw32. In das OSG-Quellverzeichnis wechseln

C:\Qt\Qt5.11.2\5.11.2\mingw53_32>D:
D:\> cd OSG\build-win32-debug

Gib einen Befehl

D:\OSG\build-win32-debug>cmake -G "MinGW Makefiles" -DCMAKE_INSTALL_PREFIX=E:\Apps\OSG -DCMAKE_BUILD_TYPE=DEBUG ../OpenSceneGraph

Lassen Sie uns die Bedeutung der Parameter genauer analysieren:

  • -G "MinGW Makefiles" - Gibt an, dass Sie ein Makefile für das Dienstprogramm mingw32-make erstellen müssen
  • -DCMAKE_INSTALL_PREFIX = E: \ Apps \ OSG - Legen Sie den Pfad fest, auf dem OSG installiert wird
  • -DCMAKE_BUILD_TYPE = DEBUG - Gibt an, dass die Debugversion der Engine erstellt werden soll.

Beim Ausführen des Befehls wird die Bereitschaft der Umgebung für die Assembly geprüft, das Assemblyskript und der nächste Auslass generiert

Lassen Sie beim Einrichten einer OSG-Baugruppe Auspuff aus
-- The C compiler identification is GNU 5.3.0-- The CXX compiler identification is GNU 5.3.0-- Check for working C compiler: C:/Qt/Qt5.11.2/Tools/mingw530_32/bin/gcc.exe-- Check for working C compiler: C:/Qt/Qt5.11.2/Tools/mingw530_32/bin/gcc.exe -- works-- Detecting C compiler ABI info-- Detecting C compiler ABI info - done-- Detecting C compile features-- Detecting C compile features - done-- Check for working CXX compiler: C:/Qt/Qt5.11.2/Tools/mingw530_32/bin/g++.exe-- Check for working CXX compiler: C:/Qt/Qt5.11.2/Tools/mingw530_32/bin/g++.exe -- works-- Detecting CXX compiler ABI info-- Detecting CXX compiler ABI info - done-- Detecting CXX compile features-- Detecting CXX compile features - done-- Looking for pthread.h-- Looking for pthread.h - found-- Looking for pthread_create-- Looking for pthread_create - found-- Found Threads: TRUE-- Found OpenGL: opengl32-- Could NOT find EGL (missing: EGL_INCLUDE_DIR)-- Checking windows version...-- Performing Test GL_HEADER_HAS_GLINT64-- Performing Test GL_HEADER_HAS_GLINT64 - Failed-- Performing Test GL_HEADER_HAS_GLUINT64-- Performing Test GL_HEADER_HAS_GLUINT64 - Failed-- 32 bit architecture detected-- Could NOT find Freetype (missing: FREETYPE_LIBRARY FREETYPE_INCLUDE_DIRS)-- Could NOT find JPEG (missing: JPEG_LIBRARY JPEG_INCLUDE_DIR)-- Could NOT find Jasper (missing: JASPER_LIBRARIES JASPER_INCLUDE_DIR JPEG_LIBRARIES)-- Could NOT find LibXml2 (missing: LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR)-- Could NOT find ZLIB (missing: ZLIB_INCLUDE_DIR)-- Could NOT find ZLIB (missing: ZLIB_INCLUDE_DIR)-- Could NOT find GDAL (missing: GDAL_LIBRARY GDAL_INCLUDE_DIR)-- Could NOT find PkgConfig (missing: PKG_CONFIG_EXECUTABLE)-- Could NOT find CURL (missing: CURL_LIBRARY CURL_INCLUDE_DIR)-- Trying to find DCMTK expecting DCMTKConfig.cmake-- Trying to find DCMTK expecting DCMTKConfig.cmake - failed-- Trying to find DCMTK relying on FindDCMTK.cmake-- Please set DCMTK_DIR and re-run configure (missing: DCMTK_config_INCLUDE_DIR DCMTK_dcmdata_INCLUDE_DIR DCMTK_dcmimage_INCLUDE_DIR DCMTK_dcmimgle_INCLUDE_DIR DCMTK_dcmjpeg_INCLUDE_DIR DCMTK_dcmjpls_INCLUDE_DIR DCMTK_dcmnet_INCLUDE_DIR DCMTK_dcmpstat_INCLUDE_DIR DCMTK_dcmqrdb_INCLUDE_DIR DCMTK_dcmsign_INCLUDE_DIR DCMTK_dcmsr_INCLUDE_DIR DCMTK_dcmtls_INCLUDE_DIR DCMTK_ofstd_INCLUDE_DIR DCMTK_oflog_INCLUDE_DIR)-- Could NOT find PkgConfig (missing: PKG_CONFIG_EXECUTABLE)-- Could NOT find GStreamer (missing: GSTREAMER_INCLUDE_DIRS GSTREAMER_LIBRARIES GSTREAMER_VERSION GSTREAMER_BASE_INCLUDE_DIRS GSTREAMER_BASE_LIBRARIES GSTREAMER_APP_INCLUDE_DIRS GSTREAMER_APP_LIBRARIES GSTREAMER_PBUTILS_INCLUDE_DIRS GSTREAMER_PBUTILS_LIBRARIES) (found version "")-- Could NOT find SDL2 (missing: SDL2_LIBRARY SDL2_INCLUDE_DIR)-- Could NOT find SDL (missing: SDL_LIBRARY SDL_INCLUDE_DIR)-- Could NOT find PkgConfig (missing: PKG_CONFIG_EXECUTABLE)-- Could NOT find PkgConfig (missing: PKG_CONFIG_EXECUTABLE)-- Could NOT find PkgConfig (missing: PKG_CONFIG_EXECUTABLE)-- Could NOT find JPEG (missing: JPEG_LIBRARY JPEG_INCLUDE_DIR)-- Could NOT find ZLIB (missing: ZLIB_INCLUDE_DIR)-- Could NOT find PNG (missing: PNG_LIBRARY PNG_PNG_INCLUDE_DIR)-- Could NOT find TIFF (missing: TIFF_LIBRARY TIFF_INCLUDE_DIR)-- g++ version 5.3.0-- Performing Test _OPENTHREADS_ATOMIC_USE_GCC_BUILTINS-- Performing Test _OPENTHREADS_ATOMIC_USE_GCC_BUILTINS - Success-- Performing Test _OPENTHREADS_ATOMIC_USE_MIPOSPRO_BUILTINS-- Performing Test _OPENTHREADS_ATOMIC_USE_MIPOSPRO_BUILTINS - Failed-- Performing Test _OPENTHREADS_ATOMIC_USE_SUN-- Performing Test _OPENTHREADS_ATOMIC_USE_SUN - Failed-- Performing Test _OPENTHREADS_ATOMIC_USE_WIN32_INTERLOCKED-- Performing Test _OPENTHREADS_ATOMIC_USE_WIN32_INTERLOCKED - Success-- Performing Test _OPENTHREADS_ATOMIC_USE_BSD_ATOMIC-- Performing Test _OPENTHREADS_ATOMIC_USE_BSD_ATOMIC - Failed-- Configuring done-- Generating done-- Build files have been written to: D:/OSG/build-win32-debug



sagt uns, dass Sie mit der Montage fortfahren können. Gib einen Befehl

D:\OSG\build-win32-debug>mingw32-make -j9

Sie können wie in meinem Beispiel die Anzahl der Threads der Assembly angeben, wenn Sie einen Multi-Core-Prozessor (-j-Schalter) haben. Der Build-Vorgang beginnt auf meinem Computer und dauert etwa acht Minuten.



Nachdem der Build abgeschlossen ist, installieren Sie die Bibliothek

D:\OSG\build-win32-debug> mingw32-make install

Nachdem wir den Befehl ausgeführt haben, finden wir die Bibliothek mit dem Pfad, den



wir im Voraus festgelegt haben, installiert. Jetzt werden wir die Release-Version der Engine zusammenstellen, indem wir ein anderes Build-Verzeichnis erstellen

D:\OSG\build-win32-debug>cd ..
D:\OSG> mkdir build-win32-release
D:\OSG>cd build-win32-release
D:\OSG\build-win32-release> cmake -G "MinGW Makefiles" -DCMAKE_INSTALL_PREFIX=E:\Apps\OSG ../OpenSceneGraph
D:\OSG\build-win32-release> mingw32-make -j9
D:\OSG\build-win32-release> mingw32-make install

4. Umgebungsvariablen einstellen


Der Speicherort der OSG-Bibliotheken nach der Installation kann beliebig sein. Er wird von den Wünschen eines bestimmten Benutzers und seinen Möglichkeiten zum Ablegen von Dateien auf dem Computer bestimmt. Wenn Sie ein bestimmtes Projekt einrichten, das die gegebene Bibliothek verwendet, müssen Sie dabei eine gewisse Vereinheitlichung anstreben, indem Sie vom jeweiligen Speicherort der Bibliotheken abgrenzen.

Erstellen Sie mehrere Systemumgebungsvariablen, die die Pfade zu Bibliotheken, Header-Dateien und OSG-Plugins angeben. In meinem Beispiel wird es so aussehen.



Sie müssen Variablen erstellen, deren Namen im Screenshot rot eingekreist sind. Nachdem Sie eine Variable erstellen, um sichtbar Entwicklungs - Tools, insbesondere QtCreator-ten Bedarf zumindest das System abzuzumelden (Ausfahrt und im Namen des aktuellen Benutzers gehen), oder das System neu starten kann (dies ist von Windows!)

Nach dieser Installation OSG auf unserem Computer kann als abgeschlossen betrachtet werden.

5. Hello World in QtCreator schreiben


Die Vertrautheit mit der Grafik-Engine OpenSceneGraph beginnt mit dem einfachsten Beispiel, wie es bei der Programmierung mit einigen "Hallo Welt!" Üblich ist.

Bevor Sie Code schreiben, richten Sie unser Projekt für das qmake-Build-System ein, das wir während des gesamten Artikelzyklus verwenden werden. Erstellen Sie im für uns interessanten Dateisystempfad die folgende Verzeichnisstruktur

OSG-lessons/
	|-data/|-OSG-lessons/||-hello/|-include/|-src/

Erstellen Sie im Verzeichnis hallo eine Datei hello.pro mit folgendem Inhalt

Volltext hello.pro
TEMPLATE = app
TARGET = hello
DESTDIR = ../../bin
win32 {
    OSG_LIB_DIRECTORY = $$(OSG_BIN_PATH)
    OSG_INCLUDE_DIRECTORY = $$(OSG_INCLUDE_PATH)
    CONFIG(debug, debug|release) {
        TARGET = $$join(TARGET,,,_d)
        LIBS += -L$$OSG_LIB_DIRECTORY -losgd
        LIBS += -L$$OSG_LIB_DIRECTORY -losgViewerd
        LIBS += -L$$OSG_LIB_DIRECTORY -losgDBd
        LIBS += -L$$OSG_LIB_DIRECTORY -lOpenThreadsd
    } else {
        LIBS += -L$$OSG_LIB_DIRECTORY -losg
        LIBS += -L$$OSG_LIB_DIRECTORY -losgViewer
        LIBS += -L$$OSG_LIB_DIRECTORY -losgDB
        LIBS += -L$$OSG_LIB_DIRECTORY -lOpenThreads
    }
    INCLUDEPATH += $$OSG_INCLUDE_DIRECTORY
}
unix {
    CONFIG(debug, debug|release) {
        TARGET = $$join(TARGET,,,_d)
        LIBS += -losgd
        LIBS += -losgViewerd
        LIBS += -losgDBd
        LIBS += -lOpenThreadsd
    } else {
        LIBS +=  -losg
        LIBS +=  -losgViewer
        LIBS +=  -losgDB
        LIBS +=  -lOpenThreads
    }
}
INCLUDEPATH += ./include
HEADERS += $$files(./include/*.h)
SOURCES += $$files(./src/*.cpp)

Разберем эти письме подробнее

TEMPLATE = app
TARGET = hello
DESTDIR = ../../bin


Variablen definieren die Projektvorlage (App), den Namen der ausführbaren Datei (Hallo) und das Verzeichnis, in dem sich die ausführbare Datei nach dem Zusammenfügen befindet.


win32 {
    OSG_LIB_DIRECTORY = $$(OSG_BIN_PATH)
    OSG_INCLUDE_DIRECTORY = $$(OSG_INCLUDE_PATH)
    CONFIG(debug, debug|release) {
        TARGET = $$join(TARGET,,,_d)
        LIBS += -L$$OSG_LIB_DIRECTORY -losgd
        LIBS += -L$$OSG_LIB_DIRECTORY -losgViewerd
        LIBS += -L$$OSG_LIB_DIRECTORY -losgDBd
        LIBS += -L$$OSG_LIB_DIRECTORY -lOpenThreadsd
    } else {
        LIBS += -L$$OSG_LIB_DIRECTORY -losg
        LIBS += -L$$OSG_LIB_DIRECTORY -losgViewer
        LIBS += -L$$OSG_LIB_DIRECTORY -losgDB
        LIBS += -L$$OSG_LIB_DIRECTORY -lOpenThreads
    }
    INCLUDEPATH += $$OSG_INCLUDE_DIRECTORY
}

Abhängig vom Betriebssystem, in dem das Projekt zusammengestellt ist, definieren wir Variablen, die die Pfade zu den Verzeichnissen von Bibliotheken und OSG-Header-Dateien angeben. Hier bieten sich die Umgebungsvariablen OSG_BIN_PATH und OSG_INCLUDE_PATH an. Jetzt ist es egal, wo die OSG-Bibliothek installiert ist. Jeder, der mit diesem Projekt auf seinem Computer arbeiten möchte, registriert einfach die entsprechenden Umgebungsvariablen in seinem System, ohne das Build-Skript zu bearbeiten.


CONFIG(debug, debug|release) {
    TARGET = $$join(TARGET,,,_d)
    LIBS += -L$$OSG_LIB_DIRECTORY -losgd
    LIBS += -L$$OSG_LIB_DIRECTORY -losgViewerd
    LIBS += -L$$OSG_LIB_DIRECTORY -losgDBd
    LIBS += -L$$OSG_LIB_DIRECTORY -lOpenThreadsd
} else {
    LIBS += -L$$OSG_LIB_DIRECTORY -losg
    LIBS += -L$$OSG_LIB_DIRECTORY -losgViewer
    LIBS += -L$$OSG_LIB_DIRECTORY -losgDB
    LIBS += -L$$OSG_LIB_DIRECTORY -lOpenThreads
}

Wir schreiben das Skript für die Montage in einem Unix-ähnlichen Betriebssystem


unix {
    CONFIG(debug, debug|release) {
        TARGET = $$join(TARGET,,,_d)
        LIBS += -losgd
        LIBS += -losgViewerd
        LIBS += -losgDBd
        LIBS += -lOpenThreadsd
    } else {
        LIBS +=  -losg
        LIBS +=  -losgViewer
        LIBS +=  -losgDB
        LIBS +=  -lOpenThreads
    }
}

Hier passen wir den Namen der ausführbaren Datei an und geben die Bibliotheken an, die mit unserem Programm für verschiedene Build-Optionen verknüpft werden sollen: sowohl Debug als auch Release. OSG-Debugbibliotheken haben nach dem Dateinamen das Suffix "d". Das Suffix "_d" wird der ausführbaren Datei des Projekts hinzugefügt, um die Debugversion von der Releaseversion zu unterscheiden.

INCLUDEPATH += $$OSG_INCLUDE_DIRECTORY
INCLUDEPATH += ./include
HEADERS += $$files(./include/*.h)
SOURCES += $$files(./src/*.cpp)

Zum Schluss definieren wir die Suchpfade für Header-Dateien und Dateien, die in der Projektnavigation enthalten sind. Erstellen Sie die Datei main.h im Verzeichnis include / und die Datei main.cpp im Verzeichnis src /. Öffnen Sie dieses Projekt in QtCreator und richten Sie es wie in der Abbildung gezeigt ein:



Nach dem Öffnen des Projekts sehen Sie folgendes Bild:



Wir schreiben diesen Code in die Datei main.h.

#ifndef		MAIN_H#define		MAIN_H#include<osgDB/ReadFile>#include<osgViewer/Viewer>#endif

Als Nächstes implementieren wir den Hauptteil des Programms in der Datei main.cpp.

#include"main.h"intmain(int argc, char *argv[]){
    (void) argc;
    (void) argv;
    osg::ref_ptr<osg::Node> root = osgDB::readNodeFile("../data/cessna.osg");
    osgViewer::Viewer viewer;
    viewer.setSceneData(root.get());
    return viewer.run();
}

Die Datei mit dem Flugmodell muss in das Verzeichnis data / kopiert werden. Diese Datei sowie ein Großteil der in dieser Artikelserie verwendeten Elemente können Sie aus dem Repository von OpenSceneGraph-Data herunterladen .

Nach dem Kompilieren und Ausführen erhalten Sie so etwas wie



die ersten beiden Zeilen unseres Codes

	
(void) argc;
(void) argv;

kennzeichnen Sie die Eingabeparameter der Funktion main () als nicht verwendet, um die Compiler-Warnung zu vermeiden. Als Nächstes erstellen Sie einen Stammknoten der Szene, der das Modell des Flugzeugs ist, das aus der Datei cessna.osg geladen wird

osg::ref_ptr<osg::Node> root = osgDB::readNodeFile("../data/cessna.osg");

Dann wird eine Instanz der Klasse osgViewer :: Viewer erstellt - der sogenannte "Viewer" - ein Objekt, das die Anzeige der Szene auf dem Bildschirm steuert. Szenendaten werden an den Betrachter übertragen.

	
viewer.setSceneData(root.get());

und die Szene-Rendering-Schleife beginnt

return viewer.run();

Dieser grundlegende Code enthält bereits einige grundlegende Konzepte, die in OSG verwendet werden. Aber darüber zu reden, wird etwas später gehen.

Fazit


Der vollständige Quellcode der nachfolgend beschriebenen Beispiele kann hier erhalten werden . Ich hoffe, dass diese Publikation die Leser interessiert, um fortgesetzt zu werden ...

Jetzt auch beliebt: