Introduction

Synkro framework consists of multiple interfaces, grouped into several namespaces. These interfaces describe all entities, of which the application consists, like rendering window, virtual scenes, cameras, light sources, visible geometry, etc.

Building a Synkro-based application begins with creating an instance of ISynkro interface, which is done by calling SynkroCreate() function, declared in synkro.h header. Typically, you want to create a class for your application and make ISynkro object one of its properties. This way it can be accessed from event handlers.

ISynkro object is the root of the application functionality. It provides access to all the framework's sub-systems. One of them is the Window system, which enables the programmer to create OS window, which is used as an main output. During Synkro initialization, for each of the created OS windows, a rendering window wrapper is additionally created, which is then used as a rendering target in the applications's main loop.

Once the framework is configured, it's time to launch it. This is done by calling ISynkro::Run() method, which starts the main loop. When this method returns, the application exits. To exit main loop, set "running" parameter of the ISynkro::Run() method to false.

The application can react to various events, happening inside the main loop, by subscribing to them during the initialization stage and handling them at runtime.

The following chapters describe various aspects of the Synkro framework in more detail.

Memory management

Synkro framework has a standard memory manager that enables the developer to detect memory leaks and corruptions. To enable it, use SynkroMemoryInit() macro before calling SynkroCreate() function. After the application exits, memory manager creates memory usage report in the application folder. At runtime, the application can request memory usage details by calling MemoryManager::GetStats() method.

Code profiling

The developer can measure application code performance by means of Synkro code profiler. To enable it, use SynkroProfileInit() macro before calling SynkroCreate() function. After the application exits, the profiler creates memory usage report in the application folder. To identify the code blocks of interest, use SynkroProfile(), SynkroProfileCollapsed(), SynkroProfileBegin() and SynkroProfileEnd() macros.

Language extensions

Synkro framework introduces a set of custom data types, used throughout its classes and interfaces. These types are defined in the lang namespace. The custom data types include exceptions, date and time, base enumeration and flag, point, rectangle, immutable Unicode string, etc. The only template class here is Ptr, which represents a smart pointer to Synkro interface. It's widely used to keep references to application's objects.

Math library

The math namespace contains classes applicable to affine transformations and trigonometry, without which the 3D graphics would be impossible. These classes are vectors, matrices and quaternions.

Core interfaces

The core namespace contains classes and interfaces representing the base for the interfaces in other namespaces. The base for almost all Synkro interfaces is the IObject interface. It provides methods for reference counting that control objects lifetime. The only interfaces that are not derived from IObject are IFactory and IResource because their instances are created statically and exist during the application lifetime.

Sub-systems

The ISynkro interface is derived from the IContext interface, which provides access to all the framework sub-systems. The application should request sub-systems to create the stuff and perform actions it needs. For example, to get access to stream system, call _synkro->GetStreamSystem() method. Further, you can write ->GetStream( "photo.jpg" ) to retrieve IStream object, describing "photo.jpg" image located in the framework's search paths. Or you can call _synkro->GetSceneManager()->CreateScene() to create a virtual scene. All the Synkro sub-systems have similar design, so, once you learn how to use one of them, you instantly learn how to use others.

Configuration

Synkro is a flexible and configurable framework. It uses a set of configuration parameters that the programmer can use to customize application's behavior and select sub-system implementations. For example, the application may choose from either DirectSound or OpenAL as the Audio system implementation. It's possible to configure the framework either programmatically or visually by means of the configuration editor dialog.

IConfiguration interface

Synkro provides access to its default configuration object via _synkro->GetConfiguration(). The default configuration is immutable. To change synkro configuration, you need to clone the default configuration by means of the Clone() method of the IConfiguration interface. Custom configuration can be loaded from io::IStream by means of the Load() method.

Param class

The core::Param class contains symbolic parameter names you can use to override defaults. The following types of configuration parameters are supported: Boolean, Integer, Enum, String. Example: config->Set( core::Param::GraphicsDisplayMode, gfx::DisplayMode::Maximum.Index() ); Once you are done with setting custom configuration parameters, you need to initialize synkro: _synkro->Initialize( config ); During the initialization, Synkro uses Get() methods of the IConfiguration interface to retrieve parameter values and initialize sub-systems as appropriate.

Configuration dialog

