Programming
Fundamentals
Setting Up Development Environment
UnigineScript
C++
C#
UUSL (Unified UNIGINE Shader Language)
File Formats
Rebuilding the Engine and Tools
GUI
Double Precision Coordinates
API
Containers
Common Functionality
Controls-Related Classes
Engine-Related Classes
Filesystem Functionality
GUI-Related Classes
Math Functionality
Node-Related Classes
Networking Functionality
Pathfinding-Related Classes
Physics-Related Classes
Plugins-Related Classes
Rendering-Related Classes

Running Syncker with AppProjection

If computers connected via Syncker use projectors instead of monitors to render an application, it is required to use the AppProjection plugin, which enables to configure the created projections over LAN.

See Also

Script Implementation

  1. Set a fixed FPS value to make simulations consistent across all computers and initialize Syncker in the script running on the master computer. Also you should initialize a console to allow running master command-line options.
    Source code (UnigineScript)
    int init() {
    	
    	engine.game.setFTime(1.0f / 60.0f);
    	Unigine::Syncker::Master::Console::init();
    	Unigine::Syncker::Master::init(master_address);
    	
    	return 1;
    }
  2. In the init() function, create a world: add nodes, implement interaction logic, etc.
  3. Get names of the slaves and add them to the interface of the Projection panel. It will allow you to choose the slave, whose projection should be configured from the master computer.

    The master should also be added to the interface of the Projection panel. It will allow you to clear the projection configuration on the master computer after configuring of the slaves' projections.

    Notice
    You should implement this logic in the init() function of the world script.
    Source code (UnigineScript)
    engine.system.call("projectionClearAuxiliary");
    // add the master to the Projection panel interface
    engine.system.call("projectionAddAuxiliaryItem","Master");
    forloop(int i = 0; Unigine::Syncker::Master::getNumSlaves()) {
    	string name = Unigine::Syncker::Master::getSlaveName(i);
    	string address = Unigine::Syncker::Master::getSlaveAddress(i);
    	engine.system.call("projectionAddAuxiliaryItem",format("%s (%s)",name,address));
    }
  4. Set custom callback functions in the init() function of the world script.
    Notice
    The wallSetChangedWorldCallback() and projectionSetChangedWorldCallback() functions are specified in the wall.h and projection.h scripts respectively and receive the identifiers of the custom callback functions.
    Source code (UnigineScript)
    engine.system.call("wallSetChangedWorldCallback",functionid(my_wall_changed_callback));
    engine.system.call("projectionSetChangedWorldCallback",functionid(my_projection_changed_callback));
  5. Implement the custom callback function my_wall_changed_callback(), which has been set in the previous step and will be invoked when the Bezel X and Bezel Y settings are changed in the Wall tab.
    Notice
    The wallGetBezelX(), wallGetBezelY(), wallSetBezelX(), wallSetBezelY() functions are defined in the data/core/scripts/system/wall.h script.
    Source code (UnigineScript)
    void my_wall_changed_callback() {
    	
    	// get the currently changed values of bezel parameters
    	float bezel_x = engine.system.call("wallGetBezelX");
    	float bezel_y = engine.system.call("wallGetBezelY");
    	// set this values as current for all of the slaves via the system script functions
    	Unigine::Syncker::Master::systemCall(~0,"wallSetBezelX",(bezel_x));
    	Unigine::Syncker::Master::systemCall(~0,"wallSetBezelY",(bezel_y));
    }
    Another way to set the changed values is to run the slave_bezel console command from the script on each slave.
    Notice
    Use the code below instead of calling the wallSetBezelX() and wallSetBezelY() functions.
    Source code (UnigineScript)
    // run the slave_bezel console command on all of the slaves to update their bezel compensation 
    Unigine::Syncker::Master::systemCall(~0,"engine.console.run",(format("slave_bezel %f %f",bezel_x,bezel_y)));
  6. Implement the my_projection_changed_callback() callback function, which has been set in the step 3 and will be invoked when you change the projection settings on the Projection panel:
    Notice
    The system script functions called below are defined in the data/core/scripts/system/projection.h file.
    Source code (UnigineScript)
    void my_projection_changed_callback() {
    	
    	// update grid mode if it was changed
    	if(engine.system.call("projectionGetActivity")) {
    		int mode = engine.system.call("projectionGetGridMode");
    		int step = engine.system.call("projectionGetGridStep");
    		Unigine::Syncker::Master::systemCall(~0,"projectionSetGrid",(mode,step));
    	} else {
    		Unigine::Syncker::Master::systemCall(~0,"projectionClearGrid",());
    	}
    		
    	// update projection parameters for the chosen projection
    	int item = engine.system.call("projectionGetAuxiliaryItem");
    	if (item != 0) {
    		int mask = 1 << (item - 1);
    		Buffer buffer = new Buffer();
    		engine.projection.saveState(class_cast(classid(Stream),buffer));
    		// restore the state of the slave display
    		Unigine::Syncker::Master::systemStream(mask,"engine.projection.restoreState",buffer);
    		delete buffer;
    	}
    	
    }
  7. Implement logic, which allows loading the world for all of the slaves on the master side, and call it in the init() function after the Syncker initialization.
    Notice
    You can skip this step and load the world on each slave individually via the console.
    Source code (UnigineScript)
    void sync_world() {
    	
    	// load slave world
    	Unigine::Syncker::Master::systemCall(~0,"engine.console.run",("world_load " + engine.world.getName()));
    		
    	// waiting for the slave world
    	int ret[0];
    	float begin = clock();
    		
    	while(clock() - begin < 2.0f) {
    		int is_loaded = 1;
    		Unigine::Syncker::Master::systemCall(~0,"engine.world.isLoaded",(),ret);
    		foreach(int i = 0; ret) is_loaded &= i;
    		if(is_loaded) break;
    	}
    }
  8. Implement shut down logic for the console and Syncker, clear the slaves' names and system script callbacks:
    Source code (UnigineScript)
    int shutdown() {
    
    	// clear slaves' names
    	engine.system.call("projectionClearAuxiliary");
    		
    	// clear system script callbacks
    	engine.system.call("wallSetChangedWorldCallback",NULL);
    	engine.system.call("projectionSetChangedWorldCallback",NULL);
    	
    	// quit the slave world
    	Unigine::Syncker::Master::systemCall(~0,"engine.console.run",("world_quit"));
    	
    	// Shut down the console
    	Unigine::Syncker::Master::Console::shutdown();
    	
    	// shutdown Syncker
    	Unigine::Syncker::Master::shutdown();
    		
    	return 1;
    }
  9. Implement synchronization logic in the render() function.
    Source code (UnigineScript)
    int render() {
    	
    	// synchronize frame
    	Unigine::Syncker::Master::syncFrame();
    	
    	// synchronize player
    	Unigine::Syncker::Master::syncPlayer();
    	
    	// synchronize render
    	Unigine::Syncker::Master::syncRender();
    	
    	// synchronize end
    	Unigine::Syncker::Master::syncEnd();
    	
    	return 1;
    }

