Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //vec4 ~= struct {x,y,z,w} ; vec3 ~= struct {x, y, z} ; etc
- //I32 = int, U8 = unsigned byte, etc
- //vectorImpl = std::vector with custom allocator
- //minSquareMatrixSize = computes the smallest NxN matrix that holds the specified number of elements. Returns N
- // mainViewport = the main game viewport (e.g. 0, 0, 1920, 1080)
- // targetViewports = will hold the resulting 'count' viewports in the format (xOffset, yOffset, playerWidth, playerHeight)
- // count = the number of viewports to split the main view into
- void computeViewports(const vec4<I32>& mainViewport, vectorImpl<vec4<I32>>& targetViewports, U8 count) {
- assert(count > 0);
- I32 xOffset = mainViewport.x;
- I32 yOffset = mainViewport.y;
- I32 width = mainViewport.z;
- I32 height = mainViewport.w;
- targetViewports.resize(0);
- if (count == 1) { //Single Player
- targetViewports.push_back(mainViewport);
- return;
- } else if (count == 2) { //Split Screen
- I32 halfHeight = height / 2;
- targetViewports.emplace_back(xOffset, halfHeight + yOffset, width, halfHeight);
- targetViewports.emplace_back(xOffset, 0 + yOffset, width, halfHeight);
- return;
- }
- // Basic idea (X - viewport):
- // Odd # of players | Even # of players
- // X X | X X
- // X | X X
- // |
- // X X X | X X X
- // X X | X X X
- // etc
- // Always try to match last row with previous one
- // If they match, move the first viewport from the last row
- // to the previous row and add a new entry to the end of the
- // current row
- typedef vectorImpl<vec4<I32>> ViewportRow;
- typedef vectorImpl<ViewportRow> ViewportRows;
- ViewportRows rows;
- // Allocates storage for a N x N matrix of viewports that will hold numViewports
- // Returns N;
- auto resizeViewportContainer = [&rows](U32 numViewports) {
- //Try to fit all viewports into an appropriately sized matrix.
- //If the number of resulting rows is too large, drop empty rows.
- //If the last row has an odd number of elements, center them later.
- U8 matrixSize = to_ubyte(minSquareMatrixSize(numViewports));
- rows.resize(matrixSize);
- std::for_each(std::begin(rows), std::end(rows), [matrixSize](ViewportRow& row) { row.resize(matrixSize); });
- return matrixSize;
- };
- // Remove extra rows and columns, if any
- U8 columnCount = resizeViewportContainer(count);
- U8 extraColumns = (columnCount * columnCount) - count;
- U8 extraRows = extraColumns / columnCount;
- for (U8 i = 0; i < extraRows; ++i) {
- rows.pop_back();
- }
- U8 columnsToRemove = extraColumns - (extraRows * columnCount);
- for (U8 i = 0; i < columnsToRemove; ++i) {
- rows.back().pop_back();
- }
- U8 rowCount = to_ubyte(rows.size());
- // Calculate and set viewport dimensions
- // The number of columns is valid for the width;
- I32 playerWidth = width / columnCount;
- // The number of rows is valid for the height;
- I32 playerHeight = height / to_int(rowCount);
- for (U8 i = 0; i < rowCount; ++i) {
- ViewportRow& row = rows[i];
- I32 playerYOffset = playerHeight * (rowCount - i - 1);
- for (U8 j = 0; j < to_ubyte(row.size()); ++j) {
- I32 playerXOffset = playerWidth * j;
- row[j].set(playerXOffset, playerYOffset, playerWidth, playerHeight);
- }
- }
- //Slide the last row to center it
- if (extraColumns > 0) {
- ViewportRow& lastRow = rows.back();
- I32 screenMidPoint = width / 2;
- I32 rowMidPoint = to_int((lastRow.size() * playerWidth) / 2);
- I32 slideFactor = screenMidPoint - rowMidPoint;
- for (vec4<I32>& viewport : lastRow) {
- viewport.x += slideFactor;
- }
- }
- // Update the system viewports
- for (const ViewportRow& row : rows) {
- for (const vec4<I32>& viewport : row) {
- targetViewports.push_back(viewport);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement