diff options
author | ultramn <dchapm2@umbc.edu> | 2017-05-14 18:54:49 -0700 |
---|---|---|
committer | ultramn <dchapm2@umbc.edu> | 2017-05-14 18:54:49 -0700 |
commit | 0d83014f61489522b9b55f3966eaf4c9578a14e5 (patch) | |
tree | 65e36dddc8b212250c84fb0a159bb3bc97838152 /redist | |
parent | 006af3f9b168fcde6892a22ae914b5b55634b2ca (diff) | |
parent | 2e8bf907f46bcb98b3b482e957b98c52cacb6a4b (diff) | |
download | libsurvive-0d83014f61489522b9b55f3966eaf4c9578a14e5.tar.gz libsurvive-0d83014f61489522b9b55f3966eaf4c9578a14e5.tar.bz2 |
Merge branch 'master' of https://github.com/cnlohr/libsurvive
Diffstat (limited to 'redist')
-rw-r--r-- | redist/CNFGFunctions.c (renamed from redist/DrawFunctions.c) | 97 | ||||
-rw-r--r-- | redist/CNFGFunctions.h (renamed from redist/DrawFunctions.h) | 13 | ||||
-rw-r--r-- | redist/CNFGNullDriver.c (renamed from redist/RawDrawNull.c) | 2 | ||||
-rw-r--r-- | redist/CNFGRasterizer.h (renamed from redist/RawDrawRasterizer.c) | 33 | ||||
-rw-r--r-- | redist/CNFGWinDriver.c (renamed from redist/WinDriver.c) | 299 | ||||
-rw-r--r-- | redist/CNFGXDriver.c (renamed from redist/XDriver.c) | 90 | ||||
-rw-r--r-- | redist/json_helpers.c | 62 | ||||
-rw-r--r-- | redist/json_helpers.h | 4 | ||||
-rw-r--r-- | redist/linmath.c | 36 | ||||
-rw-r--r-- | redist/linmath.h | 1 | ||||
-rw-r--r-- | redist/os_generic.c | 17 | ||||
-rw-r--r-- | redist/svd.h | 450 |
12 files changed, 952 insertions, 152 deletions
diff --git a/redist/DrawFunctions.c b/redist/CNFGFunctions.c index f4f27d2..25e9298 100644 --- a/redist/DrawFunctions.c +++ b/redist/CNFGFunctions.c @@ -21,14 +21,13 @@ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "DrawFunctions.h" +#include "CNFGFunctions.h" #include <stdio.h> int CNFGPenX, CNFGPenY; uint32_t CNFGBGColor; uint32_t CNFGLastColor; uint32_t CNFGDialogColor; //background for boxes - const unsigned short FontCharMap[256] = { 65535, 0, 10, 20, 32, 44, 56, 68, 70, 65535, 65535, 80, 92, 65535, 104, 114, 126, 132, 138, 148, 156, 166, 180, 188, 200, 206, 212, 218, 224, 228, 238, 244, @@ -68,7 +67,7 @@ const unsigned char FontCharData[1902] = { 0x23, 0x14, 0x14, 0x03, 0x10, 0x94, 0x00, 0x01, 0x23, 0x24, 0x04, 0x03, 0x03, 0x21, 0x21, 0xa0, 0x21, 0x10, 0x10, 0x01, 0x01, 0x12, 0x12, 0x03, 0x03, 0x14, 0x14, 0x23, 0x02, 0xa4, 0x10, 0x91, 0x10, 0x01, 0x01, 0x03, 0x03, 0x94, 0x10, 0x21, 0x21, 0x23, 0x23, 0x94, 0x01, 0x23, 0x11, 0x13, - 0x21, 0x03, 0x02, 0xa2, 0x02, 0x22, 0x11, 0x93, 0x31, 0xc0, 0x03, 0xa1, 0x00, 0x20, 0x20, 0x24, + 0x21, 0x03, 0x02, 0xa2, 0x02, 0x22, 0x11, 0x93, 0x04, 0x93, 0x03, 0xa1, 0x00, 0x20, 0x20, 0x24, 0x24, 0x04, 0x04, 0x00, 0x12, 0x92, 0x01, 0x10, 0x10, 0x14, 0x04, 0xa4, 0x01, 0x10, 0x10, 0x21, 0x21, 0x22, 0x22, 0x04, 0x04, 0xa4, 0x00, 0x20, 0x20, 0x24, 0x24, 0x04, 0x12, 0xa2, 0x00, 0x02, 0x02, 0x22, 0x20, 0xa4, 0x20, 0x00, 0x00, 0x02, 0x02, 0x22, 0x22, 0x24, 0x24, 0x84, 0x20, 0x02, @@ -208,11 +207,7 @@ void CNFGDrawText( const char * text, int scale ) int x2 = (int)((((*(lmap+1)) & 0x70)>>4)*scale + iox); int y2 = (int)(((*(lmap+1)) & 0x0f)*scale + ioy); lmap++; - if(x1 == x2 && y1 == y2){ - CNFGTackPixel( x1, y1 ); - } else { - CNFGTackSegment( x1, y1, x2, y2 ); - } + CNFGTackSegment( x1, y1, x2, y2 ); bQuit = *lmap & 0x80; lmap++; } while( !bQuit ); @@ -275,3 +270,89 @@ void CNFGDrawTextbox( int x, int y, const char * text, int textsize ) CNFGPenY = y + textsize; CNFGDrawText( text, textsize ); } + + +#ifdef CNFGOGL + +#ifdef _MSC_VER +#include <windows.h> +#pragma comment( lib, "OpenGL32.lib" ) +#endif +#include <GL/gl.h> + +uint32_t CNFGColor( uint32_t RGB ) +{ + unsigned char red = RGB & 0xFF; + unsigned char grn = ( RGB >> 8 ) & 0xFF; + unsigned char blu = ( RGB >> 16 ) & 0xFF; + glColor3ub( red, grn, blu ); +} + +void CNFGClearFrame() +{ + short w, h; + unsigned char red = CNFGBGColor & 0xFF; + unsigned char grn = ( CNFGBGColor >> 8 ) & 0xFF; + unsigned char blu = ( CNFGBGColor >> 16 ) & 0xFF; + glClearColor( red/255.0, grn/255.0, blu/255.0, 1.0 ); + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + CNFGGetDimensions( &w, &h ); + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glViewport( 0, 0, w, h ); + glOrtho( 0, w, h, 0, 1, -1 ); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); +} + + +void CNFGTackSegment( short x1, short y1, short x2, short y2 ) +{ + if( x1 == x2 && y1 == y2 ) + { + glBegin( GL_POINTS ); + glVertex2f( x1+.5, y1+.5 ); + glEnd(); + } + else + { + glBegin( GL_LINES ); + glVertex2f( x1+.5, y1+.5 ); + glVertex2f( x2+.5, y2+.5 ); + glEnd(); + } +} + +void CNFGTackPixel( short x1, short y1 ) +{ + glBegin( GL_POINTS ); + glVertex2f( x1, y1 ); + glEnd(); +} + +void CNFGTackRectangle( short x1, short y1, short x2, short y2 ) +{ + glBegin( GL_QUADS ); + glVertex2f( x1, y1 ); + glVertex2f( x2, y1 ); + glVertex2f( x2, y2 ); + glVertex2f( x1, y2 ); + glEnd(); +} + +void CNFGTackPoly( RDPoint * points, int verts ) +{ + int i; + glBegin( GL_TRIANGLE_FAN ); + glVertex2f( points[0].x, points[0].y ); + for( i = 1; i < verts; i++ ) + { + glVertex2f( points[i].x, points[i].y ); + } + glEnd(); +} + +void CNFGInternalResize( short x, short y ) { } + + +#endif diff --git a/redist/DrawFunctions.h b/redist/CNFGFunctions.h index 542fcf9..179a20b 100644 --- a/redist/DrawFunctions.h +++ b/redist/CNFGFunctions.h @@ -1,4 +1,4 @@ -//Copyright (c) 2011 <>< Charles Lohr - Under the MIT/x11 or NewBSD License you choose. +//Copyright (c) 2011, 2017 <>< Charles Lohr - Under the MIT/x11 or NewBSD License you choose. #ifndef _DRAWFUCNTIONS_H #define _DRAWFUCNTIONS_H @@ -34,7 +34,6 @@ void CNFGClearFrame(); void CNFGSwapBuffers(); void CNFGGetDimensions( short * x, short * y ); -void CNFGTearDown(); void CNFGSetup( const char * WindowName, int w, int h ); void CNFGSetupFullscreen( const char * WindowName, int screen_number ); void CNFGHandleInput(); @@ -44,8 +43,18 @@ void CNFGHandleInput(); void HandleKey( int keycode, int bDown ); void HandleButton( int x, int y, int button, int bDown ); void HandleMotion( int x, int y, int mask ); +void HandleDestroy(); +//Internal function for resizing rasterizer for rasterizer-mode. +void CNFGInternalResize( short x, short y ); //don't call this. + +//Not available on all systems. Use The OGL portion with care. +#ifdef CNFGOGL +void CNFGSetVSync( int vson ); +void * CNFGGetExtension( const char * extname ); +#endif + #ifdef __cplusplus }; #endif diff --git a/redist/RawDrawNull.c b/redist/CNFGNullDriver.c index 34346cc..c35884a 100644 --- a/redist/RawDrawNull.c +++ b/redist/CNFGNullDriver.c @@ -1,6 +1,6 @@ //Copyright (c) 2017 <>< Charles Lohr - Under the MIT/x11 or NewBSD License you choose. -#include "DrawFunctions.h" +#include "CNFGFunctions.h" static int w, h; void CNFGGetDimensions( short * x, short * y ) diff --git a/redist/RawDrawRasterizer.c b/redist/CNFGRasterizer.h index af40588..1b8e2dd 100644 --- a/redist/RawDrawRasterizer.c +++ b/redist/CNFGRasterizer.h @@ -1,6 +1,7 @@ +//Don't call this file yourself. It is intended to be included in any drivers which want to support the rasterizer plugin. + #ifdef RASTERIZER -#include "DrawFunctions.h" -#include <stdio.h> +#include "CNFGFunctions.h" #include <stdlib.h> #include <stdint.h> @@ -8,6 +9,15 @@ static uint32_t * buffer = 0; static short bufferx; static short buffery; + +void CNFGInternalResize( short x, short y ) +{ + bufferx = x; + buffery = y; + if( buffer ) free( buffer ); + buffer = malloc( bufferx * buffery * 4 ); +} + static uint32_t SWAPS( uint32_t r ) { uint32_t ret = (r&0xFF)<<16; @@ -24,11 +34,6 @@ uint32_t CNFGColor( uint32_t RGB ) return CNFGLastColor; } -void CNFGTackPixel( short x, short y ) -{ - buffer[bufferx*y+x] = CNFGLastColor; -} - void CNFGTackSegment( short x1, short y1, short x2, short y2 ) { short tx, ty; @@ -53,11 +58,11 @@ void CNFGTackSegment( short x1, short y1, short x2, short y2 ) for( tx = minx; tx <= maxx; tx++ ) { - thisy += slope; ty = thisy; if( tx < 0 || ty < 0 || ty >= buffery ) continue; if( tx >= bufferx ) break; buffer[ty * bufferx + tx] = CNFGLastColor; + thisy += slope; } } else @@ -71,15 +76,14 @@ void CNFGTackSegment( short x1, short y1, short x2, short y2 ) for( ty = miny; ty <= maxy; ty++ ) { - thisx += slope; tx = thisx; if( ty < 0 || tx < 0 || tx >= bufferx ) continue; if( ty >= buffery ) break; buffer[ty * bufferx + tx] = CNFGLastColor; + thisx += slope; } } } - void CNFGTackRectangle( short x1, short y1, short x2, short y2 ) { short minx = (x1<x2)?x1:x2; @@ -216,7 +220,6 @@ void CNFGClearFrame() { bufferx = x; buffery = y; - printf( "MALLOCING: %d\n", x * y ); buffer = malloc( x * y * 8 ); } @@ -229,9 +232,15 @@ void CNFGClearFrame() } } +void CNFGTackPixel( short x, short y ) +{ + if( x < 0 || y < 0 || x >= bufferx || y >= buffery ) return; + buffer[x+bufferx*y] = CNFGLastColor; +} + void CNFGSwapBuffers() { - CNFGUpdateScreenWithBitmap( buffer, bufferx, buffery ); + CNFGUpdateScreenWithBitmap( (long unsigned int*)buffer, bufferx, buffery ); } diff --git a/redist/WinDriver.c b/redist/CNFGWinDriver.c index 3613150..b1c1eb0 100644 --- a/redist/WinDriver.c +++ b/redist/CNFGWinDriver.c @@ -2,80 +2,73 @@ //Portion from: http://en.wikibooks.org/wiki/Windows_Programming/Window_Creation -#include "DrawFunctions.h" +#include "CNFGFunctions.h" #include <windows.h> #include <stdlib.h> #include <malloc.h> //for alloca +static HBITMAP lsBitmap; static HINSTANCE lhInstance; static HWND lsHWND; -static HDC lsHDC; -static HBITMAP lsBackBitmap; static HDC lsWindowHDC; -static HBRUSH lsHBR; -static HPEN lsHPEN; -static HBRUSH lsClearBrush; -static unsigned int lsLastWidth; -static unsigned int lsLastHeight; - -static void InternalHandleResize() -{ - DeleteObject( lsBackBitmap ); - lsBackBitmap = CreateCompatibleBitmap( lsHDC, lsLastWidth, lsLastHeight ); - SelectObject( lsHDC, lsBackBitmap ); +static HDC lsHDC; -} +#ifdef RASTERIZER +#include "CNFGRasterizer.h" -uint32_t CNFGColor( uint32_t RGB ) +void InternalHandleResize() { - CNFGLastColor = RGB; - - DeleteObject( lsHBR ); - lsHBR = CreateSolidBrush( RGB ); - SelectObject( lsHDC, lsHBR ); + if( lsBitmap ) DeleteObject( lsBitmap ); - DeleteObject( lsHPEN ); - lsHPEN = CreatePen( PS_SOLID, 0, RGB ); - SelectObject( lsHDC, lsHPEN ); - - return RGB; + CNFGInternalResize( bufferx, buffery ); + lsBitmap = CreateBitmap( bufferx, buffery, 1, 32, buffer ); + SelectObject( lsHDC, lsBitmap ); } +#else +static int bufferx, buffery; +static int bufferx, buffery; +static void InternalHandleResize(); +#endif -void CNFGTackSegment( short x1, short y1, short x2, short y2 ) -{ - POINT pt[2] = { {x1, y1}, {x2, y2} }; - Polyline( lsHDC, pt, 2 ); - SetPixel( lsHDC, x1, y1, CNFGLastColor ); - SetPixel( lsHDC, x2, y2, CNFGLastColor ); -} -void CNFGTackRectangle( short x1, short y1, short x2, short y2 ) +#ifdef CNFGOGL +#include <GL/gl.h> +static HGLRC hRC=NULL; +static void InternalHandleResize() { } +void CNFGSwapBuffers() { - RECT r; - if( x1 < x2 ) { r.left = x1; r.right = x2; } - else { r.left = x2; r.right = x1; } - if( y1 < y2 ) { r.top = y1; r.bottom = y2; } - else { r.top = y2; r.bottom = y1; } - FillRect( lsHDC, &r, lsHBR ); + SwapBuffers(lsWindowHDC); } +#endif -void CNFGClearFrame() +void CNFGGetDimensions( short * x, short * y ) { - RECT r = { 0, 0, lsLastWidth, lsLastHeight }; - DeleteObject( lsClearBrush ); - lsClearBrush = CreateSolidBrush( CNFGBGColor ); - SelectObject( lsHDC, lsClearBrush ); - - FillRect( lsHDC, &r, lsClearBrush ); + static int lastx, lasty; + RECT window; + GetClientRect( lsHWND, &window ); + bufferx = ( window.right - window.left); + buffery = ( window.bottom - window.top); + if( bufferx != lastx || buffery != lasty ) + { + lastx = bufferx; + lasty = buffery; + InternalHandleResize(); + } + *x = bufferx; + *y = buffery; } -void CNFGSwapBuffers() + +void CNFGUpdateScreenWithBitmap( unsigned long * data, int w, int h ) { - int thisw, thish; RECT r; - BitBlt( lsWindowHDC, 0, 0, lsLastWidth, lsLastHeight, lsHDC, 0, 0, SRCCOPY ); + + int a = SetBitmapBits(lsBitmap,w*h*4,data); + a = BitBlt(lsWindowHDC, 0, 0, w, h, lsHDC, 0, 0, SRCCOPY); UpdateWindow( lsHWND ); + int thisw, thish; + //Check to see if the window is closed. if( !IsWindow( lsHWND ) ) { @@ -85,36 +78,18 @@ void CNFGSwapBuffers() GetClientRect( lsHWND, &r ); thisw = r.right - r.left; thish = r.bottom - r.top; - if( thisw != lsLastWidth || thish != lsLastHeight ) + if( thisw != bufferx || thish != buffery ) { - lsLastWidth = thisw; - lsLastHeight = thish; + bufferx = thisw; + buffery = thish; InternalHandleResize(); } } -void CNFGTackPoly( RDPoint * points, int verts ) -{ - int i; - POINT * t = (POINT*)alloca( sizeof( POINT ) * verts ); - for( i = 0; i < verts; i++ ) - { - t[i].x = points[i].x; - t[i].y = points[i].y; - } - Polygon( lsHDC, t, verts ); -} - - -void CNFGTackPixel( short x1, short y1 ) -{ - SetPixel( lsHDC, x1, y1, CNFGLastColor ); -} -void CNFGGetDimensions( short * x, short * y ) +void CNFGTearDown() { - *x = lsLastWidth; - *y = lsLastHeight; + PostQuitMessage(0); } //This was from the article @@ -123,17 +98,13 @@ LRESULT CALLBACK MyWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) switch(msg) { case WM_DESTROY: + HandleDestroy(); CNFGTearDown(); return 0; } return DefWindowProc(hwnd, msg, wParam, lParam); } -void CNFGTearDown() -{ - PostQuitMessage(0); -} - //This was from the article, too... well, mostly. void CNFGSetup( const char * name_of_window, int width, int height ) { @@ -143,8 +114,8 @@ void CNFGSetup( const char * name_of_window, int width, int height ) int w, h, wd, hd; HINSTANCE hInstance = GetModuleHandle(NULL); - lsLastWidth = width; - lsLastHeight = height; + bufferx = width; + buffery = height; wnd.style = CS_HREDRAW | CS_VREDRAW; //we will explain this later wnd.lpfnWndProc = MyWndProc; @@ -167,22 +138,63 @@ void CNFGSetup( const char * name_of_window, int width, int height ) WS_OVERLAPPEDWINDOW, //basic window style CW_USEDEFAULT, CW_USEDEFAULT, //set starting point to default value - lsLastWidth, - lsLastHeight, //set all the dimensions to default value + bufferx, + buffery, //set all the dimensions to default value NULL, //no parent window NULL, //no menu hInstance, NULL); //no parameters to pass - lsWindowHDC = GetDC( lsHWND ); + +#ifdef CNFGOGL + //From NeHe + static PIXELFORMATDESCRIPTOR pfd = + { + sizeof(PIXELFORMATDESCRIPTOR), + 1, + PFD_DRAW_TO_WINDOW | + PFD_SUPPORT_OPENGL | + PFD_DOUBLEBUFFER, + PFD_TYPE_RGBA, + 32, + 0, 0, 0, 0, 0, 0, + 0, + 0, + 0, + 0, 0, 0, 0, + 16, + 0, + 0, + PFD_MAIN_PLANE, + 0, + 0, 0, 0 + }; + GLuint PixelFormat = ChoosePixelFormat( lsWindowHDC, &pfd ); + if( !SetPixelFormat( lsWindowHDC, PixelFormat, &pfd ) ) + { + MessageBox( 0, "Could not create PFD for OpenGL Context\n", 0, 0 ); + exit( -1 ); + } + if (!(hRC=wglCreateContext(lsWindowHDC))) // Are We Able To Get A Rendering Context? + { + MessageBox( 0, "Could not create OpenGL Context\n", 0, 0 ); + exit( -1 ); + } + if(!wglMakeCurrent(lsWindowHDC,hRC)) // Try To Activate The Rendering Context + { + MessageBox( 0, "Could not current OpenGL Context\n", 0, 0 ); + exit( -1 ); + } +#endif + lsHDC = CreateCompatibleDC( lsWindowHDC ); - lsBackBitmap = CreateCompatibleBitmap( lsWindowHDC, lsLastWidth, lsLastHeight ); - SelectObject( lsHDC, lsBackBitmap ); + lsBitmap = CreateCompatibleBitmap( lsWindowHDC, bufferx, buffery ); + SelectObject( lsHDC, lsBitmap ); - lsClearBrush = CreateSolidBrush( CNFGBGColor ); - lsHBR = CreateSolidBrush( 0xFFFFFF ); - lsHPEN = CreatePen( PS_SOLID, 0, 0xFFFFFF ); + //lsClearBrush = CreateSolidBrush( CNFGBGColor ); + //lsHBR = CreateSolidBrush( 0xFFFFFF ); + //lsHPEN = CreatePen( PS_SOLID, 0, 0xFFFFFF ); ShowWindow(lsHWND, 1); //display the window on the screen @@ -193,7 +205,7 @@ void CNFGSetup( const char * name_of_window, int width, int height ) h = ( window.bottom - window.top); wd = w - client.right; hd = h - client.bottom; - MoveWindow( lsHWND, window.left, window.top, lsLastWidth + wd, lsLastHeight + hd, 1 ); + MoveWindow( lsHWND, window.left, window.top, bufferx + wd, buffery + hd, 1 ); InternalHandleResize(); } @@ -220,7 +232,7 @@ void CNFGHandleInput() case WM_MBUTTONUP: HandleButton( (msg.lParam & 0xFFFF), (msg.lParam>>16) & 0xFFFF, 3, 0 ); break; case WM_KEYDOWN: case WM_KEYUP: - HandleKey( tolower( (int)msg.wParam ), (msg.message==WM_KEYDOWN) ); + HandleKey( tolower( (int)(msg.wParam) ), (msg.message==WM_KEYDOWN) ); break; default: DispatchMessage(&msg); @@ -229,3 +241,110 @@ void CNFGHandleInput() } } +#ifndef CNFGOGL + +#ifndef RASTERIZER + +static HBITMAP lsBackBitmap; +static HDC lsWindowHDC; +static HBRUSH lsHBR; +static HPEN lsHPEN; +static HBRUSH lsClearBrush; + +static void InternalHandleResize() +{ + DeleteObject( lsBackBitmap ); + lsBackBitmap = CreateCompatibleBitmap( lsHDC, bufferx, buffery ); + SelectObject( lsHDC, lsBackBitmap ); +} + +uint32_t CNFGColor( uint32_t RGB ) +{ + CNFGLastColor = RGB; + + DeleteObject( lsHBR ); + lsHBR = CreateSolidBrush( RGB ); + SelectObject( lsHDC, lsHBR ); + + DeleteObject( lsHPEN ); + lsHPEN = CreatePen( PS_SOLID, 0, RGB ); + SelectObject( lsHDC, lsHPEN ); + + return RGB; +} + +void CNFGTackSegment( short x1, short y1, short x2, short y2 ) +{ + POINT pt[2] = { {x1, y1}, {x2, y2} }; + Polyline( lsHDC, pt, 2 ); + SetPixel( lsHDC, x1, y1, CNFGLastColor ); + SetPixel( lsHDC, x2, y2, CNFGLastColor ); +} + +void CNFGTackRectangle( short x1, short y1, short x2, short y2 ) +{ + RECT r; + if( x1 < x2 ) { r.left = x1; r.right = x2; } + else { r.left = x2; r.right = x1; } + if( y1 < y2 ) { r.top = y1; r.bottom = y2; } + else { r.top = y2; r.bottom = y1; } + FillRect( lsHDC, &r, lsHBR ); +} + +void CNFGClearFrame() +{ + RECT r = { 0, 0, bufferx, buffery }; + DeleteObject( lsClearBrush ); + lsClearBrush = CreateSolidBrush( CNFGBGColor ); + SelectObject( lsHDC, lsClearBrush ); + FillRect( lsHDC, &r, lsClearBrush); +} + +void CNFGTackPoly( RDPoint * points, int verts ) +{ + int i; + POINT * t = (POINT*)alloca( sizeof( POINT ) * verts ); + for( i = 0; i < verts; i++ ) + { + t[i].x = points[i].x; + t[i].y = points[i].y; + } + Polygon( lsHDC, t, verts ); +} + + +void CNFGTackPixel( short x1, short y1 ) +{ + SetPixel( lsHDC, x1, y1, CNFGLastColor ); +} + +void CNFGSwapBuffers() +{ + int thisw, thish; + + RECT r; + BitBlt( lsWindowHDC, 0, 0, bufferx, buffery, lsHDC, 0, 0, SRCCOPY ); + UpdateWindow( lsHWND ); + //Check to see if the window is closed. + if( !IsWindow( lsHWND ) ) + { + exit( 0 ); + } + + GetClientRect( lsHWND, &r ); + thisw = r.right - r.left; + thish = r.bottom - r.top; + + if( thisw != bufferx || thish != buffery ) + { + bufferx = thisw; + buffery = thish; + InternalHandleResize(); + } +} + +void CNFGInternalResize( short bufferx, short buffery ) { } +#endif + +#endif + diff --git a/redist/XDriver.c b/redist/CNFGXDriver.c index 507ca95..ebaed91 100644 --- a/redist/XDriver.c +++ b/redist/CNFGXDriver.c @@ -1,10 +1,10 @@ -//Copyright (c) 2011 <>< Charles Lohr - Under the MIT/x11 or NewBSD License you choose. +//Copyright (c) 2011, 2017 <>< Charles Lohr - Under the MIT/x11 or NewBSD License you choose. //portions from //http://www.xmission.com/~georgeps/documentation/tutorials/Xlib_Beginner.html //#define HAS_XINERAMA -#include "DrawFunctions.h" +#include "CNFGFunctions.h" #include <X11/Xlib.h> #include <X11/Xutil.h> @@ -25,12 +25,33 @@ Window CNFGWindow; Pixmap CNFGPixmap; GC CNFGGC; GC CNFGWindowGC; +Visual * CNFGVisual; + + +#ifdef CNFGOGL +#include <GL/glx.h> +#include <GL/glxext.h> + +GLXContext CNFGCtx; +void * CNFGGetExtension( const char * extname ) { return glXGetProcAddressARB((const GLubyte *) extname); } +#endif + int FullScreen = 0; void CNFGGetDimensions( short * x, short * y ) { + static int lastx; + static int lasty; + *x = CNFGWinAtt.width; *y = CNFGWinAtt.height; + + if( lastx != *x || lasty != *y ) + { + lastx = *x; + lasty = *y; + CNFGInternalResize( lastx, lasty ); + } } static void InternalLinkScreenAndGo( const char * WindowName ) @@ -76,7 +97,7 @@ void CNFGSetupFullscreen( const char * WindowName, int screen_no ) exit( 1 ); } - Visual * visual = DefaultVisual(CNFGDisplay, screen); + CNFGVisual = DefaultVisual(CNFGDisplay, screen); CNFGWinAtt.depth = DefaultDepth(CNFGDisplay, screen); if (XineramaQueryExtension(CNFGDisplay, &a, &b ) && @@ -107,7 +128,9 @@ void CNFGSetupFullscreen( const char * WindowName, int screen_no ) CNFGWindow = XCreateWindow(CNFGDisplay, XRootWindow(CNFGDisplay, screen), xpos, ypos, CNFGWinAtt.width, CNFGWinAtt.height, - 0, CNFGWinAtt.depth, InputOutput, visual, CWBorderPixel | CWEventMask | CWOverrideRedirect | CWSaveUnder, &setwinattr); + 0, CNFGWinAtt.depth, InputOutput, CNFGVisual, + CWBorderPixel | CWEventMask | CWOverrideRedirect | CWSaveUnder, + &setwinattr); XMapWindow(CNFGDisplay, CNFGWindow); XSetInputFocus( CNFGDisplay, CNFGWindow, RevertToParent, CurrentTime ); @@ -145,7 +168,31 @@ void CNFGSetup( const char * WindowName, int w, int h ) XGetWindowAttributes( CNFGDisplay, RootWindow(CNFGDisplay, 0), &CNFGWinAtt ); int depth = CNFGWinAtt.depth; - CNFGWindow = XCreateWindow(CNFGDisplay, RootWindow(CNFGDisplay, 0), 1, 1, w, h, 0, depth, InputOutput, CopyFromParent, 0, 0 ); + int screen = DefaultScreen(CNFGDisplay); + CNFGVisual = DefaultVisual(CNFGDisplay, screen); + +#ifdef CNFGOGL + int attribs[] = { GLX_RGBA, + GLX_DOUBLEBUFFER, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_DEPTH_SIZE, 1, + None }; + XVisualInfo * vis = glXChooseVisual(CNFGDisplay, screen, attribs); + CNFGVisual = vis->visual; + depth = vis->depth; + CNFGCtx = glXCreateContext( CNFGDisplay, vis, NULL, True ); +#endif + + XSetWindowAttributes attr; + attr.background_pixel = 0; + attr.border_pixel = 0; + attr.colormap = XCreateColormap( CNFGDisplay, RootWindow(CNFGDisplay, 0), CNFGVisual, AllocNone); + attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask; + int mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; + + CNFGWindow = XCreateWindow(CNFGDisplay, RootWindow(CNFGDisplay, 0), 1, 1, w, h, 0, depth, InputOutput, CNFGVisual, mask, &attr ); XMapWindow(CNFGDisplay, CNFGWindow); XFlush(CNFGDisplay); @@ -153,7 +200,12 @@ void CNFGSetup( const char * WindowName, int w, int h ) Atom WM_DELETE_WINDOW = XInternAtom( CNFGDisplay, "WM_DELETE_WINDOW", False ); XSetWMProtocols( CNFGDisplay, CNFGWindow, &WM_DELETE_WINDOW, 1 ); + XSelectInput( CNFGDisplay, CNFGWindow, KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | ExposureMask | PointerMotionMask ); + +#ifdef CNFGOGL + glXMakeCurrent( CNFGDisplay, CNFGWindow, CNFGCtx ); +#endif } void CNFGHandleInput() @@ -216,7 +268,6 @@ void CNFGUpdateScreenWithBitmap( unsigned long * data, int w, int h ) if( !xi ) { int screen = DefaultScreen(CNFGDisplay); - Visual * visual = DefaultVisual(CNFGDisplay, screen); depth = DefaultDepth(CNFGDisplay, screen)/8; // xi = XCreateImage(CNFGDisplay, DefaultVisual( CNFGDisplay, DefaultScreen(CNFGDisplay) ), depth*8, ZPixmap, 0, (char*)data, w, h, 32, w*4 ); // lw = w; @@ -226,7 +277,7 @@ void CNFGUpdateScreenWithBitmap( unsigned long * data, int w, int h ) if( lw != w || lh != h ) { if( xi ) free( xi ); - xi = XCreateImage(CNFGDisplay, DefaultVisual( CNFGDisplay, DefaultScreen(CNFGDisplay) ), depth*8, ZPixmap, 0, (char*)data, w, h, 32, w*4 ); + xi = XCreateImage(CNFGDisplay, CNFGVisual, depth*8, ZPixmap, 0, (char*)data, w, h, 32, w*4 ); lw = w; lh = h; } @@ -237,7 +288,25 @@ void CNFGUpdateScreenWithBitmap( unsigned long * data, int w, int h ) } -#ifndef RASTERIZER +#ifdef CNFGOGL + +void CNFGSetVSync( int vson ) +{ + void (*glfn)( int ); + glfn = (void (*)( int ))CNFGGetExtension( "glXSwapIntervalMESA" ); if( glfn ) glfn( vson ); + glfn = (void (*)( int ))CNFGGetExtension( "glXSwapIntervalSGI" ); if( glfn ) glfn( vson ); + glfn = (void (*)( int ))CNFGGetExtension( "glXSwapIntervalEXT" ); if( glfn ) glfn( vson ); +} + +void CNFGSwapBuffers() +{ + glFlush(); + glFinish(); + glXSwapBuffers( CNFGDisplay, CNFGWindow ); +} +#endif + +#if !defined( RASTERIZER ) && !defined( CNFGOGL) uint32_t CNFGColor( uint32_t RGB ) @@ -286,5 +355,10 @@ void CNFGTackPoly( RDPoint * points, int verts ) XFillPolygon(CNFGDisplay, CNFGPixmap, CNFGGC, (XPoint *)points, 3, Convex, CoordModeOrigin ); } +void CNFGInternalResize( short x, short y ) { } + +#else +#include "CNFGRasterizer.h" #endif + diff --git a/redist/json_helpers.c b/redist/json_helpers.c index 0267932..af7ddda 100644 --- a/redist/json_helpers.c +++ b/redist/json_helpers.c @@ -50,44 +50,46 @@ void json_write_float_array(FILE* f, const char* tag, float* v, uint8_t count) { uint8_t i = 0; char * str1 = NULL; char * str2 = NULL; - asprintf(&str1,"\"%s\":[", tag); + if( asprintf(&str1,"\"%s\":[", tag) < 0 ) goto giveup; for (i=0;i<count;++i) { if ( (i+1) < count) { - asprintf(&str2, "%s\"%f\"", str1,v[i]); + if( asprintf(&str2, "%s\"%f\"", str1,v[i]) < 0 ) goto giveup; } else { - asprintf(&str2, "%s\"%f\",", str1,v[i]); + if( asprintf(&str2, "%s\"%f\",", str1,v[i]) < 0 ) goto giveup; } free(str1); str1=str2; str2=NULL; } - asprintf(&str2, "%s]", str1); + if( asprintf(&str2, "%s]", str1) < 0 ) goto giveup; fputs(str2,f); - free(str1); - free(str2); +giveup: + if( str1 ) free(str1); + if( str2 ) free(str2); } void json_write_double_array(FILE* f, const char* tag, double* v, uint8_t count) { uint8_t i = 0; char * str1 = NULL; char * str2 = NULL; - asprintf(&str1,"\"%s\":[", tag); + if( asprintf(&str1,"\"%s\":[", tag) < 0 ) goto giveup; for (i=0;i<count;++i) { if (i<(count-1)) { - asprintf(&str2, "%s\"%f\",", str1,v[i]); + if( asprintf(&str2, "%s\"%f\",", str1,v[i]) < 0 ) goto giveup; } else { - asprintf(&str2, "%s\"%f\"", str1,v[i]); + if( asprintf(&str2, "%s\"%f\"", str1,v[i]) < 0 ) goto giveup; } free(str1); str1=str2; str2=NULL; } - asprintf(&str2, "%s]", str1); + if( asprintf(&str2, "%s]", str1) < 0 ) goto giveup; fputs(str2,f); - free(str1); - free(str2); +giveup: + if( str1 ) free(str1); + if( str2 ) free(str2); } void json_write_uint32(FILE* f, const char* tag, uint32_t v) { @@ -117,8 +119,9 @@ char* load_file_to_mem(const char* path) { fseek( f, 0, SEEK_END ); int len = ftell( f ); fseek( f, 0, SEEK_SET ); - char * JSON_STRING = malloc( len ); - fread( JSON_STRING, len, 1, f ); + char * JSON_STRING = malloc( len + 1); + memset(JSON_STRING,0,len+1); + int i = fread( JSON_STRING, len, 1, f ); i = i; //Ignore return value. fclose( f ); return JSON_STRING; } @@ -173,7 +176,7 @@ void json_load_file(const char* path) { int16_t children = -1; - for (i=0; i<(int)items; i+=2) + for (i=0; i<(unsigned int)items; i+=2) { //increment i on each successful tag + values combination, not individual tokens jsmntok_t* tag_t = tokens+i; @@ -213,3 +216,32 @@ void json_load_file(const char* path) { free(JSON_STRING); } +int parse_float_array(char* str, jsmntok_t* token, FLT** f, uint8_t count) { + uint16_t i = 0; + + if (count==0) return 0; + + if (*f!=NULL) free(*f); + *f = malloc(sizeof(FLT) * count); + + for(i=0;i<count;++i) { + char* end = str + token->end; + char* s = str+token->start; + + #ifdef USE_DOUBLE + (*f)[i] = strtod(s, &end); + #else + (*f)[i] = strtof(s, &end); + #endif + + if (s == end) { + free(*f); + *f=NULL; + return 0; //not a float + } + token++; + } + + + return count; +}
\ No newline at end of file diff --git a/redist/json_helpers.h b/redist/json_helpers.h index 1cccfe3..3ebf66b 100644 --- a/redist/json_helpers.h +++ b/redist/json_helpers.h @@ -4,6 +4,8 @@ #define JSON_HELPERS_H #include <stdint.h> +#include <jsmn.h> +#include "survive_types.h" void json_write_float_array(FILE* f, const char* tag, float* v, uint8_t count); void json_write_double_array(FILE* f, const char* tag, double* v, uint8_t count); @@ -11,6 +13,8 @@ void json_write_uint32(FILE* f, const char* tag, uint32_t v); void json_write_float(FILE* f, const char* tag, float v); void json_write_str(FILE* f, const char* tag, const char* v); +int parse_float_array(char* str, jsmntok_t* token, FLT** values, uint8_t count); + void json_load_file(const char* path); extern void (*json_begin_object)(char* tag); extern void (*json_end_object)(); diff --git a/redist/linmath.c b/redist/linmath.c index eefcd5f..5fefe1e 100644 --- a/redist/linmath.c +++ b/redist/linmath.c @@ -82,6 +82,28 @@ FLT anglebetween3d( FLT * a, FLT * b ) return FLT_ACOS(dot); } +// algorithm found here: http://inside.mines.edu/fs_home/gmurray/ArbitraryAxisRotation/ +void rotatearoundaxis(FLT *outvec3, FLT *invec3, FLT *axis, FLT angle) +{ + // TODO: this really should be external. + normalize3d(axis, axis); + + FLT s = FLT_SIN(angle); + FLT c = FLT_COS(angle); + + FLT u=axis[0]; + FLT v=axis[1]; + FLT w=axis[2]; + + FLT x=invec3[0]; + FLT y=invec3[1]; + FLT z=invec3[2]; + + outvec3[0] = u*(u*x + v*y + w*z)*(1-c) + x*c + (-w*y + v*z)*s; + outvec3[1] = v*(u*x + v*y + w*z)*(1-c) + y*c + ( w*x - u*z)*s; + outvec3[2] = w*(u*x + v*y + w*z)*(1-c) + z*c + (-v*x + u*y)*s; +} + /////////////////////////////////////QUATERNIONS////////////////////////////////////////// //Originally from Mercury (Copyright (C) 2009 by Joshua Allen, Charles Lohr, Adam Lowman) //Under the mit/X11 license. @@ -215,7 +237,7 @@ void quatfrommatrix( FLT * q, const FLT * matrix44 ) q[1] = (matrix44[9] - matrix44[6]) / S; q[2] = (matrix44[2] - matrix44[8]) / S; q[3] = (matrix44[4] - matrix44[1]) / S; - } else if ((matrix44[0] > matrix44[5])&(matrix44[0] > matrix44[10])) { + } else if ((matrix44[0] > matrix44[5])&&(matrix44[0] > matrix44[10])) { FLT S = FLT_SQRT(1.0 + matrix44[0] - matrix44[5] - matrix44[10]) * 2.; // S=4*qx q[0] = (matrix44[9] - matrix44[6]) / S; q[1] = 0.25f * S; @@ -498,17 +520,15 @@ void quatfrom2vectors(FLT *q, const FLT *src, const FLT *dest) FLT invs = 1 / s; FLT c[3]; - //cross3d(c, v0, v1); - cross3d(c, v1, v0); + cross3d(c, v0, v1); - q[0] = c[0] * invs; - q[1] = c[1] * invs; - q[2] = c[2] * invs; - q[3] = s * 0.5f; + q[0] = s * 0.5f; + q[1] = c[0] * invs; + q[2] = c[1] * invs; + q[3] = c[2] * invs; quatnormalize(q, q); } - } void matrix44copy(FLT * mout, const FLT * minm ) diff --git a/redist/linmath.h b/redist/linmath.h index 4e0cb77..6f0bf60 100644 --- a/redist/linmath.h +++ b/redist/linmath.h @@ -70,6 +70,7 @@ FLT magnitude3d(const FLT * a ); FLT anglebetween3d( FLT * a, FLT * b ); +void rotatearoundaxis(FLT *outvec3, FLT *invec3, FLT *axis, FLT angle); //Quaternion things... void quatsetnone( FLT * q ); diff --git a/redist/os_generic.c b/redist/os_generic.c index 1ab4863..3191357 100644 --- a/redist/os_generic.c +++ b/redist/os_generic.c @@ -151,8 +151,9 @@ void OGDeleteSema( og_sema_t os ) #else -#define _GNU_SOURCE - +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif #include <sys/stat.h> #include <stdlib.h> @@ -198,7 +199,7 @@ double OGGetFileTime( const char * file ) og_thread_t OGCreateThread( void * (routine)( void * ), void * parameter ) { - pthread_t * ret = malloc( sizeof( pthread_t ) ); + pthread_t * ret = (pthread_t *)malloc( sizeof( pthread_t ) ); int r = pthread_create( ret, 0, routine, parameter ); if( r ) { @@ -277,7 +278,7 @@ void OGDeleteMutex( og_mutex_t om ) og_sema_t OGCreateSema() { - sem_t * sem = malloc( sizeof( sem_t ) ); + sem_t * sem = (sem_t *)malloc( sizeof( sem_t ) ); sem_init( sem, 0, 0 ); return (og_sema_t)sem; } @@ -285,24 +286,24 @@ og_sema_t OGCreateSema() int OGGetSema( og_sema_t os ) { int valp; - sem_getvalue( os, &valp ); + sem_getvalue( (sem_t *)os, &valp ); return valp; } void OGLockSema( og_sema_t os ) { - sem_wait( os ); + sem_wait( (sem_t *)os ); } void OGUnlockSema( og_sema_t os ) { - sem_post( os ); + sem_post( (sem_t *)os ); } void OGDeleteSema( og_sema_t os ) { - sem_destroy( os ); + sem_destroy( (sem_t *)os ); free(os); } diff --git a/redist/svd.h b/redist/svd.h new file mode 100644 index 0000000..41708da --- /dev/null +++ b/redist/svd.h @@ -0,0 +1,450 @@ +/************************************************************************** +** +** svd3 +** +** Quick singular value decomposition as described by: +** A. McAdams, A. Selle, R. Tamstorf, J. Teran and E. Sifakis, +** "Computing the Singular Value Decomposition of 3x3 matrices +** with minimal branching and elementary floating point operations", +** University of Wisconsin - Madison technical report TR1690, May 2011 +** +** OPTIMIZED CPU VERSION +** Implementation by: Eric Jang +** +** 13 Apr 2014 +** +** This file originally retrieved from: +** https://github.com/ericjang/svd3/blob/master/svd3.h 3/26/2017 +** +** Original licesnse is MIT per: +** https://github.com/ericjang/svd3/blob/master/LICENSE.md +** +** Ported from C++ to C by Mike Turvey. All modifications also released +** under an MIT license. +**************************************************************************/ + + +#ifndef SVD3_H +#define SVD3_H + +#define _gamma 5.828427124 // FOUR_GAMMA_SQUARED = sqrt(8)+3; +#define _cstar 0.923879532 // cos(pi/8) +#define _sstar 0.3826834323 // sin(p/8) +#define EPSILON 1e-6 + +#include <math.h> + +/* This is a novel and fast routine for the reciprocal square root of an +IEEE float (single precision). +http://www.lomont.org/Math/Papers/2003/InvSqrt.pdf +http://playstation2-linux.com/download/p2lsd/fastrsqrt.pdf +http://www.beyond3d.com/content/articles/8/ +*/ +inline float rsqrt(float x) { + // int ihalf = *(int *)&x - 0x00800000; // Alternative to next line, + // float xhalf = *(float *)&ihalf; // for sufficiently large nos. + float xhalf = 0.5f*x; + int i = *(int *)&x; // View x as an int. + // i = 0x5f3759df - (i >> 1); // Initial guess (traditional). + i = 0x5f375a82 - (i >> 1); // Initial guess (slightly better). + x = *(float *)&i; // View i as float. + x = x*(1.5f - xhalf*x*x); // Newton step. + // x = x*(1.5008908 - xhalf*x*x); // Newton step for a balanced error. + return x; +} + +/* This is rsqrt with an additional step of the Newton iteration, for +increased accuracy. The constant 0x5f37599e makes the relative error +range from 0 to -0.00000463. +You can't balance the error by adjusting the constant. */ +inline float rsqrt1(float x) { + float xhalf = 0.5f*x; + int i = *(int *)&x; // View x as an int. + i = 0x5f37599e - (i >> 1); // Initial guess. + x = *(float *)&i; // View i as float. + x = x*(1.5f - xhalf*x*x); // Newton step. + x = x*(1.5f - xhalf*x*x); // Newton step again. + return x; +} + +inline float accurateSqrt(float x) +{ + return x * rsqrt1(x); +} + +inline void condSwap(bool c, float *X, float *Y) +{ + // used in step 2 + float Z = *X; + *X = c ? *Y : *X; + *Y = c ? Z : *Y; +} + +inline void condNegSwap(bool c, float *X, float *Y) +{ + // used in step 2 and 3 + float Z = -*X; + *X = c ? *Y : *X; + *Y = c ? Z : *Y; +} + +// matrix multiplication M = A * B +inline void multAB(float a11, float a12, float a13, + float a21, float a22, float a23, + float a31, float a32, float a33, + // + float b11, float b12, float b13, + float b21, float b22, float b23, + float b31, float b32, float b33, + // + float *m11, float *m12, float *m13, + float *m21, float *m22, float *m23, + float *m31, float *m32, float *m33) +{ + + *m11 = a11*b11 + a12*b21 + a13*b31; *m12 = a11*b12 + a12*b22 + a13*b32; *m13 = a11*b13 + a12*b23 + a13*b33; + *m21 = a21*b11 + a22*b21 + a23*b31; *m22 = a21*b12 + a22*b22 + a23*b32; *m23 = a21*b13 + a22*b23 + a23*b33; + *m31 = a31*b11 + a32*b21 + a33*b31; *m32 = a31*b12 + a32*b22 + a33*b32; *m33 = a31*b13 + a32*b23 + a33*b33; +} + +// matrix multiplication M = Transpose[A] * B +inline void multAtB(float a11, float a12, float a13, + float a21, float a22, float a23, + float a31, float a32, float a33, + // + float b11, float b12, float b13, + float b21, float b22, float b23, + float b31, float b32, float b33, + // + float *m11, float *m12, float *m13, + float *m21, float *m22, float *m23, + float *m31, float *m32, float *m33) +{ + *m11 = a11*b11 + a21*b21 + a31*b31; *m12 = a11*b12 + a21*b22 + a31*b32; *m13 = a11*b13 + a21*b23 + a31*b33; + *m21 = a12*b11 + a22*b21 + a32*b31; *m22 = a12*b12 + a22*b22 + a32*b32; *m23 = a12*b13 + a22*b23 + a32*b33; + *m31 = a13*b11 + a23*b21 + a33*b31; *m32 = a13*b12 + a23*b22 + a33*b32; *m33 = a13*b13 + a23*b23 + a33*b33; +} + +inline void quatToMat3(const float * qV, + float *m11, float *m12, float *m13, + float *m21, float *m22, float *m23, + float *m31, float *m32, float *m33 +) +{ + float w = qV[3]; + float x = qV[0]; + float y = qV[1]; + float z = qV[2]; + + float qxx = x*x; + float qyy = y*y; + float qzz = z*z; + float qxz = x*z; + float qxy = x*y; + float qyz = y*z; + float qwx = w*x; + float qwy = w*y; + float qwz = w*z; + + *m11 = 1 - 2 * (qyy + qzz); *m12 = 2 * (qxy - qwz); *m13 = 2 * (qxz + qwy); + *m21 = 2 * (qxy + qwz); *m22 = 1 - 2 * (qxx + qzz); *m23 = 2 * (qyz - qwx); + *m31 = 2 * (qxz - qwy); *m32 = 2 * (qyz + qwx); *m33 = 1 - 2 * (qxx + qyy); +} + +inline void approximateGivensQuaternion(float a11, float a12, float a22, float *ch, float *sh) +{ + /* + * Given givens angle computed by approximateGivensAngles, + * compute the corresponding rotation quaternion. + */ + *ch = 2 * (a11 - a22); + *sh = a12; + bool b = _gamma* (*sh)*(*sh) < (*ch)*(*ch); + // fast rsqrt function suffices + // rsqrt2 (https://code.google.com/p/lppython/source/browse/algorithm/HDcode/newCode/rsqrt.c?r=26) + // is even faster but results in too much error + float w = rsqrt((*ch)*(*ch) + (*sh)*(*sh)); + *ch = b ? w*(*ch) : (float)_cstar; + *sh = b ? w*(*sh) : (float)_sstar; +} + +inline void jacobiConjugation(const int x, const int y, const int z, + float *s11, + float *s21, float *s22, + float *s31, float *s32, float *s33, + float * qV) +{ + float ch, sh; + approximateGivensQuaternion(*s11, *s21, *s22, &ch, &sh); + + float scale = ch*ch + sh*sh; + float a = (ch*ch - sh*sh) / scale; + float b = (2 * sh*ch) / scale; + + // make temp copy of S + float _s11 = *s11; + float _s21 = *s21; float _s22 = *s22; + float _s31 = *s31; float _s32 = *s32; float _s33 = *s33; + + // perform conjugation S = Q'*S*Q + // Q already implicitly solved from a, b + *s11 = a*(a*_s11 + b*_s21) + b*(a*_s21 + b*_s22); + *s21 = a*(-b*_s11 + a*_s21) + b*(-b*_s21 + a*_s22); *s22 = -b*(-b*_s11 + a*_s21) + a*(-b*_s21 + a*_s22); + *s31 = a*_s31 + b*_s32; *s32 = -b*_s31 + a*_s32; *s33 = _s33; + + // update cumulative rotation qV + float tmp[3]; + tmp[0] = qV[0] * sh; + tmp[1] = qV[1] * sh; + tmp[2] = qV[2] * sh; + sh *= qV[3]; + + qV[0] *= ch; + qV[1] *= ch; + qV[2] *= ch; + qV[3] *= ch; + + // (x,y,z) corresponds to ((0,1,2),(1,2,0),(2,0,1)) + // for (p,q) = ((0,1),(1,2),(0,2)) + qV[z] += sh; + qV[3] -= tmp[z]; // w + qV[x] += tmp[y]; + qV[y] -= tmp[x]; + + // re-arrange matrix for next iteration + _s11 = *s22; + _s21 = *s32; _s22 = *s33; + _s31 = *s21; _s32 = *s31; _s33 = *s11; + *s11 = _s11; + *s21 = _s21; *s22 = _s22; + *s31 = _s31; *s32 = _s32; *s33 = _s33; + +} + +inline float dist2(float x, float y, float z) +{ + return x*x + y*y + z*z; +} + +// finds transformation that diagonalizes a symmetric matrix +inline void jacobiEigenanlysis( // symmetric matrix + float *s11, + float *s21, float *s22, + float *s31, float *s32, float *s33, + // quaternion representation of V + float * qV) +{ + qV[3] = 1; qV[0] = 0; qV[1] = 0; qV[2] = 0; // follow same indexing convention as GLM + for (int i = 0; i<4; i++) + { + // we wish to eliminate the maximum off-diagonal element + // on every iteration, but cycling over all 3 possible rotations + // in fixed order (p,q) = (1,2) , (2,3), (1,3) still retains + // asymptotic convergence + jacobiConjugation(0, 1, 2, s11, s21, s22, s31, s32, s33, qV); // p,q = 0,1 + jacobiConjugation(1, 2, 0, s11, s21, s22, s31, s32, s33, qV); // p,q = 1,2 + jacobiConjugation(2, 0, 1, s11, s21, s22, s31, s32, s33, qV); // p,q = 0,2 + } +} + + +inline void sortSingularValues(// matrix that we want to decompose + float *b11, float *b12, float *b13, + float *b21, float *b22, float *b23, + float *b31, float *b32, float *b33, + // sort V simultaneously + float *v11, float *v12, float *v13, + float *v21, float *v22, float *v23, + float *v31, float *v32, float *v33) +{ + float rho1 = dist2(*b11, *b21, *b31); + float rho2 = dist2(*b12, *b22, *b32); + float rho3 = dist2(*b13, *b23, *b33); + bool c; + c = rho1 < rho2; + condNegSwap(c, b11, b12); condNegSwap(c, v11, v12); + condNegSwap(c, b21, b22); condNegSwap(c, v21, v22); + condNegSwap(c, b31, b32); condNegSwap(c, v31, v32); + condSwap(c, &rho1, &rho2); + c = rho1 < rho3; + condNegSwap(c, b11, b13); condNegSwap(c, v11, v13); + condNegSwap(c, b21, b23); condNegSwap(c, v21, v23); + condNegSwap(c, b31, b33); condNegSwap(c, v31, v33); + condSwap(c, &rho1, &rho3); + c = rho2 < rho3; + condNegSwap(c, b12, b13); condNegSwap(c, v12, v13); + condNegSwap(c, b22, b23); condNegSwap(c, v22, v23); + condNegSwap(c, b32, b33); condNegSwap(c, v32, v33); +} + + +void QRGivensQuaternion(float a1, float a2, float *ch, float *sh) +{ + // a1 = pivot point on diagonal + // a2 = lower triangular entry we want to annihilate + float epsilon = (float)EPSILON; + float rho = accurateSqrt(a1*a1 + a2*a2); + + *sh = rho > epsilon ? a2 : 0; + *ch = fabsf(a1) + fmaxf(rho, epsilon); + bool b = a1 < 0; + condSwap(b, sh, ch); + float w = rsqrt((*ch)*(*ch) + (*sh)*(*sh)); + *ch *= w; + *sh *= w; +} + + +inline void QRDecomposition(// matrix that we want to decompose + float b11, float b12, float b13, + float b21, float b22, float b23, + float b31, float b32, float b33, + // output Q + float *q11, float *q12, float *q13, + float *q21, float *q22, float *q23, + float *q31, float *q32, float *q33, + // output R + float *r11, float *r12, float *r13, + float *r21, float *r22, float *r23, + float *r31, float *r32, float *r33) +{ + float ch1, sh1, ch2, sh2, ch3, sh3; + float a, b; + + // first givens rotation (ch,0,0,sh) + QRGivensQuaternion(b11, b21, &ch1, &sh1); + a = 1 - 2 * sh1*sh1; + b = 2 * ch1*sh1; + // apply B = Q' * B + *r11 = a*b11 + b*b21; *r12 = a*b12 + b*b22; *r13 = a*b13 + b*b23; + *r21 = -b*b11 + a*b21; *r22 = -b*b12 + a*b22; *r23 = -b*b13 + a*b23; + *r31 = b31; *r32 = b32; *r33 = b33; + + // second givens rotation (ch,0,-sh,0) + QRGivensQuaternion(*r11, *r31, &ch2, &sh2); + a = 1 - 2 * sh2*sh2; + b = 2 * ch2*sh2; + // apply B = Q' * B; + b11 = a*(*r11) + b*(*r31); b12 = a*(*r12) + b*(*r32); b13 = a*(*r13) + b*(*r33); + b21 = *r21; b22 = *r22; b23 = *r23; + b31 = -b*(*r11) + a*(*r31); b32 = -b*(*r12) + a*(*r32); b33 = -b*(*r13) + a*(*r33); + + // third givens rotation (ch,sh,0,0) + QRGivensQuaternion(b22, b32, &ch3, &sh3); + a = 1 - 2 * sh3*sh3; + b = 2 * ch3*sh3; + // R is now set to desired value + *r11 = b11; *r12 = b12; *r13 = b13; + *r21 = a*b21 + b*b31; *r22 = a*b22 + b*b32; *r23 = a*b23 + b*b33; + *r31 = -b*b21 + a*b31; *r32 = -b*b22 + a*b32; *r33 = -b*b23 + a*b33; + + // construct the cumulative rotation Q=Q1 * Q2 * Q3 + // the number of floating point operations for three quaternion multiplications + // is more or less comparable to the explicit form of the joined matrix. + // certainly more memory-efficient! + float sh12 = sh1*sh1; + float sh22 = sh2*sh2; + float sh32 = sh3*sh3; + + *q11 = (-1 + 2 * sh12)*(-1 + 2 * sh22); + *q12 = 4 * ch2*ch3*(-1 + 2 * sh12)*sh2*sh3 + 2 * ch1*sh1*(-1 + 2 * sh32); + *q13 = 4 * ch1*ch3*sh1*sh3 - 2 * ch2*(-1 + 2 * sh12)*sh2*(-1 + 2 * sh32); + + *q21 = 2 * ch1*sh1*(1 - 2 * sh22); + *q22 = -8 * ch1*ch2*ch3*sh1*sh2*sh3 + (-1 + 2 * sh12)*(-1 + 2 * sh32); + *q23 = -2 * ch3*sh3 + 4 * sh1*(ch3*sh1*sh3 + ch1*ch2*sh2*(-1 + 2 * sh32)); + + *q31 = 2 * ch2*sh2; + *q32 = 2 * ch3*(1 - 2 * sh22)*sh3; + *q33 = (-1 + 2 * sh22)*(-1 + 2 * sh32); +} + +void svd(// input A + float a11, float a12, float a13, + float a21, float a22, float a23, + float a31, float a32, float a33, + // output U + float *u11, float *u12, float *u13, + float *u21, float *u22, float *u23, + float *u31, float *u32, float *u33, + // output S + float *s11, float *s12, float *s13, + float *s21, float *s22, float *s23, + float *s31, float *s32, float *s33, + // output V + float *v11, float *v12, float *v13, + float *v21, float *v22, float *v23, + float *v31, float *v32, float *v33) +{ + // normal equations matrix + float ATA11, ATA12, ATA13; + float ATA21, ATA22, ATA23; + float ATA31, ATA32, ATA33; + + multAtB(a11, a12, a13, a21, a22, a23, a31, a32, a33, + a11, a12, a13, a21, a22, a23, a31, a32, a33, + &ATA11, &ATA12, &ATA13, &ATA21, &ATA22, &ATA23, &ATA31, &ATA32, &ATA33); + + // symmetric eigenalysis + float qV[4]; + jacobiEigenanlysis(&ATA11, &ATA21, &ATA22, &ATA31, &ATA32, &ATA33, qV); + quatToMat3(qV, v11, v12, v13, v21, v22, v23, v31, v32, v33); + + float b11, b12, b13; + float b21, b22, b23; + float b31, b32, b33; + multAB(a11, a12, a13, a21, a22, a23, a31, a32, a33, + *v11, *v12, *v13, *v21, *v22, *v23, *v31, *v32, *v33, + &b11, &b12, &b13, &b21, &b22, &b23, &b31, &b32, &b33); + + // sort singular values and find V + sortSingularValues(&b11, &b12, &b13, &b21, &b22, &b23, &b31, &b32, &b33, + v11, v12, v13, v21, v22, v23, v31, v32, v33); + + // QR decomposition + QRDecomposition(b11, b12, b13, b21, b22, b23, b31, b32, b33, + u11, u12, u13, u21, u22, u23, u31, u32, u33, + s11, s12, s13, s21, s22, s23, s31, s32, s33 + ); +} + +/// polar decomposition can be reconstructed trivially from SVD result +// A = UP +void pd(float a11, float a12, float a13, + float a21, float a22, float a23, + float a31, float a32, float a33, + // output U + float *u11, float *u12, float *u13, + float *u21, float *u22, float *u23, + float *u31, float *u32, float *u33, + // output P + float *p11, float *p12, float *p13, + float *p21, float *p22, float *p23, + float *p31, float *p32, float *p33) +{ + float w11, w12, w13, w21, w22, w23, w31, w32, w33; + float s11, s12, s13, s21, s22, s23, s31, s32, s33; + float v11, v12, v13, v21, v22, v23, v31, v32, v33; + + svd(a11, a12, a13, a21, a22, a23, a31, a32, a33, + &w11, &w12, &w13, &w21, &w22, &w23, &w31, &w32, &w33, + &s11, &s12, &s13, &s21, &s22, &s23, &s31, &s32, &s33, + &v11, &v12, &v13, &v21, &v22, &v23, &v31, &v32, &v33); + + // P = VSV' + float t11, t12, t13, t21, t22, t23, t31, t32, t33; + multAB(v11, v12, v13, v21, v22, v23, v31, v32, v33, + s11, s12, s13, s21, s22, s23, s31, s32, s33, + &t11, &t12, &t13, &t21, &t22, &t23, &t31, &t32, &t33); + + multAB(t11, t12, t13, t21, t22, t23, t31, t32, t33, + v11, v21, v31, v12, v22, v32, v13, v23, v33, + p11, p12, p13, p21, p22, p23, p31, p32, p33); + + // U = WV' + multAB(w11, w12, w13, w21, w22, w23, w31, w32, w33, + v11, v21, v31, v12, v22, v32, v13, v23, v33, + u11, u12, u13, u21, u22, u23, u31, u32, u33); +} + +#endif
\ No newline at end of file |