If you use the same world script on the master and slave sides, you need to wrap your code around with #ifndef DEFINE_NAME ... #else ... #endif as follows to separate the script logic:

Notice
The DEFINE_NAME should be specified on the application start-up.
Source code (UnigineScript)
#include <core/unigine.h>

// logic to run on the master
#ifndef DEFINE_NAME

	#include <core/systems/syncker/syncker_master.h>
	#include <core/systems/syncker/syncker_master_console.h>
	
	// init() function defined above
	// shutdown() functions defined above
	// render() function defined above
	// implementation of the custom callback functions
	
#else

	// logic to run on a slave
	int init() {

		// slave logic implementation
	
		return 1;
	}
	
#endif

Running Project

To run Syncker with the AppProjection plugin, perform the following:

  1. On the slave application start-up, override a default editor script with the Syncker script for slaves, activate the AppProjection plugin and specify the PROJECTION_USER and DEFINE_NAME definitions:
    Notice
    Do not forget to add the other required start-up arguments.
    Shell commands
    main_x86 -data_path "../" -editor_script "core/systems/syncker/syncker_slave.cpp" -extern_plugin "AppProjection" -extern_define "PROJECTION_USER,DEFINE_NAME" -console_command "editor_reload"
    The editor_reload console command is required to load the Syncker script for slaves.

    The PROJECTION_USER definition is used to avoid overwriting the camera configuration by the core/scripts/system/wall.h script. It disables the Wall::render() function and allows you to configure slave projections manually.

  2. Run the application on the master computer
    Shell commands
    main_x86 -data_path "../" -extern_plugin "AppProjection" -console_command ""world_load unigine_project/unigine_project"
  3. Change the broadcasting network address of the master:
    Source code
    master_address xxx.xxx.xxx.xxx
    And reload the world by using the world_reload console option.

