/*---------------------------------------------------------------------------* Project: Horizon File: gx_CaptureUtil.cpp Copyright (C)2009-2012 Nintendo Co., Ltd. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Rev: 46365 $ *---------------------------------------------------------------------------*/ #include /* Decompose the perspective projection matrix. Assume input from the matrix generated by CTR-SDK MATH. */ void GetProjectionParameters( nn::math::Matrix44* proj, f32* left, f32* right, f32* bottom, f32* top, f32* near, f32* far) { // Reverse calculate, assuming that the perspective projection matrix that was input takes CTR clip coordinates into account. *near = proj->m[2][3] / proj->m[2][2]; *far = proj->m[2][3] / (proj->m[2][2] - 1.0f); f32 tmp = proj->m[2][3] / (proj->m[0][0] * proj->m[2][2]); *left = tmp * (proj->m[0][2] - 1.0f); *right = tmp * (proj->m[0][2] + 1.0f); tmp = proj->m[2][3] / (proj->m[1][1] * proj->m[2][2]); *top = tmp * (proj->m[1][2] + 1.0f); *bottom = tmp * (proj->m[1][2] - 1.0f); } /* Please see man pages for details */ void GetProjectionForPartialCapture(nn::math::Matrix44* pOut, nn::math::Matrix44* proj, s32 div, s32 indexV, s32 indexH, const f32 dist, nn::math::PivotDirection pivot) { (void)dist; NN_NULL_ASSERT(pOut); NN_NULL_ASSERT(proj); NN_ASSERT( 0 <= indexV || 0 <= indexH || indexV < div || indexH < div); NN_ASSERT( nn::math::PIVOT_NONE <= pivot || pivot <= nn::math::PIVOT_NUM ); const f32 divH = static_cast(div); const f32 divV = static_cast(div); // Reverse-calculate the arguments from the perspective projection matrix that was input. Calculate and return the projection matrix used to display the specified magnification and index position on the full screen. // f32 near, far, top, bottom, left, right; GetProjectionParameters( proj, &left, &right, &bottom, &top, &near, &far); // Find the arguments for the specified division f32 partLeft, partRight, partTop, partBottom; partLeft = (static_cast(indexH)/divH * right + (divH - static_cast(indexH))/divH * left); partRight = (static_cast(indexH + 1)/divH * right + (divH - static_cast(indexH + 1))/divH * left); partTop = (static_cast(indexV)/divV * bottom + (divV - static_cast(indexV))/divV * top); partBottom = (static_cast(indexV + 1)/divV * bottom + (divV - static_cast(indexV + 1))/divV * top); // NN_SLOG_("calc: left:%lf, right:%lf, bottom:%lf, top:%lf, near:%lf, far:%lf\n", partLeft, partRight, partBottom, partTop, near, far); nn::math::MTX44FrustumPivot(pOut, partLeft, partRight, partBottom, partTop, near, far, pivot); } /* Please see man pages for details */ int SaveDisplayBufferSD(const wchar_t *dirname, const wchar_t *filename, u32 index, GLuint addr, const u32 width, const u32 height, u8 *work = NULL) { static wchar_t *sdname = L"sdmc:/"; static wchar_t *exname = L".bmp"; // BMP Header static u8 bh[54]={ 0x42,0x4D,0x04,0x03,0x02,0x00,0x00,0x00, 0x00,0x00,0x36,0x00,0x00,0x00,0x28,0x00, 0x00,0x00,0x80,0x02,0x00,0x00,0xE0,0x01, 0x00,0x00,0x01,0x00,0x18,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00 }; NN_NULL_ASSERT( dirname ); NN_NULL_ASSERT( filename ); NN_ASSERT( 0 < width || width <= nn::gx::DISPLAY0_WIDTH ); NN_ASSERT( 0 < height || height <= nn::gx::DISPLAY0_HEIGHT); u8 linebuf[nn::gx::DISPLAY0_HEIGHT * 3]; u8 *data; int i, j; nn::Result result; // Check whether SD Card is being used for (i = 0; i < 6; ++i) { if (dirname[i] != sdname[i]) return(-1); } // Checks whether a directory was specified. If so, try to create directory. if (dirname[i]) { result = nn::fs::TryCreateDirectory(dirname); } // Create a file path wchar_t *path; path = reinterpret_cast(linebuf); for (i = 0; i < 245; ++i) { if (dirname[i] == 0) break; path[i] = dirname[i]; } if (path[i-1] != '/') { path[i++] = '/'; } for (j = 0; i < 246; i++, j++) { if (filename[j] == 0 ) break; path[i] = filename[j]; } path[i ] = (index/10000) + 48; index %= 10000; path[i+1] = (index/1000 ) + 48; index %= 1000; path[i+2] = (index/100 ) + 48; index %= 100; path[i+3] = (index/10 ) + 48; path[i+4] = (index%10 ) + 48; i += 5; for (j = 0; j < 5; i++, j++) { path[i] = exname[j]; } nn::fs::FileOutputStream fos; result = fos.TryInitialize(path, true); if (result.IsFailure()) { return(-2); } // Create a BMP header { u32 xpad; xpad = ( 4 - ((width * 3) & 3) ) & 3; i = 54 + width * height * 3 + xpad * height; // File size. bh[ 2] = static_cast(i); bh[ 3] = static_cast(i >> 8); bh[ 4] = static_cast(i >> 16) & 255; // Image size (width and height are reversed to accommodate LCD arrangement) bh[18] = static_cast(height); bh[19] = static_cast(height >> 8); bh[22] = static_cast(width); bh[23] = static_cast(width >> 8); } // Write to display buffer { int x, y; s32 size; data = reinterpret_cast(addr); if(work == NULL) { result = fos.TryWrite(&size, bh, 54, true); if (result.IsFailure()) { return(-3); } for (x = 0; x < width; ++x) { i = x * 3; for (y = j = 0; y < height; ++y) { linebuf[j ] = data[i ]; linebuf[j+1] = data[i+1]; linebuf[j+2] = data[i+2]; j += 3; i += 3 * width; } result = fos.TryWrite(&size, linebuf, height * 3, true); if (result.IsFailure()) { return(-4); } } } else { u8* dst = work + 54; // Copy to 'work' to write data along with the BMP header std::memcpy(work, bh, 54); for (x = j = 0; x < width; ++x) { i = x * 3; for (y = 0; y < height; ++y) { dst[j ] = data[i ]; dst[j+1] = data[i+1]; dst[j+2] = data[i+2]; j += 3; i += 3 * width; } } result = fos.TryWrite(&size, work, width * height * 3 + 54, true); if (result.IsFailure()) { return(-4); } } } fos.Finalize(); return 0; }