Synkro configuration can be edited visually in the special editor. To invoke it, use ISynkro::Configure() method. The editor lists all configuration parameters to the right and allows the user to override them. To the left there is a sample demonstration scene. If the user hits the Run button, it updates configuration and returns true. Hitting Cancel button returns false from the ISynkro::Configure() method.

Factories

Synkro uses Factory pattern to extend its capabilities. Many sub-systems, like graphics system are implemented as plug-ins and so the user can easily switch between plug-in implementations. Available plug-in types are listed in the core::Iface enumeration. The factories are exported from the SynkroLibGetFactory() functions of the Synkro modules.

Modules

Synkro functionality is split into multiple modules. Each sub-system implmentation resides in a separate module, for example 'synkro.gfx.dx11.dll' is the name of the module which contains DirectX11 graphics system.

Error handling

Synkro relies upon the exceptions mechanism to handle errors. The base class for Synkro error is lang::Exception. It has several derived classes in various namespaces. By default, Synkro handles errors that may occur during the initialization and main loop, by displaying Exception dialog box. The user can override this behavior, by deriving application class from SynkroListener and implementing its OnSynkroException() method. For example, you can use Platform::Error() method to show OS-specific error message.

Logging

The application can emit messages (info, warnings and errors) into system log. The log file name is set by Param::LogFileName parameter. To generate rich log file, set Param::LogFilePlain to false. To control the number of messages that are emitted in the log file, use Param::LogLevel. Choose from a set of values from Quiet to Extensive.

Stream system

Synkro uses stream concept (IStream interface) as a means of storing/reading data. To retrieve a stream located in the search paths, use IStreamSystem::GetStream() method. To create a stream use CreateStream() method of stream system or stream directory (IStreamDirectory interface). Synkro can work with compressed directories (zip files). The user can access files inside zip file as if they were located in an ordinary directory, referrring them by file name.

Stream sets

Sometimes, several files are related to each other (for example, image files, representing the sides of a cube map). In such a case the files have similar names. To retrieve such files as a collection, use one of the IStreamDirectory::GetStreams() method overloads. Example: _dir->GetStreams( L"SkyBox*.bmp" );

Imaging

Images are one of the most widely-used resources in Synkro. They are represented by img::IImage interface. The user can load an image from stream using the IImageManager::LoadImage() method. This method allows loading image in its actual format, or converting it to a certain img::PixelFormat. To load image asynchronously, use IImageManager::LoadImageAsync() method. The supported image formats are described by the img::ImageCodec enumeration.

Colors

Synkro provides a set of named constants (more than a thousand) that represent various color tints. They can be used to elegantly specify material, light or text color. These constants as well as some handy methods are stored in the img::Color class, which uses RGB color model.

Visual materials

The mat namespace contains definitions of materials, which are used to create visible geometry in the scene namespace. Materials are created by material manager (mat::IMaterialManager interface). The are several types of materials in Synkro: simple (like IOpaqueMaterial) and complex (IMultiMaterial). Multi-material is used with multi-subset geometry.

Window system

Application windows serve as the host for all the other stuff that exists in the application. It's always the programmer's responsibility to create host windows. The are three kinds of windows in synkro: frame window (win::IFrameWindowEx), view window (win::IViewWindowEx) and icon window (win::IIconWindow).

To create non-sizeable main window with a frame, 800 pixels wide and 600 pixels tall, write: _synkro->GetWindowSystem()->CreateWindow( false, false, L"Synkro application", 0, 800, 600 );

To create a 400x300 window within a frame window (win::IViewWindowEx interface), use the following code: _synkro->GetWindowSystem()->CreateWindow( _frameWindow, 0, 0, 400, 300 );

To create a window, bound to a tray icon, write: _synkro->GetWindowSystem()->CreateWindow( 0, L"Synkro application" );

To retrieve main window, write: _synkro->GetWindowSystem()->GetFrameWindow( 0 );

Input system

To receive user input, the application needs to enable input (Param::InputEnable) and choose input system implementation (Param::InputSystem).

Input devices

Synkro supports the following input devices: Physical: keyboard (input::IKeyboard), mouse (input::IMouse), joystick (input::IJoystick), and logical: Arcball (input::IArcball). To initialize certain type of input device, the application needs to call a create method. For example, to initialize primary keyboard, use the following code: _synkro->GetInputSystem()->CreateKeyboard( 0 );

Input events

Synkro allows applications to subscribe to specific input devices events. To make it possible, the application class needs to implement a specific listener interface. For example, to intercept 'key up' events for the Space key, write: _synkro->GetInputSystem()->GetKeyboard( 0 )->ListenKeyUp( this, Key::Space ); // Here 'this' implements KeyboardListener.

The corresponding event handler looks like this:

Bool App::OnKeyboardKeyUp( UInt device, const Key& key, Bool alt, Bool shift, Bool control )
{
	if ( key == Key::Space )
	{
		// TODO: Process event.

		return true; // Signal to Synkro the event is processed
	}

	return false;
}

Audio playback

To be able to playback sounds, the application needs to enable audio (Param::AudioEnable) and choose audio system implementation (Param::AudioSystem). Then create an audio device:
_synkro->GetAudioSystem()->CreatePlayer( 0 ); This device will be used by sound manager (sound::ISoundManager). To load 2D sound from stream, use the following code:
_synkro->GetSoundManager()->LoadSound2D( stream ); To start loaded sound playback, write: sound->Play( true );

Viewports

Viewport is a rectangular area inside application window where a scene is drawn. Frame window can have arbitrary number of viewports, while view window always has one. Viewports are created by calling one of the overloads of the IViewportManager::CreateViewport() method. A viewport is essentially a wrapper around the gfx::IRenderView interface.

Viewport filters

The image drawn in a view can be post-processed. This is done by creating viewport filters. Available filter types are listed in the view::ViewportFilter enumeration. To create a filter, use IViewport::CreateFilter() method.

Viewport transitions

The user can apply transition effects to viewports, for example 'Fade to black'. Available transition effects are listed in the view::TransitionEffect enumeration. To create a transition effect, write:
_synkro->GetViewportManager()->CreateTransitionController( this ); Where 'this' is an instance of ViewportListener class.

Picking mesh

To pick triangle mesh under the cursor, use view::IViewport::PickMesh() method. If there is a mesh under the cursor, this method returns a pointer to it. Otherwise, it returns nullptr.

Overlays

Each rendering window has an overlay that is capable of displaying sprites and texts.

Sprites pools and text pools

Such pools use a single texture resource to display multiple sprites and texts.

Fonts and texts

Synkro's overlay manager (over::IOverlayManager) allows creating font templates and then using them to create text objects.

Graphical user interface

Synkro allows the user to create user interface for their applications via ui::IUiEx interface. The UI consists of various widgets, which are the descedents of ui::IWidget interface. The widgets exist inside frames (ui::IFrame). The following widgets are available: IAngle, IButton, IDropList, IEdit, IList, IOption, IProgress, ISlider, ISwitch, ILabel, IPicture.

UI events

To intercept UI widgets events, the application class must implement UiListener interface and call Listen() on IUiEx, like this:
_synkro->GetUi()->Listen( this ); // Here 'this' implements UiListener. After that, the application can implement OnUiClick, OnUiDoubleClick and OnUiValueChanged methods. If the application processes an event, it must return true from these methods.

Scene management

To access scene manager, use the following code:
_synkro->GetSceneManager();

Scenes

Synkro scene is the 3D virtual environment. It can contain cameras, light sources and visible geometry. To create a scene, use CreateScene() method, like this:
_synkro->GetSceneManager()->CreateScene( L"World", DebugMode::Node, true );

Cameras

The camera defines the point in the 3D space where the viewer is placed. The camera is associated with the viewport (view::IViewport).

Light sources

If the 'lit' parameter of the CreateScene() method is true, the application can call ISceneEx methods that create light sources: CreateOmniLight(), CreateConeLight() and CreateDirectLight().

Meshes

The application can create 3 types of mesh: point (scene::IPointMesh), line (scene::ILineMesh) and triangle (scene::ITriangleMesh). A triangle mesh can be loaded from stream using ISceneEx::LoadMesh() method. The available mesh files formats are listed in the scene::MeshCodec enumeration.

Mesh builders

The application fill in empty mesh with geometric primitive, like this:
_synkro->GetSceneManager()->BuildMesh( mesh, type, param1, param2, transform );
The available mesh types are listed in the scene::MeshBuilder enumeration.

Animations

Many Synkro objects can be animated. Namely, if a specific interface has CreateAnimationController() method, most of its properties can be changed over time with either keyframed or procedural animation. The animation playback is started with IController::Start( true ) call.

Recording animations

If some interface has CreateRecordController() method, then its properties that change over time can be saved to IAnimationSet object.