Configuring Projections

By default all computers project the same screen as a master computer. So, after launching your application on the master and slave computers, you need to configure a viewport of each slave depending on the required screen configuration and then adjust each projection.

Changing Screen Configuration

For example, if you have 3 slave computers that project the application onto the curved screen, you should perform the following:

  1. First, set a projection configuration on the master side via the master_grid console command:
    Source code
    master_grid 3 1
  2. Set the same configuration for all slaves:
    Source code
    master_run slave_grid 3 1
  3. On each slave, run the slave_view console option with the corresponding arguments to set the number of the projection:

    • For the left projection:
      Source code
      slave_view  0 0
    • For the central projection:
      Source code
      slave_view  1 0
    • For the right projection:
      Source code
      slave_view  2 0
    Notice
    You can also set the projection number by specifying the -slave_view_x command-line option with the required value on the start-up of each slave.

    To check the current viewport configuration of all the slaves, type the master_view console option on the master side.

  4. On each slave computer, run the following console command to set the required turning angle compensation :
    Source code
    slave_angle <angle_value>
    Notice
    You can also set the turning angle compensation by specifying the -slave_angle command-line option with the required value on the start-up of each slave.
  5. Set bezel compensation for all of the slaves, for example:
    Source code
    master_bezel 0.2 0
    You can set the bezel compensation for each slave individually via its console by using the slave_bezel console option.
    Notice
    You can also adjust the bezel compensation values in the Wall tab of the main menu, if you implemented the corresponding logic in the script.

Changing Projections

When the viewports of the slaves are configured, you can adjust each projection from the master computer via the Projection panel.

Notice
You can change the slave and master projections only if you have implemented the corresponding callback function in the script.
  1. On the master computer, call the main menu by pressing the Esc button, go to the Wall tab and press the Projection button to open the Projection panel.
  2. In the lower left corner of the Projection panel, choose the slave, whose projection need to be configured:

  3. Adjust the projection of the chosen slave and press the Save button. Then specify a name of the projection and press OK. Your projection configuration will be saved in the *.projection file.
    Notice
    When you change the slave projection, the projection on the master computer is also changed. To clear the projection configuration on the master computer, perform the following after saving the slave projection into the file:
    1. In the lower left corner, choose the Master from the drop-down menu.
    2. Press the Clear button.
    3. In the dialog box that opens, press the OK button.

If you have saved all of the required projection configurations, you can load them at the next application start:

  1. On the master computer, open the Projection panel.
  2. Choose the slave, for which you want to load the projection.
  3. Press the Load button and choose one of the *.projection files.
  4. Press OK.
Notice
It is recommended to clear the projection settings on the master computer before changing the projection of the next slave. For more details, see the previous Notice.
Last update: 2017-07-03