📄 gltriwarp.c
字号:
/**************************************************************************************** * * Author: Barry Theobald, Iain Matthews * Data: 30/12/2002 * Function: Use windows API calls to set up an offscreen bitmap for image warping. * * Revision: $Id: gltriwarp.c,v 1.0 2003-12-08 11:32:56+00 barry-john_theobald Exp barry-john_theobald $ * Revision: $Id: gltriwarp.c,v 1.0 2005-09-26 15:34:00+00 andrew ian hanna Exp andrew ian hanna $ * Revision: $Id: gltriwarp.c,v 1.0 2006-02-07 16:08:00+00 andrew (god) courtenay Exp andrew (god) courtenay $****************************************************************************************/#include <windows.h>#include <stdio.h>#include <math.h>#include "GL/gl.h"#include "mex.h"// *************************************************************************************// Store windows and offscreen bitmap informationtypedef struct _WGLINFO { HDC hDC; HGLRC hGLRC; HPALETTE hPalette; HBITMAP hBitmap; HBITMAP hOldBitmap; HINSTANCE hCInst; WNDCLASS wndClass; HWND hWnd;} WGLINFO; GLuint texName;// Define globals **********************************************************************#define BMP_WIDTH 1024#define BMP_HEIGHT 1024static WGLINFO wglInfo;static int initialised = 0;char *className = "gltriwarp";char *windowName = "gltriwarp";// Function declarations ****************************************************************LRESULT APIENTRY WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);void setupDIB(void);void Initalways();void setupPixelFormat(void);void Initialise(int nrhs, const mxArray *prhs[]);void KillGLWindow(void);void InitGL(void);void InitTexture(void);GLvoid getMappedImage(int opwidth, int opheight);GLubyte *GetInputImage(const mxArray *img, int *width, int *height);void ParseVert(float *vert, int nvert, int *opwidth, int *opheight);float *ScaleTexVert(float *vert, int Nvert, int width, int height);// **************************************************************************************void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){ int k; int width, height, opwidth, opheight, Nvert; int dims[3]; float *ivert, *overt, *tvert; GLubyte *pix; mxArray *oimg; if(nrhs < 3) mexErrMsgTxt("Must give the input image and the vertices!"); // Setup the bitmap on first call ***************************************************** if(!initialised) Initialise(nrhs, prhs); Initalways(); // Get the texture image ************************************************************** pix = GetInputImage(prhs[0], &width, &height); // Check the image size < bitmap if(width > BMP_WIDTH || height > BMP_HEIGHT) mexErrMsgTxt("\nImage is larger than the rendering window\n"); // Copy image into texture memory glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pix); // Get input vertices ***************************************************************** if(!mxIsNumeric(prhs[1]) || mxIsEmpty(prhs[1])) mexErrMsgTxt("Input vertices must not be empty\n"); else ivert = (float*)mxGetData(prhs[1]); // The number of vertices Nvert = mxGetNumberOfElements(prhs[1]) / 2; // Get output vertices ***************************************************************** if(!mxIsNumeric(prhs[2]) || mxIsEmpty(prhs[2])) mexErrMsgTxt("Output vertices must not be empty\n"); else overt = (float*)mxGetData(prhs[2]); // The number of vertices if((mxGetNumberOfElements(prhs[2]) / 2) != Nvert) mexErrMsgTxt("Number of input and output vertices must match"); // Get the range of output verticies and set the output image size ******************** ParseVert(overt, Nvert, &opwidth, &opheight); // Scale texture coordinates into the range 0->1 tvert = ScaleTexVert(ivert, Nvert, BMP_WIDTH, BMP_HEIGHT); // Now draw the texture *************************************************************** glEnable(GL_TEXTURE_2D); glClear(GL_COLOR_BUFFER_BIT); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glBindTexture(GL_TEXTURE_2D, texName); glBegin(GL_TRIANGLES); for(k=0; k < Nvert * 2; k+=2) { glTexCoord2fv(tvert + k); glVertex2fv(overt + k); } glEnd(); glFinish(); glDisable(GL_TEXTURE_2D); // Texture coordinates are no longer needed mxFree(tvert); // Setup the return image and return ************************************************** dims[0] = opwidth; dims[1] = opheight; dims[2] = 3; if ((oimg = mxCreateNumericArray(3, dims, mxUINT8_CLASS, mxREAL)) == NULL) mexErrMsgTxt("Unable to allocate output matrix\n"); // Read pixels from framebuffer to output matrix glReadPixels(0, 0, opwidth, opheight, GL_RGB, GL_UNSIGNED_BYTE, (GLubyte*)mxGetData(oimg)); glFinish(); // Output matrix plhs[0] = oimg; wglDeleteContext(wglInfo.hGLRC); // DestroyWindow(wglInfo.hWnd); }//****************************************************************************************//****************************************************************************************//********************************* Windows Stuff **************************************//****************************************************************************************//****************************************************************************************void Initalways(){ // Create the OpenGL context and make it current if (!(wglInfo.hGLRC = wglCreateContext(wglInfo.hDC))) // Are We Able To Get A Rendering Context? { KillGLWindow(); // Reset The Display MessageBox(NULL,"Can't Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION); //return FALSE; // Return FALSE } if(!wglMakeCurrent(wglInfo.hDC, wglInfo.hGLRC)) // Try To Activate The Rendering Context { KillGLWindow(); // Reset The Display MessageBox(NULL,"Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION); // return FALSE; // Return FALSE } // Initialise OpenGL state variables and OpenGL texture mapping InitGL(); InitTexture();}// Initialise a window (but do not display), and use properties to setup an DIBvoid Initialise(int nrhs, const mxArray *prhs[]){ // Define and register a window class wglInfo.wndClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wglInfo.wndClass.lpfnWndProc = WndProc; wglInfo.wndClass.cbClsExtra = 0; wglInfo.wndClass.cbWndExtra = 0; wglInfo.wndClass.hInstance = wglInfo.hCInst; wglInfo.wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wglInfo.wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); wglInfo.wndClass.hbrBackground = GetStockObject(WHITE_BRUSH); wglInfo.wndClass.lpszMenuName = NULL; wglInfo.wndClass.lpszClassName = className; if (!RegisterClass(&wglInfo.wndClass)) // Attempt To Register The Window Class { MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION); //return FALSE; // Return FALSE } // // NOTE: -- // Create a window of the previously defined class, but do not display! // The window properties are used to setup the bitmap // if (!( wglInfo.hWnd = CreateWindow( className, // Window class's name windowName, // Title bar text WS_OVERLAPPEDWINDOW | // The window's style WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, // Position BMP_WIDTH, BMP_HEIGHT, // Size NULL, // Parent window's handle NULL, // Menu handle wglInfo.hCInst, // Instance handle NULL))) // No additional data { KillGLWindow(); // Reset The Display MessageBox(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION); //return FALSE; // Return FALSE }if (!(wglInfo.hDC = GetDC(wglInfo.hWnd))) // Did We Get A Device Context? { KillGLWindow(); // Reset The Display MessageBox(NULL,"Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION); //return FALSE; // Return FALSE }if (!(wglInfo.hDC = CreateCompatibleDC(wglInfo.hDC))) // Did We Get A Device Context? { KillGLWindow(); // Reset The Display MessageBox(NULL,"Can't Create Compatible DC.","ERROR",MB_OK|MB_ICONEXCLAMATION); //return FALSE; // Return FALSE } // Set up the bitmap setupDIB(); // Define the desired pixel format setupPixelFormat(); // Lock the mex file for return calls mexMakeMemoryPersistent(&wglInfo); initialised = 1; mexLock();}// This never actually gets used as MEX will clear everything when Matlab quitsLRESULT APIENTRY WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){ switch (message) { case WM_DESTROY: PostQuitMessage(0); return 0; default: break; } // Deal with any unprocessed messages return DefWindowProc(hWnd, message, wParam, lParam);}//****************************************************************************************// Set up a device independent bitmap in memory for offscreen renderingvoid setupDIB(void){ BITMAPINFO *bmInfo; BITMAPINFOHEADER *bmHeader; UINT usage; VOID *base; int bmiSize; int bitsPerPixel; bmiSize = sizeof(*bmInfo); bitsPerPixel = GetDeviceCaps(wglInfo.hDC, BITSPIXEL); bmInfo = (BITMAPINFO *) calloc(1, bmiSize); bmHeader = &bmInfo->bmiHeader; bmHeader->biSize = sizeof(*bmHeader); bmHeader->biWidth = BMP_WIDTH; bmHeader->biHeight = BMP_HEIGHT; bmHeader->biPlanes = 1; bmHeader->biBitCount = bitsPerPixel; bmHeader->biXPelsPerMeter = 0; bmHeader->biYPelsPerMeter = 0; bmHeader->biClrUsed = 0; bmHeader->biClrImportant = 0; bmHeader->biCompression = BI_RGB; bmHeader->biSizeImage = 0; usage = DIB_RGB_COLORS; wglInfo.hBitmap = CreateDIBSection(wglInfo.hDC, bmInfo, usage, &base, NULL, 0); if(wglInfo.hBitmap == NULL) mexErrMsgTxt("Failed to create DIBSection."); wglInfo.hOldBitmap = SelectObject(wglInfo.hDC, wglInfo.hBitmap); free(bmInfo); }//****************************************************************************************// Set the desire pixel format and ensure we can select itvoid setupPixelFormat(void){ PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd 1, // version num PFD_SUPPORT_OPENGL, // support OpenGL 0, // pixel type 0, // 8-bit color depth 0, 0, 0, 0, 0, 0, // color bits (ignored) 0, // no alpha buffer 0, // alpha bits (ignored) 0, // no accumulation buffer 0, 0, 0, 0, // accum bits (ignored) 16, // depth buffer 0, // no stencil buffer 0, // no auxiliary buffers PFD_MAIN_PLANE, // main layer 0, // reserved 0, 0, 0, // no layer, visible, damage masks }; int SelectedPixelFormat; BOOL retVal; pfd.cColorBits = GetDeviceCaps(wglInfo.hDC, BITSPIXEL); pfd.iPixelType = PFD_TYPE_RGBA; pfd.dwFlags |= PFD_DRAW_TO_BITMAP; if (!(SelectedPixelFormat = ChoosePixelFormat(wglInfo.hDC, &pfd))) // Did Windows Find A Matching Pixel Format? { KillGLWindow(); // Reset The Display MessageBox(NULL,"Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION); //return FALSE; // Return FALSE } retVal = SetPixelFormat(wglInfo.hDC, SelectedPixelFormat, &pfd); if(!retVal) // Are We Able To Set The Pixel Format? { KillGLWindow(); // Reset The Display MessageBox(NULL,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION); //return FALSE; // Return FALSE } }void KillGLWindow(void){}//****************************************************************************************//****************************************************************************************//******************************** OpenGL Stuff **************************************//****************************************************************************************//****************************************************************************************void InitGL(void){ glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_FLAT); glViewport(0, 0, BMP_WIDTH, BMP_HEIGHT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0, BMP_WIDTH, 0.0, BMP_HEIGHT, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity();glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_PACK_ALIGNMENT, 1);}void InitTexture(void){ glGenTextures(1, &texName); glBindTexture(GL_TEXTURE_2D, texName); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, 3, BMP_WIDTH, BMP_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);}//****************************************************************************************//****************************************************************************************//******************************** Iain's Stuff ***************************************//****************************************************************************************//****************************************************************************************GLubyte *GetInputImage(const mxArray *img, int *width, int *height){ int ndim, nx, ny; const int *dim; if(!mxIsNumeric(img) || mxIsEmpty(img) || !mxIsUint8(img)) mexErrMsgTxt("Input image must be uint8 2D or 3D numeric matrix"); ndim = mxGetNumberOfDimensions(img); if(ndim != 3) mexErrMsgTxt("Input image must be (nx * ny * 3) 24-bit RGB"); dim = mxGetDimensions(img); *width = nx = dim[0]; *height = ny = dim[1]; if(dim[2] > 3) mexWarnMsgTxt("Only using first 3 values of 3rd dimension"); else if(dim[2] < 3) mexErrMsgTxt("Third dimension must have size = 3"); return((GLubyte*)mxGetData(img));}float *ScaleTexVert(float *vert, int Nvert, int width, int height){ int k; float *tvert, xval, yval; if((tvert = (float*)mxCalloc(2 * Nvert, sizeof(float))) == NULL) mexErrMsgTxt("Unable to allocate texture vertices\n"); for(k = 0; k < Nvert; k++) { xval = vert[k*2]; yval = vert[(k*2)+1]; tvert[k*2] = xval / (float)width; tvert[(k*2)+1] = yval / (float)height; } return(tvert);}void ParseVert(float *vert, int nvert, int *opwidth, int *opheight){ float maxx = -10000.0, maxy = -10000.0; float x, y; int k; for(k = 0; k < nvert; k++) { x = vert[k*2]; y = vert[(k*2)+1]; if (maxx < x) maxx = x; if (maxy < y) maxy = y; } // Return the number of pixels in the output image *opwidth = (int)floor(maxx + 0.5); *opheight = (int)floor(maxy + 0.5);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -