Advertisement
IonutCava

Multiple equally sized viewports

Jan 17th, 2017
116
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.05 KB | None | 0 0
  1. //vec4 ~= struct {x,y,z,w} ; vec3 ~= struct {x, y, z} ; etc
  2. //I32 = int, U8 = unsigned byte, etc
  3. //vectorImpl = std::vector with custom allocator
  4. //minSquareMatrixSize = computes the smallest NxN matrix that holds the specified number of elements. Returns N
  5.  
  6. // mainViewport = the main game viewport (e.g. 0, 0, 1920, 1080)
  7. // targetViewports = will hold the resulting 'count' viewports in the format (xOffset, yOffset, playerWidth, playerHeight)
  8. // count = the number of viewports to split the main view into
  9.  
  10. void computeViewports(const vec4<I32>& mainViewport, vectorImpl<vec4<I32>>& targetViewports, U8 count) {
  11.    
  12.     assert(count > 0);
  13.     I32 xOffset = mainViewport.x;
  14.     I32 yOffset = mainViewport.y;
  15.     I32 width = mainViewport.z;
  16.     I32 height = mainViewport.w;
  17.  
  18.     targetViewports.resize(0);
  19.     if (count == 1) { //Single Player
  20.         targetViewports.push_back(mainViewport);
  21.         return;
  22.     } else if (count == 2) { //Split Screen
  23.         I32 halfHeight = height / 2;
  24.         targetViewports.emplace_back(xOffset, halfHeight + yOffset, width, halfHeight);
  25.         targetViewports.emplace_back(xOffset, 0 + yOffset,          width, halfHeight);
  26.         return;
  27.     }
  28.  
  29.     // Basic idea (X - viewport):
  30.     // Odd # of players | Even # of players
  31.     // X X              |      X X
  32.     //  X               |      X X
  33.     //                  |
  34.     // X X X            |     X X X
  35.     //  X X             |     X X X
  36.     // etc
  37.     // Always try to match last row with previous one
  38.     // If they match, move the first viewport from the last row
  39.     // to the previous row and add a new entry to the end of the
  40.     // current row
  41.  
  42.     typedef vectorImpl<vec4<I32>> ViewportRow;
  43.     typedef vectorImpl<ViewportRow> ViewportRows;
  44.     ViewportRows rows;
  45.  
  46.     // Allocates storage for a N x N matrix of viewports that will hold numViewports
  47.     // Returns N;
  48.     auto resizeViewportContainer = [&rows](U32 numViewports) {
  49.         //Try to fit all viewports into an appropriately sized matrix.
  50.         //If the number of resulting rows is too large, drop empty rows.
  51.         //If the last row has an odd number of elements, center them later.
  52.         U8 matrixSize = to_ubyte(minSquareMatrixSize(numViewports));
  53.         rows.resize(matrixSize);
  54.         std::for_each(std::begin(rows), std::end(rows), [matrixSize](ViewportRow& row) { row.resize(matrixSize); });
  55.  
  56.         return matrixSize;
  57.     };
  58.  
  59.     // Remove extra rows and columns, if any
  60.     U8 columnCount = resizeViewportContainer(count);
  61.     U8 extraColumns = (columnCount * columnCount) - count;
  62.     U8 extraRows = extraColumns / columnCount;
  63.     for (U8 i = 0; i < extraRows; ++i) {
  64.         rows.pop_back();
  65.     }
  66.     U8 columnsToRemove = extraColumns - (extraRows * columnCount);
  67.     for (U8 i = 0; i < columnsToRemove; ++i) {
  68.         rows.back().pop_back();
  69.     }
  70.  
  71.     U8 rowCount = to_ubyte(rows.size());
  72.  
  73.     // Calculate and set viewport dimensions
  74.     // The number of columns is valid for the width;
  75.     I32 playerWidth = width / columnCount;
  76.     // The number of rows is valid for the height;
  77.     I32 playerHeight = height / to_int(rowCount);
  78.  
  79.     for (U8 i = 0; i < rowCount; ++i) {
  80.         ViewportRow& row = rows[i];
  81.         I32 playerYOffset = playerHeight * (rowCount - i - 1);
  82.         for (U8 j = 0; j < to_ubyte(row.size()); ++j) {
  83.             I32 playerXOffset = playerWidth * j;
  84.             row[j].set(playerXOffset, playerYOffset, playerWidth, playerHeight);
  85.         }
  86.     }
  87.  
  88.     //Slide the last row to center it
  89.     if (extraColumns > 0) {
  90.         ViewportRow& lastRow = rows.back();
  91.         I32 screenMidPoint = width / 2;
  92.         I32 rowMidPoint = to_int((lastRow.size() * playerWidth) / 2);
  93.         I32 slideFactor = screenMidPoint - rowMidPoint;
  94.         for (vec4<I32>& viewport : lastRow) {
  95.             viewport.x += slideFactor;
  96.         }
  97.     }
  98.  
  99.     // Update the system viewports
  100.     for (const ViewportRow& row : rows) {
  101.         for (const vec4<I32>& viewport : row) {
  102.             targetViewports.push_back(viewport);
  103.         }
  104.     }
  105. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement