├── bin_Windows_32 └── glslc.exe ├── bin_Windows_64 └── glslc.exe ├── LICENSE.md ├── README.md └── src └── glslc.cpp /bin_Windows_32/glslc.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixeljetstream/glslc/HEAD/bin_Windows_32/glslc.exe -------------------------------------------------------------------------------- /bin_Windows_64/glslc.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixeljetstream/glslc/HEAD/bin_Windows_64/glslc.exe -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | glslc 2 | ============================================================================= 3 | Copyright: 2013 Christoph Kubisch. 4 | http://pixeljetstream.luxinia.de 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining 7 | a copy of this software and associated documentation files (the 8 | "Software"), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to 11 | permit persons to whom the Software is furnished to do so, subject to 12 | the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | [ MIT license: http://www.opensource.org/licenses/mit-license.php ] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | glslc 2 | ===== 3 | 4 | Simple GLSL compilation checker (uses display driver) 5 | 6 | (c) 2013-2015 Christoph Kubisch: pixeljetstream@luxinia.de 7 | http://glslc.luxinia.de 8 | 9 | * Basic commandline compiler for GLSL 10 | * Creates an invisible dummy window and evokes the GL driver for compiling. 11 | * Can dump pseudo assembly files for NVIDIA 12 | * Basic #include handling independent of GL_ARB_shading_language_include support 13 | * Best used with GLSL editing capabilites of the https://github.com/pkulchenko/ZeroBraneStudio/ IDE 14 | * Install the [zbstudio-graphicscodepack](https://github.com/pixeljetstream/zbstudio-graphicscodepack) 15 | * Set the GLSLC_BIN_PATH environment variable to where your glslc.exe is located (excluding the exe name). Alternatively add "path.glslcbin = [[path to glslc.exe]] " to your "cfg/user.lua" file. Upon restart of zbstudio, you should now see the GLSL top menu. 16 | * *'Compile from .ext'* derives the shader profile type from the filename, for example a ".v" within the filename causes the file to be compiled as vertex shader. The tool tests in following order: ".v",".f",".g",".t * c",".t * e",".c". 17 | * *'Link multiple .ext'* will try to compile and link multiple shader files that only differ in their file extension. 18 | 19 | ![glslc inside zbstudio](http://www.luxinia.de/images/estrela_glslc.png) 20 | 21 | Examples 22 | -------- 23 | 24 | glslc -o output.txt -profile vertex myvertex.vs 25 | 26 | glslc -glslversion "430 core" -o output.txt -DFOO -vertex myvertex.vs -fragment myfrag.fs 27 | 28 | glslc -glslversion "430 core" -o output.txt -DFOO -SD_VERTEX_ -vertex myprogram.glsl -SD_FRAGMENT_ -fragment myprogram.glsl 29 | 30 | Usage 31 | ----- 32 | 33 | glslc [options] *filename* 34 | 35 | ### Mandatory options 36 | 37 | -*profilename* 38 | 39 | or 40 | 41 | -profile *profilename* 42 | 43 | > Profilename can be: vertex, fragment, geometry, tessevaluation, tesscontrol, compute 44 | > and must be specified prior each file name. 45 | 46 | ### Other options: 47 | 48 | -glslversion "*string*" 49 | 50 | > Prepends "#version *string*\n" prior macros and shader and puts // in front of #version find in shaderfile. 51 | 52 | -separable 53 | 54 | > Will mark the program separable (default is false) prior attaching and linking, if GL_ARB_separate_shader_objects is supported. 55 | 56 | -o *outputfilename* 57 | 58 | > NVIDIA drivers can output pseudo assembly file based on NV_program 59 | 60 | -P *preprocessfilename* 61 | 62 | > stores the pre-processed file for the next specified shader 63 | 64 | -E 65 | 66 | > Pre-processes files only, no GL context creation. Outputs to stdout unless -P was specified. 67 | 68 | -DMACRO[=VALUE] 69 | 70 | > Prepends '#define MACRO VALUE' to all shaders. If VALUE is not specified it defaults to 1. 71 | 72 | -SDMACRO[=VALUE] 73 | 74 | > Prepends '#define MACRO VALUE' to next shader. If VALUE is not specified it defaults to 1. All shader defines are cleared with each shader file. 75 | 76 | Building 77 | -------- 78 | 79 | Currently Windows and Linux are supported. For Visual Studio 2008 a solution exists in /buildvc9. The project is just the src/glsl.cpp compiled as console application. 80 | 81 | Thanks to Alan Chambers for Linux support. 82 | -------------------------------------------------------------------------------- /src/glslc.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | glslc 4 | ============================================================================= 5 | Copyright: 2013-2015 Christoph Kubisch. 6 | http://glslc.luxinia.de 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining 9 | a copy of this software and associated documentation files (the 10 | "Software"), to deal in the Software without restriction, including 11 | without limitation the rights to use, copy, modify, merge, publish, 12 | distribute, sublicense, and/or sell copies of the Software, and to 13 | permit persons to whom the Software is furnished to do so, subject to 14 | the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be 17 | included in all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | [ MIT license: http://www.opensource.org/licenses/mit-license.php ] 28 | 29 | */ 30 | 31 | #define GLSLC_VERSION 11 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) 42 | #define WIN32_LEAN_AND_MEAN 1 43 | #include 44 | #include 45 | #include 46 | #endif 47 | 48 | #ifndef APIENTRY 49 | #define APIENTRY 50 | #endif 51 | #ifndef APIENTRYP 52 | #define APIENTRYP APIENTRY * 53 | #endif 54 | #ifndef GLAPI 55 | #define GLAPI extern 56 | #endif 57 | 58 | typedef char GLchar; 59 | 60 | #include 61 | 62 | #ifdef __linux__ 63 | #define GLX_GLXEXT_PROTOTYPES 64 | #include 65 | #endif 66 | 67 | enum MGLERROR { 68 | MGL_NO_ERROR = GL_NO_ERROR, 69 | MGL_INVALID_ENUM = GL_INVALID_ENUM, 70 | MGL_INVALID_VALUE = GL_INVALID_VALUE, 71 | MGL_INVALID_OPERATION = GL_INVALID_OPERATION, 72 | MGL_STACK_OVERFLOW = GL_STACK_OVERFLOW, 73 | MGL_STACK_UNDERFLOW = GL_STACK_UNDERFLOW, 74 | MGL_OUT_OF_MEMORY = GL_OUT_OF_MEMORY, 75 | }; 76 | 77 | #define GL_PROGRAM_SEPARABLE 0x8258 78 | 79 | #define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257 80 | #define GL_PROGRAM_BINARY_LENGTH 0x8741 81 | #define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE 82 | #define GL_PROGRAM_BINARY_FORMATS 0x87FF 83 | 84 | #define GL_COMPILE_STATUS 0x8B81 85 | #define GL_LINK_STATUS 0x8B82 86 | #define GL_VALIDATE_STATUS 0x8B83 87 | #define GL_INFO_LOG_LENGTH 0x8B84 88 | 89 | #define GL_FRAGMENT_SHADER 0x8B30 90 | #define GL_VERTEX_SHADER 0x8B31 91 | #define GL_GEOMETRY_SHADER 0x8DD9 92 | #define GL_TESS_EVALUATION_SHADER 0x8E87 93 | #define GL_TESS_CONTROL_SHADER 0x8E88 94 | #define GL_COMPUTE_SHADER 0x91B9 95 | 96 | #define GL_SHADER_INCLUDE_ARB 0x8DAE 97 | #define GL_NAMED_STRING_LENGTH_ARB 0x8DE9 98 | #define GL_NAMED_STRING_TYPE_ARB 0x8DEA 99 | 100 | typedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary); 101 | typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value); 102 | 103 | typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void); 104 | typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type); 105 | 106 | typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program); 107 | typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader); 108 | #if defined(_WIN32) 109 | typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar* const *string, const GLint *length); 110 | #endif 111 | typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); 112 | 113 | typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params); 114 | typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); 115 | typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); 116 | typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); 117 | 118 | typedef void (APIENTRYP PFNGLCOMPILESHADERINCLUDEARBPROC) (GLuint shader, GLsizei count, const GLchar* const *path, const GLint *length); 119 | typedef void (APIENTRYP PFNGLDELETENAMEDSTRINGARBPROC) (GLint namelen, const GLchar* name); 120 | typedef void (APIENTRYP PFNGLGETNAMEDSTRINGARBPROC) (GLint namelen, const GLchar* name, GLsizei bufSize, GLint *stringlen, GLchar *string); 121 | typedef void (APIENTRYP PFNGLGETNAMEDSTRINGIVARBPROC) (GLint namelen, const GLchar* name, GLenum pname, GLint *params); 122 | typedef GLboolean (APIENTRYP PFNGLISNAMEDSTRINGARBPROC) (GLint namelen, const GLchar* name); 123 | typedef void (APIENTRYP PFNGLNAMEDSTRINGARBPROC) (GLenum type, GLint namelen, const GLchar* name, GLint stringlen, const GLchar *string); 124 | 125 | 126 | PFNGLGETPROGRAMBINARYPROC PFNGLGETPROGRAMBINARYPROCvar; 127 | PFNGLPROGRAMPARAMETERIPROC PFNGLPROGRAMPARAMETERIPROCvar; 128 | 129 | PFNGLCREATEPROGRAMPROC PFNGLCREATEPROGRAMPROCvar; 130 | PFNGLCREATESHADERPROC PFNGLCREATESHADERPROCvar; 131 | 132 | PFNGLLINKPROGRAMPROC PFNGLLINKPROGRAMPROCvar; 133 | PFNGLCOMPILESHADERPROC PFNGLCOMPILESHADERPROCvar; 134 | PFNGLSHADERSOURCEPROC PFNGLSHADERSOURCEPROCvar; 135 | PFNGLATTACHSHADERPROC PFNGLATTACHSHADERPROCvar; 136 | 137 | PFNGLGETPROGRAMIVPROC PFNGLGETPROGRAMIVPROCvar; 138 | PFNGLGETSHADERIVPROC PFNGLGETSHADERIVPROCvar; 139 | PFNGLGETPROGRAMINFOLOGPROC PFNGLGETPROGRAMINFOLOGPROCvar; 140 | PFNGLGETSHADERINFOLOGPROC PFNGLGETSHADERINFOLOGPROCvar; 141 | 142 | PFNGLCOMPILESHADERINCLUDEARBPROC PFNGLCOMPILESHADERINCLUDEARBPROCvar; 143 | PFNGLDELETENAMEDSTRINGARBPROC PFNGLDELETENAMEDSTRINGARBPROCvar; 144 | PFNGLGETNAMEDSTRINGARBPROC PFNGLGETNAMEDSTRINGARBPROCvar; 145 | PFNGLGETNAMEDSTRINGIVARBPROC PFNGLGETNAMEDSTRINGIVARBPROCvar; 146 | PFNGLISNAMEDSTRINGARBPROC PFNGLISNAMEDSTRINGARBPROCvar; 147 | PFNGLNAMEDSTRINGARBPROC PFNGLNAMEDSTRINGARBPROCvar; 148 | 149 | int SUPPORTS_SEPARATESHADERS = 0; 150 | int SUPPORTS_SHADERINCLUDE = 1; 151 | 152 | void glGetProgramBinary(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary){ 153 | PFNGLGETPROGRAMBINARYPROCvar(program,bufSize,length,binaryFormat,binary); 154 | } 155 | 156 | void glProgramParameteri(GLuint program, GLenum pname, GLint value){ 157 | PFNGLPROGRAMPARAMETERIPROCvar(program,pname,value); 158 | } 159 | 160 | GLuint glCreateProgram() 161 | { 162 | return PFNGLCREATEPROGRAMPROCvar(); 163 | } 164 | 165 | GLuint glCreateShader(GLenum type) 166 | { 167 | return PFNGLCREATESHADERPROCvar(type); 168 | } 169 | 170 | void glLinkProgram(GLuint program) 171 | { 172 | PFNGLLINKPROGRAMPROCvar(program); 173 | } 174 | 175 | void glCompileShader(GLuint shader) 176 | { 177 | PFNGLCOMPILESHADERPROCvar(shader); 178 | } 179 | 180 | void glShaderSource(GLuint shader, GLsizei count, const GLchar* const *string, const GLint *length) 181 | { 182 | PFNGLSHADERSOURCEPROCvar(shader,count,string,length); 183 | } 184 | 185 | void glAttachShader (GLuint program, GLuint shader) 186 | { 187 | PFNGLATTACHSHADERPROCvar(program,shader); 188 | } 189 | 190 | void glGetProgramiv(GLuint program, GLenum pname, GLint *params){ 191 | PFNGLGETPROGRAMIVPROCvar(program,pname,params); 192 | } 193 | 194 | void glGetShaderiv(GLuint shader, GLenum pname, GLint *params){ 195 | PFNGLGETSHADERIVPROCvar(shader,pname,params); 196 | } 197 | 198 | void glGetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) 199 | { 200 | PFNGLGETPROGRAMINFOLOGPROCvar(program,bufSize,length,infoLog); 201 | } 202 | 203 | void glGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) 204 | { 205 | PFNGLGETSHADERINFOLOGPROCvar(shader,bufSize,length,infoLog); 206 | } 207 | 208 | void glCompileShaderIncludeARB(GLuint shader,GLsizei count,const GLchar* const *path,const GLint *length){ 209 | PFNGLCOMPILESHADERINCLUDEARBPROCvar(shader,count,path,length); 210 | } 211 | 212 | void glDeleteNamedStringARB(GLint namelen,const GLchar* name){ 213 | PFNGLDELETENAMEDSTRINGARBPROCvar(namelen,name); 214 | } 215 | 216 | void glGetNamedStringARB(GLint namelen,const GLchar* name,GLsizei bufSize,GLint *stringlen,GLchar *string){ 217 | PFNGLGETNAMEDSTRINGARBPROCvar(namelen,name,bufSize,stringlen,string); 218 | } 219 | 220 | void glGetNamedStringivARB(GLint namelen,const GLchar* name,GLenum pname,GLint *params){ 221 | PFNGLGETNAMEDSTRINGIVARBPROCvar(namelen,name,pname,params); 222 | } 223 | 224 | GLboolean glIsNamedStringARB(GLint namelen,const GLchar* name){ 225 | return PFNGLISNAMEDSTRINGARBPROCvar(namelen,name); 226 | } 227 | 228 | void glNamedStringARB(GLenum type,GLint namelen,const GLchar* name,GLint stringlen,const GLchar *string){ 229 | PFNGLNAMEDSTRINGARBPROCvar(type,namelen,name,stringlen,string); 230 | } 231 | 232 | #ifdef _WIN32 233 | #define INIT_GL_FUNC( type, name ) type##var = (type) wglGetProcAddress(name); if (! type##var) notfound = true; 234 | #elif __linux__ 235 | #define INIT_GL_FUNC( type, name ) type##var = (type) glXGetProcAddressARB((const GLubyte *)name); if (! type##var) notfound = true; 236 | #endif 237 | 238 | bool initGL() 239 | { 240 | bool notfound = false; 241 | 242 | SUPPORTS_SEPARATESHADERS = strstr((const char*)glGetString(GL_EXTENSIONS),"GL_ARB_separate_shader_objects") != NULL; 243 | SUPPORTS_SHADERINCLUDE = strstr((const char*)glGetString(GL_EXTENSIONS),"GL_ARB_shading_language_include") != NULL; 244 | 245 | INIT_GL_FUNC(PFNGLGETPROGRAMBINARYPROC,"glGetProgramBinary"); 246 | INIT_GL_FUNC(PFNGLPROGRAMPARAMETERIPROC,"glProgramParameteri"); 247 | 248 | INIT_GL_FUNC(PFNGLCOMPILESHADERINCLUDEARBPROC,"glCompileShaderIncludeARB"); 249 | INIT_GL_FUNC(PFNGLDELETENAMEDSTRINGARBPROC,"glDeleteNamedStringARB"); 250 | INIT_GL_FUNC(PFNGLGETNAMEDSTRINGARBPROC,"glGetNamedStringARB"); 251 | INIT_GL_FUNC(PFNGLGETNAMEDSTRINGIVARBPROC,"glGetNamedStringivARB"); 252 | INIT_GL_FUNC(PFNGLISNAMEDSTRINGARBPROC,"glIsNamedStringARB"); 253 | INIT_GL_FUNC(PFNGLNAMEDSTRINGARBPROC,"glNamedStringARB"); 254 | 255 | // mandatory 256 | notfound = false; 257 | 258 | INIT_GL_FUNC(PFNGLCREATEPROGRAMPROC,"glCreateProgram"); 259 | INIT_GL_FUNC(PFNGLCREATESHADERPROC,"glCreateShader"); 260 | 261 | INIT_GL_FUNC(PFNGLLINKPROGRAMPROC,"glLinkProgram"); 262 | INIT_GL_FUNC(PFNGLSHADERSOURCEPROC,"glShaderSource"); 263 | INIT_GL_FUNC(PFNGLCOMPILESHADERPROC,"glCompileShader"); 264 | INIT_GL_FUNC(PFNGLATTACHSHADERPROC,"glAttachShader"); 265 | 266 | INIT_GL_FUNC(PFNGLGETPROGRAMIVPROC,"glGetProgramiv"); 267 | INIT_GL_FUNC(PFNGLGETSHADERIVPROC,"glGetShaderiv"); 268 | INIT_GL_FUNC(PFNGLGETPROGRAMINFOLOGPROC,"glGetProgramInfoLog"); 269 | INIT_GL_FUNC(PFNGLGETSHADERINFOLOGPROC,"glGetShaderInfoLog"); 270 | 271 | MGLERROR error = (MGLERROR)glGetError(); 272 | 273 | return error == MGL_NO_ERROR && !notfound; 274 | } 275 | 276 | #ifdef _WIN32 277 | 278 | LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 279 | { 280 | int x = LOWORD(lParam); 281 | int y = HIWORD(lParam); 282 | switch (msg) 283 | { 284 | case WM_KEYDOWN: 285 | { 286 | switch (wParam) 287 | { 288 | case VK_ESCAPE: 289 | PostQuitMessage(0); 290 | break; 291 | case VK_OEM_2: // Question Mark / Forward Slash for US Keyboards 292 | break; 293 | } 294 | break; 295 | } 296 | } 297 | 298 | return DefWindowProc(hWnd, msg, wParam, lParam); 299 | } 300 | 301 | 302 | bool createContext() 303 | { 304 | // based on "Pez" by Philip Rideout 305 | // http://prideout.net/blog/p36/pez.windows.c 306 | 307 | LPCSTR szName = "nvglcc"; 308 | WNDCLASSEXA wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, GetModuleHandle(0), 0, 0, 0, 0, szName, 0 }; 309 | DWORD dwStyle = WS_DISABLED; 310 | DWORD dwExStyle = WS_EX_APPWINDOW; 311 | RECT rect; 312 | int windowWidth, windowHeight, windowLeft, windowTop; 313 | HWND hWnd; 314 | PIXELFORMATDESCRIPTOR pfd; 315 | HDC hDC; 316 | HGLRC hRC; 317 | int pixelFormat; 318 | DWORD previousTime = GetTickCount(); 319 | MSG msg = {0}; 320 | 321 | wc.hCursor = LoadCursor(0, IDC_ARROW); 322 | RegisterClassExA(&wc); 323 | 324 | SetRect(&rect, 0, 0, 32, 32); 325 | AdjustWindowRectEx(&rect, dwStyle, FALSE, dwExStyle); 326 | windowWidth = rect.right - rect.left; 327 | windowHeight = rect.bottom - rect.top; 328 | windowLeft = GetSystemMetrics(SM_CXSCREEN) / 2 - windowWidth / 2; 329 | windowTop = GetSystemMetrics(SM_CYSCREEN) / 2 - windowHeight / 2; 330 | hWnd = CreateWindowExA(0, szName, szName, dwStyle, windowLeft, windowTop, windowWidth, windowHeight, 0, 0, 0, 0); 331 | 332 | // Create the GL context. 333 | ZeroMemory(&pfd, sizeof(pfd)); 334 | pfd.nSize = sizeof(pfd); 335 | pfd.nVersion = 1; 336 | pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; 337 | pfd.iPixelType = PFD_TYPE_RGBA; 338 | pfd.cColorBits = 24; 339 | pfd.cDepthBits = 24; 340 | pfd.cStencilBits = 8; 341 | pfd.iLayerType = PFD_MAIN_PLANE; 342 | 343 | hDC = GetDC(hWnd); 344 | pixelFormat = ChoosePixelFormat(hDC, &pfd); 345 | 346 | SetPixelFormat(hDC, pixelFormat, &pfd); 347 | hRC = wglCreateContext(hDC); 348 | wglMakeCurrent(hDC, hRC); 349 | 350 | return true; 351 | } 352 | 353 | #elif __linux__ 354 | 355 | static int const bufferAttributes[] = 356 | { 357 | GLX_DOUBLEBUFFER, False, 358 | GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, 359 | GLX_BIND_TO_TEXTURE_RGB_EXT, True, 360 | None 361 | }; 362 | 363 | static int const pixmapAttributes[] = 364 | { 365 | GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT, 366 | GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, 367 | None 368 | }; 369 | 370 | static int const contextAttributes[] = 371 | { 372 | GLX_RENDER_TYPE, GLX_RGBA_TYPE, 373 | #ifndef NDEBUG 374 | GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, 375 | #endif 376 | None 377 | }; 378 | 379 | bool createContext() 380 | { 381 | Display *const pDisplay = XOpenDisplay(NULL); 382 | if (NULL == pDisplay) 383 | { 384 | printf( "Unable to open a connection to the X server\n" ); 385 | return false; 386 | } 387 | 388 | // Request a frame-buffer config. 389 | int numFbConfigs; 390 | GLXFBConfig *const pFbConfigs = glXChooseFBConfig( 391 | pDisplay, 392 | DefaultScreen(pDisplay), 393 | bufferAttributes, 394 | &numFbConfigs); 395 | 396 | // Create a new GL context. 397 | GLXContext glContext = glXCreateContextAttribsARB( 398 | pDisplay, 399 | pFbConfigs[0], 400 | NULL, 401 | True, 402 | contextAttributes); 403 | 404 | // Create a pixmap. 405 | Pixmap xPixmap = XCreatePixmap(pDisplay, DefaultRootWindow(pDisplay), 128, 128, 24); 406 | GLXPixmap glPixmap = glXCreatePixmap(pDisplay, pFbConfigs[0], xPixmap, pixmapAttributes); 407 | 408 | // Make the context active. 409 | glXMakeCurrent(pDisplay, glPixmap, glContext); 410 | 411 | return true; 412 | } 413 | 414 | #endif 415 | 416 | std::string readFile( const char* filename) 417 | { 418 | std::string result; 419 | 420 | std::ifstream stream(filename, std::ios::in); 421 | if(!stream.is_open()){ 422 | fprintf(stderr,"error: could not open input file \"%s\"\n",filename); 423 | exit(1); 424 | return result; 425 | } 426 | 427 | stream.seekg(0, std::ios::end); 428 | result.reserve(stream.tellg()); 429 | stream.seekg(0, std::ios::beg); 430 | 431 | result.assign( 432 | (std::istreambuf_iterator(stream)), 433 | std::istreambuf_iterator()); 434 | 435 | return result; 436 | } 437 | 438 | void printHelp() 439 | { 440 | printf("glslc v%d\n",GLSLC_VERSION); 441 | printf("-----\n"); 442 | printf("(c) 2013-2014 Christoph Kubisch: pixeljetstream@luxinia.de\n"); 443 | printf("http://glslc.luxinia.de\n"); 444 | printf("\n"); 445 | printf("Basic offline compiler for GLSL\n"); 446 | printf("Creates a dummy window and evokes the GL driver for compiling.\n"); 447 | printf("Can dump pseudo assembly files for NVIDIA\n"); 448 | printf("Basic #include handling independent of GL_ARB_shading_language_include\n"); 449 | printf("\n"); 450 | printf("Usage:\n"); 451 | printf("\n"); 452 | printf("glslc [options] filename\n"); 453 | printf("Mandatory Options:\n"); 454 | printf(" -profilename\n"); 455 | printf(" -profile profilename\n"); 456 | printf(" profilename can be: vertex, fragment, geometry,\n"); 457 | printf(" tessevaluation, tesscontrol, compute\n"); 458 | printf(" and affects subsequent filenames.\n"); 459 | printf(" all files will be linked to a single program\n"); 460 | printf("Other:\n"); 461 | printf(" -E\n"); 462 | printf(" pre-processes all shaders only. Dumps to stdout unless -P option is used\n"); 463 | printf(" -P filename\n"); 464 | printf(" Stores pre-processed file for next defined shader\n"); 465 | printf(" -separable\n"); 466 | printf(" enables separate shader objects usage (default false)\n"); 467 | printf(" -o outputfilename\n"); 468 | printf(" NVIDIA drivers can output pseudo assembly based on NV_program\n"); 469 | printf(" -DMACRO[=VALUE]\n"); 470 | printf(" prepends '#define MACRO VALUE' to all shaders\n"); 471 | printf(" If VALUE is not specified it defaults to 1.\n"); 472 | printf(" -SDMACRO[=VALUE]\n"); 473 | printf(" prepends '#define MACRO VALUE' only to next shader\n"); 474 | printf(" If VALUE is not specified it defaults to 1.\n"); 475 | printf(" -glslversion \"version string\"\n"); 476 | printf(" prepends version string prior defines, puts // in front of #version directives in shader file\n"); 477 | printf("\n"); 478 | } 479 | 480 | 481 | // manual include derived of Christoph Riccio's g_truc OpenGL SamplePack 482 | // http://ogl-samples.g-truc.net/ 483 | 484 | std::string parseInclude(std::string const & Line, std::size_t const & Offset) 485 | { 486 | std::string Result; 487 | 488 | std::string::size_type IncludeFirstQuote = Line.find("\"", Offset); 489 | std::string::size_type IncludeSecondQuote = Line.find("\"", IncludeFirstQuote + 1); 490 | 491 | return Line.substr(IncludeFirstQuote + 1, IncludeSecondQuote - IncludeFirstQuote - 1); 492 | } 493 | 494 | std::vector includeMarkers; 495 | 496 | std::string eol("\n"); 497 | 498 | #define SSTR( x ) dynamic_cast< std::ostringstream & >( \ 499 | ( std::ostringstream() << std::dec << (x) ) ).str() 500 | 501 | inline std::string includeMarker(const std::string & filename) 502 | { 503 | std::string fixedname; 504 | #ifdef _WIN32 505 | for (size_t i = 0; i < filename.size(); i++){ 506 | char c = filename[i]; 507 | if ( c == '\\'){ 508 | fixedname.append("/"); 509 | } 510 | else{ 511 | fixedname.append(1,c); 512 | } 513 | } 514 | #else 515 | fixedname = filename; 516 | #endif 517 | if (!SUPPORTS_SHADERINCLUDE){ 518 | // #line lineNumber markerNumber 519 | 520 | includeMarkers.push_back(fixedname); 521 | int slot = int( includeMarkers.size() ); 522 | std::string slotstr = SSTR(slot); 523 | return slotstr; 524 | } 525 | else{ 526 | return std::string(" \"") + fixedname + std::string("\" "); 527 | } 528 | } 529 | 530 | std::string manualInclude ( std::string const & filename, 531 | std::string const & prepend, 532 | std::string const & forcedVersion) 533 | { 534 | std::string source = readFile(filename.c_str()); 535 | if (source.empty()) 536 | return source; 537 | 538 | std::stringstream stream; 539 | stream << source; 540 | std::string Line, Text; 541 | 542 | // Handle command line defines 543 | Text += prepend; 544 | Text += std::string("#line 1 ") + includeMarker(filename) + eol; 545 | int lineCount = 0; 546 | while(std::getline(stream, Line)) 547 | { 548 | std::size_t Offset = 0; 549 | lineCount++; 550 | 551 | // Version 552 | Offset = Line.find("#version"); 553 | if(Offset != std::string::npos) 554 | { 555 | std::size_t CommentOffset = Line.find("//"); 556 | if(CommentOffset != std::string::npos && CommentOffset < Offset) 557 | continue; 558 | 559 | // Reorder so that the #version line is always the first of a shader text 560 | Text = (forcedVersion.empty() ? Line : forcedVersion) + eol + Text + std::string("//") + Line + eol; 561 | continue; 562 | } 563 | 564 | // Include 565 | Offset = Line.find("#include"); 566 | if(Offset != std::string::npos) 567 | { 568 | std::size_t CommentOffset = Line.find("//"); 569 | if(CommentOffset != std::string::npos && CommentOffset < Offset) 570 | continue; 571 | 572 | std::string includeFile = parseInclude(Line, Offset); 573 | std::string includeSource = manualInclude(includeFile,std::string(),std::string()); 574 | if(!includeSource.empty()) 575 | { 576 | // strip null terminator from content 577 | Text += includeSource; 578 | Text += eol + std::string("#line ") + SSTR(lineCount + 1) + std::string(" ") + includeMarker(filename) + eol; 579 | } 580 | 581 | continue; 582 | } 583 | 584 | Text += Line + eol; 585 | } 586 | 587 | return Text; 588 | } 589 | 590 | void printCorrectedLog(const std::string &log, const char *filename) 591 | { 592 | std::string output = log; 593 | #ifndef __linux__ 594 | if (!SUPPORTS_SHADERINCLUDE){ 595 | // (0) : 596 | std::tr1::regex patternFile("^\\(0\\)"); 597 | output = std::tr1::regex_replace( output, patternFile, std::string(filename) ); 598 | 599 | // 0(572) : 600 | std::tr1::regex patternLine("^0(\\(\\d+\\) : )"); 601 | output = std::tr1::regex_replace( output, patternLine, std::string(filename) + std::string("$1") ); 602 | 603 | for (size_t i = 0; i < includeMarkers.size(); i++){ 604 | std::string curfile = includeMarkers[i]; 605 | int slot = int(i+1); 606 | 607 | // (0) : 608 | std::tr1::regex patternFile(std::string("^\\(") + SSTR(slot) + std::string("\\)")); 609 | output = std::tr1::regex_replace( output, patternFile, std::string(curfile) ); 610 | 611 | // 0(572) : 612 | std::tr1::regex patternLine(std::string("^") + SSTR(slot) + std::string("(\\(\\d+\\) : )")); 613 | output = std::tr1::regex_replace( output, patternLine, std::string(curfile) + std::string("$1") ); 614 | } 615 | } 616 | #endif 617 | printf("%s", output.c_str()); 618 | } 619 | 620 | 621 | const char* shaderTypeName(GLenum type) 622 | { 623 | switch(type){ 624 | case GL_VERTEX_SHADER: return "Vertex"; 625 | case GL_FRAGMENT_SHADER: return "Fragment"; 626 | case GL_GEOMETRY_SHADER: return "Geometry"; 627 | case GL_TESS_EVALUATION_SHADER: return "Tessellation evaluation"; 628 | case GL_TESS_CONTROL_SHADER: return "Tessellation control"; 629 | case GL_COMPUTE_SHADER: return "Compute"; 630 | } 631 | return ""; 632 | } 633 | 634 | static const size_t NPOS = std::string::npos; 635 | 636 | size_t findShaderInLog(const std::string& log, size_t offset, GLenum& type) 637 | { 638 | GLenum types[] = { 639 | GL_VERTEX_SHADER, 640 | GL_FRAGMENT_SHADER, 641 | GL_GEOMETRY_SHADER, 642 | GL_TESS_EVALUATION_SHADER, 643 | GL_TESS_CONTROL_SHADER, 644 | GL_COMPUTE_SHADER 645 | }; 646 | 647 | size_t pos = NPOS; 648 | for (size_t i = 0; i < sizeof(types)/sizeof(types[0]); i++){ 649 | std::string search = std::string(shaderTypeName(types[i])) + std::string(" info"); 650 | size_t searchpos = log.find(search.c_str(), offset); 651 | if (searchpos < pos ){ 652 | type = types[i]; 653 | pos = searchpos; 654 | } 655 | } 656 | 657 | return pos; 658 | } 659 | 660 | struct ShaderInfo { 661 | GLenum type; 662 | std::string infile; 663 | std::string preprocessfile; 664 | std::vector defines; 665 | }; 666 | 667 | int main(int argc, char **argv) 668 | { 669 | bool useSeparate = false; 670 | bool useOutfile = false; 671 | bool usePreprocessonly = false; 672 | 673 | const char* preprocessfilename = NULL; 674 | const char* outfilename = NULL; 675 | const char* versionstring = NULL; 676 | std::string version; 677 | std::string alldefines; 678 | std::vector shaders; 679 | std::vector defines; 680 | std::vector shaderdefines; 681 | 682 | { 683 | GLenum shadertype = 0; 684 | const char* filename = NULL; 685 | 686 | for (int i = 1; i < argc; i++){ 687 | if ( strcmp(argv[i],"-profile")==0 && i + 1 < argc) { 688 | if (strcmp(argv[i+1],"vertex")==0){ 689 | shadertype = GL_VERTEX_SHADER; 690 | } 691 | else if (strcmp(argv[i+1],"fragment")==0){ 692 | shadertype = GL_FRAGMENT_SHADER; 693 | } 694 | else if (strcmp(argv[i+1],"geometry")==0){ 695 | shadertype = GL_GEOMETRY_SHADER; 696 | } 697 | else if (strcmp(argv[i+1],"tessevaluation")==0){ 698 | shadertype = GL_TESS_EVALUATION_SHADER; 699 | } 700 | else if (strcmp(argv[i+1],"tesscontrol")==0){ 701 | shadertype = GL_TESS_CONTROL_SHADER; 702 | } 703 | else if (strcmp(argv[i+1],"compute")==0){ 704 | shadertype = GL_COMPUTE_SHADER; 705 | } 706 | else { 707 | fprintf(stderr,"error: illegal profile\n"); 708 | exit(1); 709 | } 710 | i++; 711 | } 712 | else if (strcmp(argv[i],"-separable") == 0){ 713 | useSeparate = true; 714 | } 715 | else if (strcmp(argv[i],"-vertex")==0){ 716 | shadertype = GL_VERTEX_SHADER; 717 | } 718 | else if (strcmp(argv[i],"-fragment")==0){ 719 | shadertype = GL_FRAGMENT_SHADER; 720 | } 721 | else if (strcmp(argv[i],"-geometry")==0){ 722 | shadertype = GL_GEOMETRY_SHADER; 723 | } 724 | else if (strcmp(argv[i],"-tessevaluation")==0){ 725 | shadertype = GL_TESS_EVALUATION_SHADER; 726 | } 727 | else if (strcmp(argv[i],"-tesscontrol")==0){ 728 | shadertype = GL_TESS_CONTROL_SHADER; 729 | } 730 | else if (strcmp(argv[i],"-compute")==0){ 731 | shadertype = GL_COMPUTE_SHADER; 732 | } 733 | else if (strstr(argv[i],"-D") == argv[i]){ 734 | std::string def(argv[i]+2); 735 | if (def.find('=') != NPOS){ 736 | def[def.find('=')] = ' '; 737 | } 738 | else { 739 | def += std::string(" 1"); 740 | } 741 | 742 | defines.push_back(std::string("#define ") + def + eol); 743 | } 744 | else if (strstr(argv[i],"-SD") == argv[i]){ 745 | std::string def(argv[i]+3); 746 | if (def.find('=') != NPOS){ 747 | def[def.find('=')] = ' '; 748 | } 749 | else { 750 | def += std::string(" 1"); 751 | } 752 | 753 | shaderdefines.push_back(std::string("#define ") + def + eol); 754 | } 755 | else if (strcmp(argv[i],"-glslversion")==0 && i + 1 < argc){ 756 | versionstring = argv[i+1]; 757 | i++; 758 | } 759 | else if (strcmp(argv[i],"-o")==0 && i + 1 < argc){ 760 | outfilename = argv[i+1]; 761 | i++; 762 | } 763 | else if (strcmp(argv[i],"-E")==0){ 764 | usePreprocessonly = true; 765 | } 766 | else if (strcmp(argv[i],"-P")==0 && i + 1 < argc){ 767 | preprocessfilename = argv[i+1]; 768 | i++; 769 | } 770 | else { 771 | if (!shadertype){ 772 | fprintf(stderr,"error: profile not provided\n"); 773 | exit(1); 774 | } 775 | 776 | filename = argv[i]; 777 | ShaderInfo info; 778 | info.infile = std::string(filename); 779 | info.preprocessfile = preprocessfilename ? std::string(preprocessfilename) : std::string(); 780 | info.type = shadertype; 781 | info.defines = shaderdefines; 782 | shaders.push_back(info); 783 | shaderdefines.clear(); 784 | } 785 | } 786 | } 787 | 788 | 789 | if (argc == 1){ 790 | printHelp(); 791 | return 0; 792 | } 793 | 794 | if (!shaders.size()){ 795 | fprintf(stderr,"error: no filename(s) provided\n"); 796 | return 1; 797 | } 798 | 799 | if (!usePreprocessonly && !createContext()){ 800 | fprintf(stderr,"could not create GL context\n"); 801 | return 1; 802 | } 803 | 804 | if (!usePreprocessonly && !initGL()) { 805 | fprintf(stderr,"could not initialize GL functions\n"); 806 | return 1; 807 | } 808 | 809 | 810 | printf("glslc v%d\n",GLSLC_VERSION); 811 | 812 | GLuint program; 813 | if (!usePreprocessonly){ 814 | printf("GL Vendor: %s\n", (const char*)glGetString(GL_VENDOR)); 815 | printf("GL Renderer: %s\n", (const char*)glGetString(GL_RENDERER)); 816 | printf("GL Version: %s\n", (const char*)glGetString(GL_VERSION)); 817 | 818 | if (useSeparate && !SUPPORTS_SEPARATESHADERS) { 819 | printf("separable option not supported, disabled\n"); 820 | useSeparate = true; 821 | } 822 | 823 | useOutfile = PFNGLGETPROGRAMBINARYPROCvar && outfilename && strstr((const char*)glGetString(GL_VENDOR), "NVIDIA"); 824 | 825 | program = glCreateProgram(); 826 | if (useSeparate) { 827 | glProgramParameteri(program,GL_PROGRAM_SEPARABLE,GL_TRUE); 828 | } 829 | if (useOutfile){ 830 | glProgramParameteri(program,GL_PROGRAM_BINARY_RETRIEVABLE_HINT,GL_TRUE); 831 | } 832 | } 833 | 834 | if (versionstring){ 835 | version = std::string("#version ") + std::string(versionstring); 836 | } 837 | 838 | printf("\n"); 839 | if (defines.size()){ 840 | printf("Global defines\n"); 841 | for (size_t i = 0; i < defines.size(); i++){ 842 | printf("%s",defines[i].c_str()); 843 | alldefines += defines[i]; 844 | } 845 | printf("\n"); 846 | } 847 | 848 | 849 | for (size_t i = 0; i < shaders.size(); i++){ 850 | const ShaderInfo& info = shaders[i]; 851 | const char* filename = info.infile.c_str(); 852 | 853 | std::string currentdefines; 854 | if (info.defines.size()){ 855 | printf("Shader defines\n"); 856 | for (size_t i = 0; i < info.defines.size(); i++){ 857 | printf("%s",info.defines[i].c_str()); 858 | currentdefines += info.defines[i]; 859 | } 860 | } 861 | 862 | std::string shadertext = manualInclude(filename,alldefines + currentdefines,version); 863 | 864 | if (!info.preprocessfile.empty()){ 865 | FILE* outfile = fopen(info.preprocessfile.c_str(),"wt"); 866 | if (!outfile){ 867 | fprintf(stderr,"error: could not create preprocess file, \"%s\"\n",info.preprocessfile.c_str()); 868 | return 1; 869 | } 870 | else{ 871 | printf("pre-processed written to \"%s\"\n",info.preprocessfile.c_str()); 872 | } 873 | fwrite(&shadertext[0],shadertext.size(),1,outfile); 874 | } 875 | 876 | if (usePreprocessonly){ 877 | if (info.preprocessfile.empty()){ 878 | printf("pre-processed \"%s\"\n",filename); 879 | printf("%s\n\n",shadertext.c_str()); 880 | } 881 | continue; 882 | } 883 | 884 | GLuint shader = glCreateShader(info.type); 885 | printf("compiling %s:\"%s\"...\n",shaderTypeName(info.type),filename); 886 | 887 | const char* strings[1]; 888 | GLint lengths[1]; 889 | 890 | strings[0] = shadertext.c_str(); 891 | lengths[0] = (GLint)strlen(strings[0]); 892 | 893 | glShaderSource(shader,1,strings,lengths); 894 | glCompileShader(shader); 895 | 896 | GLint status = 0; 897 | GLint logLength = 0; 898 | glGetShaderiv(shader, GL_COMPILE_STATUS, &status); 899 | glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength); 900 | if (logLength > 1){ 901 | std::string log; 902 | log.resize(logLength,0); 903 | glGetShaderInfoLog(shader, logLength,NULL,&log[0]); 904 | printCorrectedLog(log,filename); 905 | printf("\n"); 906 | } 907 | 908 | if (!status){ 909 | fprintf(stderr,"error: shader could not be compiled\n"); 910 | return 1; 911 | } 912 | 913 | printf("success\n\n"); 914 | glAttachShader(program,shader); 915 | } 916 | 917 | if (usePreprocessonly){ 918 | return 0; 919 | } 920 | 921 | glLinkProgram(program); 922 | 923 | { 924 | GLint status = 0; 925 | GLint logLength = 0; 926 | 927 | glGetProgramiv(program, GL_LINK_STATUS, &status); 928 | glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength); 929 | if (logLength > 1){ 930 | std::string log; 931 | log.resize(logLength,0); 932 | glGetProgramInfoLog(program, logLength,NULL,&log[0]); 933 | 934 | GLenum type; 935 | size_t infobegin = findShaderInLog(log,0,type); 936 | size_t infoend = NPOS; 937 | if (infobegin != NPOS){ 938 | printf("%s",log.substr(0,infobegin).c_str()); 939 | while (infobegin != NPOS){ 940 | GLenum typenext; 941 | infoend = findShaderInLog(log,infobegin+1,typenext); 942 | std::string sublog = log.substr(infobegin,infoend); 943 | const char* filename = ""; 944 | for (size_t i = 0; i < shaders.size(); i++){ 945 | if (shaders[i].type == type){ 946 | filename = shaders[i].infile.c_str(); 947 | } 948 | } 949 | 950 | printCorrectedLog(sublog,filename); 951 | infobegin = infoend; 952 | type = typenext; 953 | } 954 | 955 | } 956 | else{ 957 | printf("%s",log.c_str()); 958 | } 959 | 960 | printf("\n"); 961 | } 962 | 963 | if (!status){ 964 | fprintf(stderr,"error: program could not be linked\n"); 965 | return 1; 966 | } 967 | 968 | printf("successfully linked\n"); 969 | } 970 | 971 | if (useOutfile){ 972 | GLsizei binaryLength = 0; 973 | GLenum format = 0; 974 | glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH,&binaryLength); 975 | 976 | if (!binaryLength){ 977 | fprintf(stderr,"error: could not retrieve program binary\n"); 978 | return 1; 979 | } 980 | 981 | std::string binary(size_t(binaryLength+1),0); 982 | glGetProgramBinary(program,binaryLength,NULL,&format,&binary[0]); 983 | 984 | size_t startpos = binary.find("!!NV",0); 985 | size_t endpos = binary.rfind("END"); 986 | 987 | if (startpos == NPOS || endpos == NPOS){ 988 | fprintf(stderr,"error: cannot find NV_gpu_program strings\n"); 989 | return 1; 990 | } 991 | 992 | FILE* outfile = fopen(outfilename,"wb"); 993 | if (!outfile){ 994 | fprintf(stderr,"error: could not create output file, \"%s\"\n",outfilename); 995 | return 1; 996 | } 997 | 998 | while (startpos != NPOS && endpos != NPOS){ 999 | size_t temppos = binary.find("!!NV", startpos+1); 1000 | if (temppos != NPOS){ 1001 | endpos = binary.rfind("END", temppos); 1002 | } 1003 | 1004 | std::string shaderoutput = binary.substr(startpos,endpos + 3 - startpos); 1005 | fprintf(outfile,"%s",shaderoutput.c_str()); 1006 | fprintf(outfile,"\n\n"); 1007 | 1008 | startpos = binary.find("!!NV", endpos + 3); 1009 | endpos = binary.rfind("END"); 1010 | } 1011 | printf("NV_gpu_program written to:\n%s\n",outfilename); 1012 | fclose(outfile); 1013 | } 1014 | 1015 | return 0; 1016 | } 1017 | --------------------------------------------------------------------------------