void Matrix4x4<T>::orthographic(T inLeft, T inRight, T inBottom, T inTop, T inNear, T inFar) { Matrix4x4<T> transform; transform[0] = SCT(2) / (inRight - inLeft); transform[12] = (inRight + inLeft) / (inRight - inLeft); transform[5] = SCT(2) / (inTop - inBottom); transform[13] = (inTop + inBottom) / (inTop - inBottom); transform[10] = SCT(2) / (inNear - inFar); transform[14] = (inFar + inNear) / (inFar - inNear); multiply(Matrix4x4<T>(mData), transform); }
void Matrix4x4<T>::frustum(T inLeft, T inRight, T inBottom, T inTop, T inNear, T inFar) { Matrix4x4<T> transform; transform[0] = (SCT(2) * inNear) / (inRight - inLeft); transform[8] = (inRight + inLeft) / (inRight - inLeft); transform[5] = (SCT(2) * inNear) / (inTop - inBottom); transform[9] = (inTop + inBottom) / (inTop - inBottom); transform[10] = (inFar + inNear) / (inNear - inFar); transform[14] = (SCT(2) * inFar * inNear) / (inNear - inFar); transform[11] = SCT(-1); transform[15] = SCT(0); multiply(Matrix4x4<T>(mData), transform); }
void Matrix4x4<T>::orthographic(T inRange, T inRatio) { if (inRatio < SCT(1)) { orthographic(-inRange, inRange, -inRange / inRatio, inRange / inRatio, -inRange, inRange); } else { orthographic(-inRange * inRatio, inRange * inRatio, -inRange, inRange, -inRange, inRange); } }
void Matrix4x4<T>::rotate(T inDegrees, T inX, T inY, T inZ) { /// arbitrary rotation about an axis /// http://www.opengl.org/sdk/docs/man/xhtml/glRotate.xml T r = DEG2RAD(inDegrees); T c = cos(r); T ci = SCT(1) - c; T s = sin(r); Matrix4x4<T> transform; transform[0] = inX * inX * ci + c; transform[4] = inX * inY * ci - (inZ * s); transform[8] = inX * inZ * ci + (inY * s); transform[1] = inY * inX * ci + (inZ * s); transform[5] = inY * inY * ci + c; transform[9] = inY * inZ * ci - (inX * s); transform[2] = inX * inZ * ci - (inY * s); transform[6] = inY * inZ * ci + (inX * s); transform[10] = inZ * inZ * ci + c; multiply(Matrix4x4<T>(mData), transform); }
void Matrix4x4<T>::perspective(T inFieldOfView, T inRatio, T inNear, T inFar, bool inSmartAdjustment) { /// adaptation of gluPerspective /// http://www.opengl.org/sdk/docs/man/xhtml/gluPerspective.xml T r = DEG2RAD(inFieldOfView); if (inSmartAdjustment && inRatio < SCT(1)) r /= inRatio; T f = SCT(1) / tan(r / SCT(2)); Matrix4x4<T> transform; transform[0] = f / inRatio; transform[5] = f; transform[10] = (inFar + inNear) / (inNear - inFar); transform[14] = (SCT(2) * inFar * inNear) / (inNear - inFar); transform[11] = SCT(-1); transform[15] = SCT(0); multiply(Matrix4x4<T>(mData), transform); }
BOOL WINAPI PlugServerCommand(LPVOID pInst, CESERVER_REQ* pIn, CESERVER_REQ* &ppReply, DWORD &pcbReplySize, DWORD &pcbMaxReplySize, LPARAM lParam) { BOOL lbRc = FALSE; BOOL fSuccess = FALSE; MSectionThread SCT(csTabs); if (pIn->hdr.cbSize < sizeof(CESERVER_REQ_HDR) || /*in.nSize < cbRead ||*/ pIn->hdr.nVersion != CESERVER_REQ_VER) { gpPlugServer->BreakConnection(pInst); return FALSE; } UINT nDataSize = pIn->hdr.cbSize - sizeof(CESERVER_REQ_HDR); // Все данные из пайпа получены, обрабатываем команду и возвращаем (если нужно) результат switch (pIn->hdr.nCmd) { case CMD_LANGCHANGE: { _ASSERTE(nDataSize>=4); //-V112 // LayoutName: "00000409", "00010409", ... // А HKL от него отличается, так что передаем DWORD // HKL в x64 выглядит как: "0x0000000000020409", "0xFFFFFFFFF0010409" DWORD hkl = pIn->dwData[0]; DWORD dwLastError = 0; HKL hkl1 = NULL, hkl2 = NULL; if (hkl) { WCHAR szLoc[10]; _wsprintf(szLoc, SKIPLEN(countof(szLoc)) L"%08x", hkl); hkl1 = LoadKeyboardLayout(szLoc, KLF_ACTIVATE|KLF_REORDER|KLF_SUBSTITUTE_OK|KLF_SETFORPROCESS); hkl2 = ActivateKeyboardLayout(hkl1, KLF_SETFORPROCESS|KLF_REORDER); if (!hkl2) dwLastError = GetLastError(); else fSuccess = TRUE; } pcbReplySize = sizeof(CESERVER_REQ_HDR) + sizeof(DWORD)*2; if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->dwData[0] = fSuccess; ppReply->dwData[1] = fSuccess ? ((DWORD)(LONG)(LONG_PTR)hkl2) : dwLastError; } break; } // CMD_LANGCHANGE #if 0 case CMD_DEFFONT: { // исключение - асинхронный, результат не требуется SetConsoleFontSizeTo(FarHwnd, 4, 6); MoveWindow(FarHwnd, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), 1); // чтобы убрать возможные полосы прокрутки... break; } CMD_DEFFONT #endif case CMD_REQTABS: case CMD_SETWINDOW: { MSectionLock SC; SC.Lock(csTabs, FALSE, 1000); DWORD nSetWindowWait = (DWORD)-1; if (pIn->hdr.nCmd == CMD_SETWINDOW) { ResetEvent(ghSetWndSendTabsEvent); // Для FAR2 - сброс QSearch выполняется в том же макро, в котором актирируется окно if (gFarVersion.dwVerMajor == 1 && pIn->dwData[1]) { // А вот для FAR1 - нужно шаманить Plugin()->ProcessCommand(CMD_CLOSEQSEARCH, TRUE/*bReqMainThread*/, pIn->dwData/*хоть и не нужно?*/); } // Пересылается 2 DWORD BOOL bCmdRc = Plugin()->ProcessCommand(pIn->hdr.nCmd, TRUE/*bReqMainThread*/, pIn->dwData); DEBUGSTRCMD(L"Plugin: PlugServerThreadCommand: CMD_SETWINDOW waiting...\n"); WARNING("Почему для FAR1 не ждем? Есть возможность заблокироваться в 1.7 или что?"); if ((gFarVersion.dwVerMajor >= 2) && bCmdRc) { DWORD nTimeout = 2000; #ifdef _DEBUG if (IsDebuggerPresent()) nTimeout = 120000; #endif nSetWindowWait = WaitForSingleObject(ghSetWndSendTabsEvent, nTimeout); } if (nSetWindowWait == WAIT_TIMEOUT) { gbForceSendTabs = TRUE; DEBUGSTRCMD(L"Plugin: PlugServerThreadCommand: CMD_SETWINDOW timeout !!!\n"); } else { DEBUGSTRCMD(L"Plugin: PlugServerThreadCommand: CMD_SETWINDOW finished\n"); } } if (gpTabs && (nSetWindowWait != WAIT_TIMEOUT)) { //fSuccess = WriteFile(hPipe, gpTabs, gpTabs->hdr.cbSize, &cbWritten, NULL); pcbReplySize = gpTabs->hdr.cbSize; if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { memmove(ppReply->Data, gpTabs->Data, pcbReplySize - sizeof(ppReply->hdr)); lbRc = TRUE; } } SC.Unlock(); break; } // CMD_REQTABS, CMD_SETWINDOW case CMD_FARSETCHANGED: { // Установить переменные окружения // Плагин это получает в ответ на CECMD_RESOURCES, посланное в GUI при загрузке плагина _ASSERTE(nDataSize>=8); FAR_REQ_FARSETCHANGED *pFarSet = (FAR_REQ_FARSETCHANGED*)pIn->Data; cmd_FarSetChanged(pFarSet); pcbReplySize = sizeof(CESERVER_REQ_HDR) + sizeof(DWORD); if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->dwData[0] = TRUE; } //_ASSERTE(nDataSize<sizeof(gsMonitorEnvVar)); //gbMonitorEnvVar = false; //// Плагин FarCall "нарушает" COMSPEC (копирует содержимое запускаемого процесса) //bool lbOk = false; //if (nDataSize<sizeof(gsMonitorEnvVar)) //{ // memcpy(gsMonitorEnvVar, pszName, nDataSize); // lbOk = true; //} //UpdateEnvVar(pszName); ////while (*pszName && *pszValue) { //// const wchar_t* pszChanged = pszValue; //// // Для ConEmuOutput == AUTO выбирается по версии ФАРа //// if (!lstrcmpi(pszName, L"ConEmuOutput") && !lstrcmp(pszChanged, L"AUTO")) { //// if (gFarVersion.dwVerMajor==1) //// pszChanged = L"ANSI"; //// else //// pszChanged = L"UNICODE"; //// } //// // Если в pszValue пустая строка - удаление переменной //// SetEnvironmentVariableW(pszName, (*pszChanged != 0) ? pszChanged : NULL); //// // //// pszName = pszValue + lstrlenW(pszValue) + 1; //// if (*pszName == 0) break; //// pszValue = pszName + lstrlenW(pszName) + 1; ////} //gbMonitorEnvVar = lbOk; break; } // CMD_FARSETCHANGED case CMD_DRAGFROM: { #ifdef _DEBUG BOOL *pbClickNeed = (BOOL*)pIn->Data; COORD *crMouse = (COORD *)(pbClickNeed+1); #endif Plugin()->ProcessCommand(CMD_LEFTCLKSYNC, TRUE/*bReqMainThread*/, pIn->Data); CESERVER_REQ* pCmdRet = NULL; Plugin()->ProcessCommand(pIn->hdr.nCmd, TRUE/*bReqMainThread*/, pIn->Data, &pCmdRet); if (pCmdRet) { //fSuccess = WriteFile(hPipe, pCmdRet, pCmdRet->hdr.cbSize, &cbWritten, NULL); pcbReplySize = pCmdRet->hdr.cbSize; if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; memmove(ppReply->Data, pCmdRet->Data, pCmdRet->hdr.cbSize - sizeof(ppReply->hdr)); } Free(pCmdRet); } break; } // CMD_DRAGFROM case CMD_EMENU: { COORD *crMouse = (COORD *)pIn->Data; #ifdef _DEBUG const wchar_t *pszUserMacro = (wchar_t*)(crMouse+1); #endif DWORD ClickArg[2] = {(DWORD)TRUE, (DWORD)MAKELONG(crMouse->X, crMouse->Y)}; // Выделить файл под курсором DEBUGSTRMENU(L"\n*** ServerThreadCommand->ProcessCommand(CMD_LEFTCLKSYNC) begin\n"); BOOL lb1 = Plugin()->ProcessCommand(CMD_LEFTCLKSYNC, TRUE/*bReqMainThread*/, ClickArg/*pIn->Data*/); DEBUGSTRMENU(L"\n*** ServerThreadCommand->ProcessCommand(CMD_LEFTCLKSYNC) done\n"); // А теперь, собственно вызовем меню DEBUGSTRMENU(L"\n*** ServerThreadCommand->ProcessCommand(CMD_EMENU) begin\n"); BOOL lb2 = Plugin()->ProcessCommand(pIn->hdr.nCmd, TRUE/*bReqMainThread*/, pIn->Data); DEBUGSTRMENU(L"\n*** ServerThreadCommand->ProcessCommand(CMD_EMENU) done\n"); pcbReplySize = sizeof(CESERVER_REQ_HDR) + sizeof(DWORD)*2; if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->dwData[0] = lb1; ppReply->dwData[1] = lb1; } break; } // CMD_EMENU case CMD_ACTIVEWNDTYPE: { int nWindowType = -1; //CESERVER_REQ Out; //ExecutePrepareCmd(&Out, CMD_ACTIVEWNDTYPE, sizeof(CESERVER_REQ_HDR)+sizeof(DWORD)); if (gFarVersion.dwVerMajor>=2) nWindowType = Plugin()->GetActiveWindowType(); //fSuccess = WriteFile(hPipe, &Out, Out.hdr.cbSize, &cbWritten, NULL); pcbReplySize = sizeof(CESERVER_REQ_HDR) + sizeof(DWORD); if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->dwData[0] = nDataSize; } break; } // CMD_ACTIVEWNDTYPE case CECMD_ATTACH2GUI: { BOOL bAttached = Plugin()->Attach2Gui(); pcbReplySize = sizeof(CESERVER_REQ_HDR) + sizeof(DWORD); if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->dwData[0] = bAttached; } break; } // CECMD_ATTACH2GUI default: { CESERVER_REQ* pCmdRet = NULL; BOOL lbCmd = Plugin()->ProcessCommand(pIn->hdr.nCmd, TRUE/*bReqMainThread*/, pIn->Data, &pCmdRet); if (pCmdRet) { //fSuccess = WriteFile(hPipe, pCmdRet, pCmdRet->hdr.cbSize, &cbWritten, NULL); pcbReplySize = pCmdRet->hdr.cbSize; if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; memmove(ppReply->Data, pCmdRet->Data, pCmdRet->hdr.cbSize - sizeof(ppReply->hdr)); } Free(pCmdRet); } } // default } // switch (pIn->hdr.nCmd) return lbRc; }
BOOL WINAPI PlugServerCommand(LPVOID pInst, CESERVER_REQ* pIn, CESERVER_REQ* &ppReply, DWORD &pcbReplySize, DWORD &pcbMaxReplySize, LPARAM lParam) { BOOL lbRc = FALSE; //HANDLE hPipe = (HANDLE)ahPipe; //CESERVER_REQ *pIn=NULL; //BYTE cbBuffer[64]; // Для большей части команд нам хватит //DWORD cbRead = 0, cbWritten = 0, dwErr = 0; BOOL fSuccess = FALSE; MSectionThread SCT(csTabs); // Send a message to the pipe server and read the response. //fSuccess = ReadFile(hPipe, cbBuffer, sizeof(cbBuffer), &cbRead, NULL); //dwErr = GetLastError(); //if (!fSuccess && (dwErr != ERROR_MORE_DATA)) //{ // _ASSERTE("ReadFile(pipe) failed"==NULL); // CloseHandle(hPipe); // return 0; //} //pIn = (CESERVER_REQ*)cbBuffer; // Пока cast, если нужно больше - выделим память //_ASSERTE(pIn->hdr.cbSize>=sizeof(CESERVER_REQ_HDR) && cbRead>=sizeof(CESERVER_REQ_HDR)); //_ASSERTE(pIn->hdr.nVersion == CESERVER_REQ_VER); if (pIn->hdr.cbSize < sizeof(CESERVER_REQ_HDR) || /*in.nSize < cbRead ||*/ pIn->hdr.nVersion != CESERVER_REQ_VER) { //CloseHandle(hPipe); gpPlugServer->BreakConnection(pInst); return FALSE; } //int nAllSize = pIn->hdr.cbSize; //pIn = (CESERVER_REQ*)Alloc(nAllSize,1); //_ASSERTE(pIn!=NULL); //if (!pIn) //{ // CloseHandle(hPipe); // return 0; //} //memmove(pIn, cbBuffer, cbRead); //_ASSERTE(pIn->hdr.nVersion==CESERVER_REQ_VER); //LPBYTE ptrData = ((LPBYTE)pIn)+cbRead; //nAllSize -= cbRead; //while(nAllSize>0) //{ // //_tprintf(TEXT("%s\n"), chReadBuf); // // Break if TransactNamedPipe or ReadFile is successful // if (fSuccess) // break; // // Read from the pipe if there is more data in the message. // fSuccess = ReadFile( // hPipe, // pipe handle // ptrData, // buffer to receive reply // nAllSize, // size of buffer // &cbRead, // number of bytes read // NULL); // not overlapped // // Exit if an error other than ERROR_MORE_DATA occurs. // if (!fSuccess && ((dwErr = GetLastError()) != ERROR_MORE_DATA)) // break; // ptrData += cbRead; // nAllSize -= cbRead; //} //TODO("Может возникнуть ASSERT, если консоль была закрыта в процессе чтения"); //_ASSERTE(nAllSize==0); //if (nAllSize>0) //{ // if (((LPVOID)cbBuffer) != ((LPVOID)pIn)) // Free(pIn); // CloseHandle(hPipe); // return 0; // удалось считать не все данные //} UINT nDataSize = pIn->hdr.cbSize - sizeof(CESERVER_REQ_HDR); // Все данные из пайпа получены, обрабатываем команду и возвращаем (если нужно) результат //fSuccess = WriteFile( hPipe, pOut, pOut->nSize, &cbWritten, NULL); if (pIn->hdr.nCmd == CMD_LANGCHANGE) { _ASSERTE(nDataSize>=4); //-V112 // LayoutName: "00000409", "00010409", ... // А HKL от него отличается, так что передаем DWORD // HKL в x64 выглядит как: "0x0000000000020409", "0xFFFFFFFFF0010409" DWORD hkl = pIn->dwData[0]; DWORD dwLastError = 0; HKL hkl1 = NULL, hkl2 = NULL; if (hkl) { WCHAR szLoc[10]; _wsprintf(szLoc, SKIPLEN(countof(szLoc)) L"%08x", hkl); hkl1 = LoadKeyboardLayout(szLoc, KLF_ACTIVATE|KLF_REORDER|KLF_SUBSTITUTE_OK|KLF_SETFORPROCESS); hkl2 = ActivateKeyboardLayout(hkl1, KLF_SETFORPROCESS|KLF_REORDER); if (!hkl2) dwLastError = GetLastError(); else fSuccess = TRUE; } pcbReplySize = sizeof(CESERVER_REQ_HDR) + sizeof(DWORD)*2; if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->dwData[0] = fSuccess; ppReply->dwData[1] = fSuccess ? ((DWORD)(LONG)(LONG_PTR)hkl2) : dwLastError; } } //} else if (pIn->hdr.nCmd == CMD_DEFFONT) { // // исключение - асинхронный, результат не требуется // SetConsoleFontSizeTo(FarHwnd, 4, 6); // MoveWindow(FarHwnd, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), 1); // чтобы убрать возможные полосы прокрутки... else if (pIn->hdr.nCmd == CMD_REQTABS || pIn->hdr.nCmd == CMD_SETWINDOW) { MSectionLock SC; SC.Lock(csTabs, FALSE, 1000); DWORD nSetWindowWait = (DWORD)-1; if (pIn->hdr.nCmd == CMD_SETWINDOW) { ResetEvent(ghSetWndSendTabsEvent); // Для FAR2 - сброс QSearch выполняется в том же макро, в котором актирируется окно if (gFarVersion.dwVerMajor == 1 && pIn->dwData[1]) { // А вот для FAR1 - нужно шаманить ProcessCommand(CMD_CLOSEQSEARCH, TRUE/*bReqMainThread*/, pIn->dwData/*хоть и не нужно?*/); } // Пересылается 2 DWORD BOOL bCmdRc = ProcessCommand(pIn->hdr.nCmd, TRUE/*bReqMainThread*/, pIn->dwData); DEBUGSTRCMD(L"Plugin: PlugServerThreadCommand: CMD_SETWINDOW waiting...\n"); WARNING("Почему для FAR1 не ждем? Есть возможность заблокироваться в 1.7 или что?"); if ((gFarVersion.dwVerMajor >= 2) && bCmdRc) { DWORD nTimeout = 2000; #ifdef _DEBUG if (IsDebuggerPresent()) nTimeout = 120000; #endif nSetWindowWait = WaitForSingleObject(ghSetWndSendTabsEvent, nTimeout); } DEBUGSTRCMD(L"Plugin: PlugServerThreadCommand: CMD_SETWINDOW finished\n"); } if (gpTabs) { //fSuccess = WriteFile(hPipe, gpTabs, gpTabs->hdr.cbSize, &cbWritten, NULL); pcbReplySize = gpTabs->hdr.cbSize; if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { memmove(ppReply->Data, gpTabs->Data, pcbReplySize - sizeof(ppReply->hdr)); lbRc = TRUE; } } SC.Unlock(); } else if (pIn->hdr.nCmd == CMD_FARSETCHANGED) { // Установить переменные окружения // Плагин это получает в ответ на CECMD_RESOURCES, посланное в GUI при загрузке плагина _ASSERTE(nDataSize>=8); FAR_REQ_FARSETCHANGED *pFarSet = (FAR_REQ_FARSETCHANGED*)pIn->Data; cmd_FarSetChanged(pFarSet); pcbReplySize = sizeof(CESERVER_REQ_HDR) + sizeof(DWORD); if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->dwData[0] = TRUE; } //_ASSERTE(nDataSize<sizeof(gsMonitorEnvVar)); //gbMonitorEnvVar = false; //// Плагин FarCall "нарушает" COMSPEC (копирует содержимое запускаемого процесса) //bool lbOk = false; //if (nDataSize<sizeof(gsMonitorEnvVar)) //{ // memcpy(gsMonitorEnvVar, pszName, nDataSize); // lbOk = true; //} //UpdateEnvVar(pszName); ////while (*pszName && *pszValue) { //// const wchar_t* pszChanged = pszValue; //// // Для ConEmuOutput == AUTO выбирается по версии ФАРа //// if (!lstrcmpi(pszName, L"ConEmuOutput") && !lstrcmp(pszChanged, L"AUTO")) { //// if (gFarVersion.dwVerMajor==1) //// pszChanged = L"ANSI"; //// else //// pszChanged = L"UNICODE"; //// } //// // Если в pszValue пустая строка - удаление переменной //// SetEnvironmentVariableW(pszName, (*pszChanged != 0) ? pszChanged : NULL); //// // //// pszName = pszValue + lstrlenW(pszValue) + 1; //// if (*pszName == 0) break; //// pszValue = pszName + lstrlenW(pszName) + 1; ////} //gbMonitorEnvVar = lbOk; } else if (pIn->hdr.nCmd == CMD_DRAGFROM) { #ifdef _DEBUG BOOL *pbClickNeed = (BOOL*)pIn->Data; COORD *crMouse = (COORD *)(pbClickNeed+1); #endif ProcessCommand(CMD_LEFTCLKSYNC, TRUE/*bReqMainThread*/, pIn->Data); CESERVER_REQ* pCmdRet = NULL; ProcessCommand(pIn->hdr.nCmd, TRUE/*bReqMainThread*/, pIn->Data, &pCmdRet); if (pCmdRet) { //fSuccess = WriteFile(hPipe, pCmdRet, pCmdRet->hdr.cbSize, &cbWritten, NULL); pcbReplySize = pCmdRet->hdr.cbSize; if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; memmove(ppReply->Data, pCmdRet->Data, pCmdRet->hdr.cbSize - sizeof(ppReply->hdr)); } Free(pCmdRet); } //if (gpCmdRet && gpCmdRet == pCmdRet) //{ // Free(gpCmdRet); // gpCmdRet = NULL; gpData = NULL; gpCursor = NULL; //} } else if (pIn->hdr.nCmd == CMD_EMENU) { COORD *crMouse = (COORD *)pIn->Data; #ifdef _DEBUG const wchar_t *pszUserMacro = (wchar_t*)(crMouse+1); #endif DWORD ClickArg[2] = {TRUE, MAKELONG(crMouse->X, crMouse->Y)}; // Выделить файл под курсором DEBUGSTRMENU(L"\n*** ServerThreadCommand->ProcessCommand(CMD_LEFTCLKSYNC) begin\n"); BOOL lb1 = ProcessCommand(CMD_LEFTCLKSYNC, TRUE/*bReqMainThread*/, ClickArg/*pIn->Data*/); DEBUGSTRMENU(L"\n*** ServerThreadCommand->ProcessCommand(CMD_LEFTCLKSYNC) done\n"); // А теперь, собственно вызовем меню DEBUGSTRMENU(L"\n*** ServerThreadCommand->ProcessCommand(CMD_EMENU) begin\n"); BOOL lb2 = ProcessCommand(pIn->hdr.nCmd, TRUE/*bReqMainThread*/, pIn->Data); DEBUGSTRMENU(L"\n*** ServerThreadCommand->ProcessCommand(CMD_EMENU) done\n"); pcbReplySize = sizeof(CESERVER_REQ_HDR) + sizeof(DWORD)*2; if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->dwData[0] = lb1; ppReply->dwData[1] = lb1; } } else if (pIn->hdr.nCmd == CMD_ACTIVEWNDTYPE) { int nWindowType = -1; //CESERVER_REQ Out; //ExecutePrepareCmd(&Out, CMD_ACTIVEWNDTYPE, sizeof(CESERVER_REQ_HDR)+sizeof(DWORD)); if (gFarVersion.dwVerMajor>=2) nWindowType = GetActiveWindowType(); //fSuccess = WriteFile(hPipe, &Out, Out.hdr.cbSize, &cbWritten, NULL); pcbReplySize = sizeof(CESERVER_REQ_HDR) + sizeof(DWORD); if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; ppReply->dwData[0] = nDataSize; } } else { CESERVER_REQ* pCmdRet = NULL; BOOL lbCmd = ProcessCommand(pIn->hdr.nCmd, TRUE/*bReqMainThread*/, pIn->Data, &pCmdRet); if (pCmdRet) { //fSuccess = WriteFile(hPipe, pCmdRet, pCmdRet->hdr.cbSize, &cbWritten, NULL); pcbReplySize = pCmdRet->hdr.cbSize; if (ExecuteNewCmd(ppReply, pcbMaxReplySize, pIn->hdr.nCmd, pcbReplySize)) { lbRc = TRUE; memmove(ppReply->Data, pCmdRet->Data, pCmdRet->hdr.cbSize - sizeof(ppReply->hdr)); } Free(pCmdRet); } //if (gpCmdRet && gpCmdRet == pCmdRet) { // Free(gpCmdRet); // gpCmdRet = NULL; gpData = NULL; gpCursor = NULL; //} } //// Освободить память //if (((LPVOID)cbBuffer) != ((LPVOID)pIn)) // Free(pIn); //CloseHandle(hPipe); return lbRc; }
namespace XPG { template<typename T> class Matrix4x4 { public: Matrix4x4(const T* inArray = mIdentity); Matrix4x4(const Matrix4x4<T>& inMatrix); Matrix4x4(const Matrix4x4<T>& inLMatrix, const Matrix4x4<T>& inRMatrix); ~Matrix4x4(); void loadIdentity(); /// model view void rotate(T inDegrees, T inX, T inY, T inZ); void rotateX(T inDegrees); void rotateY(T inDegrees); void rotateZ(T inDegrees); void scale(T inScale); void scaleX(T inScale); void scaleY(T inScale); void scaleZ(T inScale); void scale(T inX, T inY, T inZ); void translate(T inX, T inY, T inZ); void smartMove(T inRX, T inRY, T inRZ, T inTX, T inTY, T inTZ); /// projection void frustum(T inLeft, T inRight, T inBottom, T inTop, T inNear, T inFar); void perspective(T inFieldOfView, T inRatio, T inNear, T inFar, bool inSmartAdjustment = false); void orthographic(T inLeft, T inRight, T inBottom, T inTop, T inNear, T inFar); void orthographic(T inRange, T inRatio); /// matrix operators Matrix4x4<T>& operator=(const Matrix4x4<T>& inMatrix); void multiply(const Matrix4x4<T>& inLMatrix, const Matrix4x4<T>& inRMatrix); void inverse(); void copyInverseTo(Matrix4x4<T>& inMatrix) const; const Matrix4x4<T> inversed() const; /// Allow this object to behave as a simple array. inline operator T*() { return mData; } inline operator const T*() const { return mData; } /// Allow simply access by row and column. inline T& operator()(size_t inRow, size_t inCol) { return mData[inCol * 4 + inRow]; } inline T operator()(size_t inRow, size_t inCol) const { return mData[inCol * 4 + inRow]; } /// simple comparison operators inline bool operator==(const Matrix4x4<T>& inMatrix) const { return !memcmp(mData, inMatrix.mData, 16 * sizeof(T)); } inline bool operator!=(const Matrix4x4<T>& inMatrix) const { return memcmp(mData, inMatrix.mData, 16 * sizeof(T)); } inline Matrix4x4<T>& operator*=(const Matrix4x4<T>& inMatrix) { multiply(Matrix4x4<T>(mData), inMatrix); return *this; } inline const Matrix4x4<T> operator*(const Matrix4x4<T>& inMatrix) const { return Matrix4x4<T>(Matrix4x4<T>(mData), inMatrix); } private: inline void copy(const Matrix4x4<T>& inMatrix) { memcpy(mData, inMatrix.mData, 16 * sizeof(T)); } inline T& at(size_t inRow, size_t inCol) { return mData[inCol * 4 + inRow]; } inline T at(size_t inRow, size_t inCol) const { return mData[inCol * 4 + inRow]; } T mData[16]; // stored in column-major order static const T mIdentity[16]; }; /// The identity matrix is pre-built so that it can just be copied to newly /// born matrices. This makes it faster than manually filling the identity /// matrix and/or having to iterate through a loop. template<typename T> const T Matrix4x4<T>::mIdentity[16] = { SCT(1), SCT(0), SCT(0), SCT(0), SCT(0), SCT(1), SCT(0), SCT(0), SCT(0), SCT(0), SCT(1), SCT(0), SCT(0), SCT(0), SCT(0), SCT(1) }; /// For increased compatibility, this matrix can read its data in from an /// array. This also doubles as the default constructor: if no array is /// specified, the pointer to the static identity matrix is passed in. /// /// IMPORTANT -- Because the array stores the matrix in column-major order, /// it is assumed the incoming data is sorted the same way. template<typename T> Matrix4x4<T>::Matrix4x4(const T* inArray) { memcpy(mData, inArray, 16 * sizeof(T)); } /// This is a very simple copy constructor. It does a byte-for-byte copy of /// target matrix's data. template<typename T> Matrix4x4<T>::Matrix4x4(const Matrix4x4<T>& inMatrix) { copy(inMatrix); } /// It is common for matrices to be created on the fly specifically for /// capturing the product of two matrices. This constructor defaults its /// data to that product (bypasses any other setting of the array). template<typename T> Matrix4x4<T>::Matrix4x4(const Matrix4x4<T>& inLMatrix, const Matrix4x4<T>& inRMatrix) { multiply(inLMatrix, inRMatrix); } /// The destructor has nothing to do. It is here primarily to satisfy the /// sacred Rule of Three. template<typename T> Matrix4x4<T>::~Matrix4x4() { } /// There are many instances where the programmer needs to reset the matrix /// back to the identity matrix. template<typename T> void Matrix4x4<T>::loadIdentity() { memcpy(mData, mIdentity, 16 * sizeof(T)); } /// This is a spiritual recreation of glRotatef template<typename T> void Matrix4x4<T>::rotate(T inDegrees, T inX, T inY, T inZ) { /// arbitrary rotation about an axis /// http://www.opengl.org/sdk/docs/man/xhtml/glRotate.xml T r = DEG2RAD(inDegrees); T c = cos(r); T ci = SCT(1) - c; T s = sin(r); Matrix4x4<T> transform; transform[0] = inX * inX * ci + c; transform[4] = inX * inY * ci - (inZ * s); transform[8] = inX * inZ * ci + (inY * s); transform[1] = inY * inX * ci + (inZ * s); transform[5] = inY * inY * ci + c; transform[9] = inY * inZ * ci - (inX * s); transform[2] = inX * inZ * ci - (inY * s); transform[6] = inY * inZ * ci + (inX * s); transform[10] = inZ * inZ * ci + c; multiply(Matrix4x4<T>(mData), transform); } /// Rather than deal with the mathematical nightmare involved with rotating /// about an arbitrary axis, it is much simpler and faster to rotate about /// X, Y, or Z. This function rotates about X axis. template<typename T> void Matrix4x4<T>::rotateX(T inDegrees) { T r = DEG2RAD(inDegrees); T c = cos(r); T s = sin(r); Matrix4x4<T> transform; transform[5] = c; transform[9] = -s; transform[6] = s; transform[10] = c; multiply(Matrix4x4<T>(mData), transform); } /// Rather than deal with the mathematical nightmare involved with rotating /// about an arbitrary axis, it is much simpler and faster to rotate about /// X, Y, or Z. This function rotates about Y axis. template<typename T> void Matrix4x4<T>::rotateY(T inDegrees) { T r = DEG2RAD(inDegrees); T c = cos(r); T s = sin(r); Matrix4x4<T> transform; transform[0] = c; transform[8] = s; transform[2] = -s; transform[10] = c; multiply(Matrix4x4<T>(mData), transform); } /// Rather than deal with the mathematical nightmare involved with rotating /// about an arbitrary axis, it is much simpler and faster to rotate about /// X, Y, or Z. This function rotates about Z axis. template<typename T> void Matrix4x4<T>::rotateZ(T inDegrees) { T r = DEG2RAD(inDegrees); T c = cos(r); T s = sin(r); Matrix4x4<T> transform; transform[0] = c; transform[4] = -s; transform[1] = s; transform[5] = c; multiply(Matrix4x4<T>(mData), transform); } /// This is a uniform scale transformations. All three components are scaled /// by the same value specified by inScale. template<typename T> void Matrix4x4<T>::scale(T inScale) { Matrix4x4<T> transform; transform[0] = inScale; transform[5] = inScale; transform[10] = inScale; multiply(Matrix4x4<T>(mData), transform); } /// A common error with scaling along one axis is that it is natural to set /// the other scales to zero instead of one. This function mitigates that. /// It scales along the X axis only. template<typename T> void Matrix4x4<T>::scaleX(T inScale) { Matrix4x4<T> transform; transform[0] = inScale; multiply(Matrix4x4<T>(mData), transform); } /// A common error with scaling along one axis is that it is natural to set /// the other scales to zero instead of one. This function mitigates that. /// It scales along the Y axis only. template<typename T> void Matrix4x4<T>::scaleY(T inScale) { Matrix4x4<T> transform; transform[5] = inScale; multiply(Matrix4x4<T>(mData), transform); } /// A common error with scaling along one axis is that it is natural to set /// the other scales to zero instead of one. This function mitigates that. /// It scales along the Z axis only. template<typename T> void Matrix4x4<T>::scaleZ(T inScale) { Matrix4x4<T> transform; transform[10] = inScale; multiply(Matrix4x4<T>(mData), transform); } /// The standard scale transformation can resize geometry along the X, Y, /// and/or the Z axes. It functions like that of glScale. template<typename T> void Matrix4x4<T>::scale(T inX, T inY, T inZ) { Matrix4x4<T> transform; transform[0] = inX; transform[5] = inY; transform[10] = inZ; multiply(Matrix4x4<T>(mData), transform); } /// This transformation serves as a direct offset for vertices. It functions /// like that of glTranslate. template<typename T> void Matrix4x4<T>::translate(T inX, T inY, T inZ) { Matrix4x4<T> transform; transform[12] = inX; transform[13] = inY; transform[14] = inZ; multiply(Matrix4x4<T>(mData), transform); } /// When positioning an object in the scene, there is a particular optimal /// order to applying those transformations: rotate Z, rotate X, rotate Y, /// translate. template<typename T> void Matrix4x4<T>::smartMove(T inRX, T inRY, T inRZ, T inTX, T inTY, T inTZ) { translate(inTX, inTY, inTZ); rotateY(inRY); rotateX(inRX); rotateZ(inRZ); } /// This is a spiritual recreation of glFrustum. template<typename T> void Matrix4x4<T>::frustum(T inLeft, T inRight, T inBottom, T inTop, T inNear, T inFar) { Matrix4x4<T> transform; transform[0] = (SCT(2) * inNear) / (inRight - inLeft); transform[8] = (inRight + inLeft) / (inRight - inLeft); transform[5] = (SCT(2) * inNear) / (inTop - inBottom); transform[9] = (inTop + inBottom) / (inTop - inBottom); transform[10] = (inFar + inNear) / (inNear - inFar); transform[14] = (SCT(2) * inFar * inNear) / (inNear - inFar); transform[11] = SCT(-1); transform[15] = SCT(0); multiply(Matrix4x4<T>(mData), transform); } /// This is a recreation of gluPerspective (more commonly used than /// glFrustum). template<typename T> void Matrix4x4<T>::perspective(T inFieldOfView, T inRatio, T inNear, T inFar, bool inSmartAdjustment) { /// adaptation of gluPerspective /// http://www.opengl.org/sdk/docs/man/xhtml/gluPerspective.xml T r = DEG2RAD(inFieldOfView); if (inSmartAdjustment && inRatio < SCT(1)) r /= inRatio; T f = SCT(1) / tan(r / SCT(2)); Matrix4x4<T> transform; transform[0] = f / inRatio; transform[5] = f; transform[10] = (inFar + inNear) / (inNear - inFar); transform[14] = (SCT(2) * inFar * inNear) / (inNear - inFar); transform[11] = SCT(-1); transform[15] = SCT(0); multiply(Matrix4x4<T>(mData), transform); } /// This is a recreation of glOrtho. It creates a basic orthographic /// projection. template<typename T> void Matrix4x4<T>::orthographic(T inLeft, T inRight, T inBottom, T inTop, T inNear, T inFar) { Matrix4x4<T> transform; transform[0] = SCT(2) / (inRight - inLeft); transform[12] = (inRight + inLeft) / (inRight - inLeft); transform[5] = SCT(2) / (inTop - inBottom); transform[13] = (inTop + inBottom) / (inTop - inBottom); transform[10] = SCT(2) / (inNear - inFar); transform[14] = (inFar + inNear) / (inFar - inNear); multiply(Matrix4x4<T>(mData), transform); } /// This is an intelligent orthographic projection. Rather than manually /// request all sides of the canonical viewing volume (as in glOrtho), this /// function simply takes the aspect ratio and requested object space range. /// The range is fixated along the shorter axis of the display. In other /// words, in a widescreen display, the top and bottom will exactly reach /// the range specified by inRange. In a tall display, the left and right /// will reach that range. template<typename T> void Matrix4x4<T>::orthographic(T inRange, T inRatio) { if (inRatio < SCT(1)) { orthographic(-inRange, inRange, -inRange / inRatio, inRange / inRatio, -inRange, inRange); } else { orthographic(-inRange * inRatio, inRange * inRatio, -inRange, inRange, -inRange, inRange); } } /// This is a rudimentary assignment operator. It just makes a byte-perfect /// copy of the target matrix. template<typename T> Matrix4x4<T>& Matrix4x4<T>::operator=(const Matrix4x4<T>& inMatrix) { if (this != &inMatrix) copy(inMatrix); return *this; } /// This function multiplies inLMatrix and inRMatrix together and stores the /// result into THIS matrix. In other words, it OVERWRITES its own data with /// the product of the two incoming matrices. This is done for performance /// reasons as it prevents an extra temporary copy from being made. template<typename T> void Matrix4x4<T>::multiply(const Matrix4x4<T>& inLMatrix, const Matrix4x4<T>& inRMatrix) { /// The actual math has been completely unrolled (out of for loops) for /// performance improvements. mData[0] = (inLMatrix[0] * inRMatrix[0]) + (inLMatrix[4] * inRMatrix[1]) + (inLMatrix[8] * inRMatrix[2]) + (inLMatrix[12] * inRMatrix[3]); mData[4] = (inLMatrix[0] * inRMatrix[4]) + (inLMatrix[4] * inRMatrix[5]) + (inLMatrix[8] * inRMatrix[6]) + (inLMatrix[12] * inRMatrix[7]); mData[8] = (inLMatrix[0] * inRMatrix[8]) + (inLMatrix[4] * inRMatrix[9]) + (inLMatrix[8] * inRMatrix[10]) + (inLMatrix[12] * inRMatrix[11]); mData[12] = (inLMatrix[0] * inRMatrix[12]) + (inLMatrix[4] * inRMatrix[13]) + (inLMatrix[8] * inRMatrix[14]) + (inLMatrix[12] * inRMatrix[15]); mData[1] = (inLMatrix[1] * inRMatrix[0]) + (inLMatrix[5] * inRMatrix[1]) + (inLMatrix[9] * inRMatrix[2]) + (inLMatrix[13] * inRMatrix[3]); mData[5] = (inLMatrix[1] * inRMatrix[4]) + (inLMatrix[5] * inRMatrix[5]) + (inLMatrix[9] * inRMatrix[6]) + (inLMatrix[13] * inRMatrix[7]); mData[9] = (inLMatrix[1] * inRMatrix[8]) + (inLMatrix[5] * inRMatrix[9]) + (inLMatrix[9] * inRMatrix[10]) + (inLMatrix[13] * inRMatrix[11]); mData[13] = (inLMatrix[1] * inRMatrix[12]) + (inLMatrix[5] * inRMatrix[13]) + (inLMatrix[9] * inRMatrix[14]) + (inLMatrix[13] * inRMatrix[15]); mData[2] = (inLMatrix[2] * inRMatrix[0]) + (inLMatrix[6] * inRMatrix[1]) + (inLMatrix[10] * inRMatrix[2]) + (inLMatrix[14] * inRMatrix[3]); mData[6] = (inLMatrix[2] * inRMatrix[4]) + (inLMatrix[6] * inRMatrix[5]) + (inLMatrix[10] * inRMatrix[6]) + (inLMatrix[14] * inRMatrix[7]); mData[10] = (inLMatrix[2] * inRMatrix[8]) + (inLMatrix[6] * inRMatrix[9]) + (inLMatrix[10] * inRMatrix[10]) + (inLMatrix[14] * inRMatrix[11]); mData[14] = (inLMatrix[2] * inRMatrix[12]) + (inLMatrix[6] * inRMatrix[13]) + (inLMatrix[10] * inRMatrix[14]) + (inLMatrix[14] * inRMatrix[15]); mData[3] = (inLMatrix[3] * inRMatrix[0]) + (inLMatrix[7] * inRMatrix[1]) + (inLMatrix[11] * inRMatrix[2]) + (inLMatrix[15] * inRMatrix[3]); mData[7] = (inLMatrix[3] * inRMatrix[4]) + (inLMatrix[7] * inRMatrix[5]) + (inLMatrix[11] * inRMatrix[6]) + (inLMatrix[15] * inRMatrix[7]); mData[11] = (inLMatrix[3] * inRMatrix[8]) + (inLMatrix[7] * inRMatrix[9]) + (inLMatrix[11] * inRMatrix[10]) + (inLMatrix[15] * inRMatrix[11]); mData[15] = (inLMatrix[3] * inRMatrix[12]) + (inLMatrix[7] * inRMatrix[13]) + (inLMatrix[11] * inRMatrix[14]) + (inLMatrix[15] * inRMatrix[15]); } /// This finds the inverse matrix and stores it into THIS matrix. template<typename T> void Matrix4x4<T>::inverse() { const Matrix4x4<T> m(*this); m.copyInverseTo(*this); } /// This finds the inverse matrix and returns it as a copy. template<typename T> const Matrix4x4<T> Matrix4x4<T>::inversed() const { Matrix4x4<T> outMatrix; copyInverseTo(outMatrix); return outMatrix; } /// This finds the inverse matrix and stores it into inMatrix. template<typename T> void Matrix4x4<T>::copyInverseTo(Matrix4x4<T>& inMatrix) const { #define SWAP_ROWS(a, b) { T* _tmp = a; (a) = (b); (b) = _tmp; } T wtmp[4][8]; T m0; T m1; T m2; T m3; T s; T* r0; T* r1; T* r2; T* r3; r0 = wtmp[0]; r1 = wtmp[1]; r2 = wtmp[2]; r3 = wtmp[3]; r0[0] = at(0, 0); r0[1] = at(0, 1); r0[2] = at(0, 2); r0[3] = at(0, 3); r0[4] = 1.0; r0[5] = r0[6] = r0[7] = 0.0; r1[0] = at(1, 0); r1[1] = at(1, 1); r1[2] = at(1, 2); r1[3] = at(1, 3); r1[5] = 1.0; r1[4] = r1[6] = r1[7] = 0.0; r2[0] = at(2, 0); r2[1] = at(2, 1); r2[2] = at(2, 2); r2[3] = at(2, 3); r2[6] = 1.0; r2[4] = r2[5] = r2[7] = 0.0; r3[0] = at(3, 0); r3[1] = at(3, 1); r3[2] = at(3, 2); r3[3] = at(3, 3); r3[7] = 1.0; r3[4] = r3[5] = r3[6] = 0.0; if (fabs(r3[0]) > fabs(r2[0])) SWAP_ROWS(r3, r2); if (fabs(r2[0]) > fabs(r1[0])) SWAP_ROWS(r2, r1); if (fabs(r1[0]) > fabs(r0[0])) SWAP_ROWS(r1, r0); if (0.0 == r0[0]) return; m1 = r1[0] / r0[0]; m2 = r2[0] / r0[0]; m3 = r3[0] / r0[0]; s = r0[1]; r1[1] -= m1 * s; r2[1] -= m2 * s; r3[1] -= m3 * s; s = r0[2]; r1[2] -= m1 * s; r2[2] -= m2 * s; r3[2] -= m3 * s; s = r0[3]; r1[3] -= m1 * s; r2[3] -= m2 * s; r3[3] -= m3 * s; s = r0[4]; if (s != 0.0) { r1[4] -= m1 * s; r2[4] -= m2 * s; r3[4] -= m3 * s; } s = r0[5]; if (s != 0.0) { r1[5] -= m1 * s; r2[5] -= m2 * s; r3[5] -= m3 * s; } s = r0[6]; if (s != 0.0) { r1[6] -= m1 * s; r2[6] -= m2 * s; r3[6] -= m3 * s; } s = r0[7]; if (s != 0.0) { r1[7] -= m1 * s; r2[7] -= m2 * s; r3[7] -= m3 * s; } if (fabs(r3[1]) > fabs(r2[1])) SWAP_ROWS(r3, r2); if (fabs(r2[1]) > fabs(r1[1])) SWAP_ROWS(r2, r1); if (0.0 == r1[1]) return; m2 = r2[1] / r1[1]; m3 = r3[1] / r1[1]; r2[2] -= m2 * r1[2]; r3[2] -= m3 * r1[2]; r2[3] -= m2 * r1[3]; r3[3] -= m3 * r1[3]; s = r1[4]; if (0.0 != s) { r2[4] -= m2 * s; r3[4] -= m3 * s; } s = r1[5]; if (0.0 != s) { r2[5] -= m2 * s; r3[5] -= m3 * s; } s = r1[6]; if (0.0 != s) { r2[6] -= m2 * s; r3[6] -= m3 * s; } s = r1[7]; if (0.0 != s) { r2[7] -= m2 * s; r3[7] -= m3 * s; } if (fabs(r3[2]) > fabs(r2[2])) SWAP_ROWS(r3, r2); if (0.0 == r2[2]) return; m3 = r3[2] / r2[2]; r3[3] -= m3 * r2[3]; r3[4] -= m3 * r2[4]; r3[5] -= m3 * r2[5]; r3[6] -= m3 * r2[6]; r3[7] -= m3 * r2[7]; if (0.0 == r3[3]) return; s = 1.0 / r3[3]; r3[4] *= s; r3[5] *= s; r3[6] *= s; r3[7] *= s; m2 = r2[3]; s = 1.0 / r2[2]; r2[4] = s * (r2[4] - r3[4] * m2); r2[5] = s * (r2[5] - r3[5] * m2); r2[6] = s * (r2[6] - r3[6] * m2); r2[7] = s * (r2[7] - r3[7] * m2); m1 = r1[3]; r1[4] -= r3[4] * m1; r1[5] -= r3[5] * m1; r1[6] -= r3[6] * m1; r1[7] -= r3[7] * m1; m0 = r0[3]; r0[4] -= r3[4] * m0; r0[5] -= r3[5] * m0; r0[6] -= r3[6] * m0; r0[7] -= r3[7] * m0; m1 = r1[2]; s = 1.0 / r1[1]; r1[4] = s * (r1[4] - r2[4] * m1); r1[5] = s * (r1[5] - r2[5] * m1); r1[6] = s * (r1[6] - r2[6] * m1); r1[7] = s * (r1[7] - r2[7] * m1); m0 = r0[2]; r0[4] -= r2[4] * m0; r0[5] -= r2[5] * m0; r0[6] -= r2[6] * m0; r0[7] -= r2[7] * m0; m0 = r0[1]; s = 1.0 / r0[0]; r0[4] = s * (r0[4] - r1[4] * m0); r0[5] = s * (r0[5] - r1[5] * m0); r0[6] = s * (r0[6] - r1[6] * m0); r0[7] = s * (r0[7] - r1[7] * m0); inMatrix(0, 0) = r0[4]; inMatrix(0, 1) = r0[5]; inMatrix(0, 2) = r0[6]; inMatrix(0, 3) = r0[7]; inMatrix(1, 0) = r1[4]; inMatrix(1, 1) = r1[5]; inMatrix(1, 2) = r1[6]; inMatrix(1, 3) = r1[7]; inMatrix(2, 0) = r2[4]; inMatrix(2, 1) = r2[5]; inMatrix(2, 2) = r2[6]; inMatrix(2, 3) = r2[7]; inMatrix(3, 0) = r3[4]; inMatrix(3, 1) = r3[5]; inMatrix(3, 2) = r3[6]; inMatrix(3, 3) = r3[7]; } /// For easy display/debugging and/or serialization, the extraction operator /// has been overloaded to allow matrices in output streams. #ifndef XPG_PLATFORM_ANDROID template<typename T> std::ostream& operator<<(std::ostream& inStream, const Matrix4x4<T>& inMatrix) { inStream << std::setprecision(2); for (size_t i = 0; i < 4; ++i) { if (i) inStream << '\n'; for (size_t j = 0; j < 4; ++j) { inStream << std::setw(6) << inMatrix(i, j); } } return inStream; } #endif }