PS2 Linux Programming

 

Dual View with Split Screen

 

Introduction

 

This tutorial illustrates the implementation of a split screen, dual view configuration which can be found in many game applications. The effect is produced by creating two 3D graphics pipelines, one for rendering to the top of the screen, the other for rendering to the bottom of the screen. The scissoring feature of the Graphics Synthesiser is also used to block out rendering to one half of the screen, whist the other half is being drawn to. The racing car demo is used in order to illustrate the technique in operation, with the top half of the screen being rendered from the perspective of the AI car and the bottom half from the perspective of the user controlled car.

 

 

Technical Details

 

Each object in the scene must be rendered twice, once for each of the two views. Each view will have a different camera position, and the location of the rendering within the frame buffer will also be different, so two separate graphics pipelines are required, one for each view. Looking at main.cpp it can be seen that tow pipeline instances are created, one for the top and one for the bottom of the screen.

 

 

// 3D pipline classes for top and bottom views

CPipeline PipelineTop, PipelineBot;

 

 

Each pipeline class must be initialised to reflect the characteristics of the part of the screen that is being rendered to. The different pipeline configuration is achieved by passing a parameter (0 or 1) into the CPipeline::Initialise() method, 0 for the top and 1 for the bottom of the screen.

 

 

PipelineTop.Initialise(0);

PipelineBot.Initialise(1);

 

 

Within the CPipeline::Initialise() method the input parameter is used to set the appropriate centre point for the rendering area:

 

 

if(Split == 0)

     m_Scale = Vector4(2048.0f, 2048.0f-128.0f, ((float)0xFFFFFF) / 32.0f, 0.0f);

    

if(Split == 1)

     m_Scale = Vector4(2048.0f, 2048.0f+128.0f, ((float)0xFFFFFF) / 32.0f, 0.0f);

 

 

The second (y) parameter within the scale vector is the important one in this context. In PAL mode the screen in 512 high so the centre of rendering for the top portion of the screen is 128 up from the centre of the screen, and the centre of rendering for the bottom portion of the screen is 128 down for the centre of the screen. All of the other parameters within the scale vector remain as before.

 

The only other class variable that requires alteration within the CPipline class is the aspect ratio for the screen. Instead of being the normal 4:3 aspect it changed to 8:3 to reflect the new dimensions of the render area.

 

 

m_Aspect = 4.0f / 3.0f * 2.0f;

 

 

Within the application, the lighting, camera position, etc for each of the pipelines is initially configured then updated as required within the game loop. Notice also, that the rendering method for the CMs3dModel class has been altered to take the pipeline class that is to be used for rendering as a parameter.

 

 

Scissoring within the Graphics Synthesiser is used to create a window which will be used for rendering, all pixels outside this scissor area will be left untouched by the rendering process. The scissor area is set by configuring the SCISSOR register within the GS. The scissor register takes four parameters:

 

 

SCAX0 – x coordinate of upper left point of enabled drawing area.

SCAX1 – x coordinate of lower right point of enabled drawing area.

SCAy0 – y coordinate of upper left point of enabled drawing area.

SCAy1 – y coordinate of lower right point of enabled drawing area.

 

 

Scissoring is accomplished by sending the appropriate data to the SCISSOR register in Direct mode, using the Address + Data mode (AD). This is accomplished using the following code for the bottom of the screen:

 

 

// Set scissor area for bottom of screen

VIFDynamicDMA.StartDirect();

VIFDynamicDMA.StartAD();

VIFDynamicDMA.AddAD(SCISSOR_SET(0, 640, 256, 512), SCISSOR_1);

VIFDynamicDMA.EndAD();

VIFDynamicDMA.EndDirect();

 

 

And for the top of the screen:

 

 

// Set scissor area for top of screen

VIFDynamicDMA.StartDirect();

VIFDynamicDMA.StartAD();

VIFDynamicDMA.AddAD(SCISSOR_SET(0, 640, 0, 256), SCISSOR_1);

VIFDynamicDMA.EndAD();

VIFDynamicDMA.EndDirect();

 

 

Note that the parameters in the SCISSOR_SET macro are in the order:

 

 

SCISSOR_SET(SCAX0, SCAX1, SCAY0, SCAY1)

 

 

Also note that the parameters of SCISSOR_SET are in frame buffer (or screen) coordinates measured relative to the top left hand corner of the screen.

 

 

The Example Code

 

Rendering of the split screen configuration is described using the following game loop pseudo code:

 

 

Set camera/pipeline matrices for top view

Set camera/pipeline matrices for bottom view

 

Set scissor area for bottom view

Render all objects

 

Set scissor area for top view

Render all objects

 

 

Notice that each object must be rendered twice, once for each view.

 

 

Running The Applications

 

On running the application, a split screen view of a racing track is obtained. The top view provided a perspective from the AI car with the bottom view looking at the user controlled car. The user controlled car can be manipulated and moved using the control pad as in previous applications.

 

 

Conclusions

 

 

Dr Henry S Fortuna

University of Abertay Dundee

h.s.fortuna@abertay.ac.uk