# # # Nimrod's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # ## This module is a wrapper around `opengl`:idx:. If you define the symbol ## ``useGlew`` this wrapper does not use Nimrod's ``dynlib`` mechanism, ## but `glew`:idx: instead. However, this shouldn't be necessary anymore; even ## extension loading for the different operating systems is handled here. ## ## You need to call ``loadExtensions`` after a rendering context has been ## created to load any extension proc that your code uses. {.deadCodeElim: on.} import macros, sequtils {.push warning[User]: off.} when defined(linux) and not defined(android) and not defined(emscripten): import X, XLib, XUtil elif defined(windows): import winlean, os when defined(windows): const ogldll* = "OpenGL32.dll" gludll* = "GLU32.dll" elif defined(macosx): #macosx has this notion of a framework, thus the path to the openGL dylib files #is absolute const ogldll* = "/System/Library/Frameworks/OpenGL.framework/Versions/Current/Libraries/libGL.dylib" gludll* = "/System/Library/Frameworks/OpenGL.framework/Versions/Current/Libraries/libGLU.dylib" else: const ogldll* = "libGL.so.1" gludll* = "libGLU.so.1" when defined(useGlew): {.pragma: ogl, header: "".} {.pragma: oglx, header: "".} {.pragma: wgl, header: "".} {.pragma: glu, dynlib: gludll.} elif defined(ios): {.pragma: ogl.} {.pragma: oglx.} {.passC: "-framework OpenGLES", passL: "-framework OpenGLES".} elif defined(android) or defined(js) or defined(emscripten): {.pragma: ogl.} {.pragma: oglx.} else: # quite complex ... thanks to extension support for various platforms: import dynlib let oglHandle = loadLib(ogldll) if isNil(oglHandle): quit("could not load: " & ogldll) when defined(windows): var wglGetProcAddress = cast[proc (s: cstring): pointer {.stdcall.}]( symAddr(oglHandle, "wglGetProcAddress")) elif defined(linux): var glxGetProcAddress = cast[proc (s: cstring): pointer {.cdecl.}]( symAddr(oglHandle, "glxGetProcAddress")) var glxGetProcAddressArb = cast[proc (s: cstring): pointer {.cdecl.}]( symAddr(oglHandle, "glxGetProcAddressARB")) proc glGetProc(h: LibHandle; procName: cstring): pointer = when defined(windows): result = symAddr(h, procname) if result != nil: return if not isNil(wglGetProcAddress): result = wglGetProcAddress(procName) elif defined(linux): if not isNil(glxGetProcAddress): result = glxGetProcAddress(procName) if result != nil: return if not isNil(glxGetProcAddressArb): result = glxGetProcAddressArb(procName) if result != nil: return result = symAddr(h, procname) else: result = symAddr(h, procName) if result == nil: raiseInvalidLibrary(procName) var gluHandle: LibHandle proc gluGetProc(procname: cstring): pointer = if gluHandle == nil: gluHandle = loadLib(gludll) if gluHandle == nil: quit("could not load: " & gludll) result = glGetProc(gluHandle, procname) # undocumented 'dynlib' feature: the string literal is replaced by # the imported proc name: {.pragma: ogl, dynlib: glGetProc(oglHandle, "0").} {.pragma: oglx, dynlib: glGetProc(oglHandle, "0").} {.pragma: wgl, dynlib: glGetProc(oglHandle, "0").} {.pragma: glu, dynlib: gluGetProc("").} proc nimLoadProcs0() {.importc.} template loadExtensions*() = ## call this after your rendering context has been setup if you use ## extensions. bind nimLoadProcs0 nimLoadProcs0() {.pop.} # warning[User]: off type GLenum* = distinct uint32 GLboolean* = bool GLbitfield* = distinct uint32 GLvoid* = pointer GLbyte* = int8 GLshort* = int64 GLint* = int32 GLclampx* = int32 GLubyte* = uint8 GLushort* = uint16 GLuint* = uint32 GLhandle* = GLuint GLsizei* = int32 GLfloat* = float32 GLclampf* = float32 GLdouble* = float64 GLclampd* = float64 GLeglImageOES* = distinct pointer GLchar* = char GLcharArb* = char GLfixed* = int32 GLhalfNv* = uint16 GLvdpauSurfaceNv* = uint GLintptr* = int GLintptrArb* = int GLint64EXT* = int64 GLuint64EXT* = uint64 GLint64* = int64 GLsizeiptrArb* = int GLsizeiptr* = int GLsync* = distinct pointer GLuint64* = uint64 GLvectorub2* = array[0..1, GLubyte] GLvectori2* = array[0..1, GLint] GLvectorf2* = array[0..1, GLfloat] GLvectord2* = array[0..1, GLdouble] GLvectorp2* = array[0..1, pointer] GLvectorb3* = array[0..2, GLbyte] GLvectorub3* = array[0..2, GLubyte] GLvectori3* = array[0..2, GLint] GLvectorui3* = array[0..2, GLuint] GLvectorf3* = array[0..2, GLfloat] GLvectord3* = array[0..2, GLdouble] GLvectorp3* = array[0..2, pointer] GLvectors3* = array[0..2, GLshort] GLvectorus3* = array[0..2, GLushort] GLvectorb4* = array[0..3, GLbyte] GLvectorub4* = array[0..3, GLubyte] GLvectori4* = array[0..3, GLint] GLvectorui4* = array[0..3, GLuint] GLvectorf4* = array[0..3, GLfloat] GLvectord4* = array[0..3, GLdouble] GLvectorp4* = array[0..3, pointer] GLvectors4* = array[0..3, GLshort] GLvectorus4* = array[0..3, GLshort] GLarray4f* = GLvectorf4 GLarrayf3* = GLvectorf3 GLarrayd3* = GLvectord3 GLarrayi4* = GLvectori4 GLarrayp4* = GLvectorp4 GLmatrixub3* = array[0..2, array[0..2, GLubyte]] GLmatrixi3* = array[0..2, array[0..2, GLint]] GLmatrixf3* = array[0..2, array[0..2, GLfloat]] GLmatrixd3* = array[0..2, array[0..2, GLdouble]] GLmatrixub4* = array[0..3, array[0..3, GLubyte]] GLmatrixi4* = array[0..3, array[0..3, GLint]] GLmatrixf4* = array[0..3, array[0..3, GLfloat]] GLmatrixd4* = array[0..3, array[0..3, GLdouble]] ClContext* = distinct pointer ClEvent* = distinct pointer GLdebugProc* = proc ( source: GLenum, typ: GLenum, id: GLuint, severity: GLenum, length: GLsizei, message: ptr GLchar, userParam: pointer) {.stdcall.} GLdebugProcArb* = proc ( source: GLenum, typ: GLenum, id: GLuint, severity: GLenum, len: GLsizei, message: ptr GLchar, userParam: pointer) {.stdcall.} GLdebugProcAmd* = proc ( id: GLuint, category: GLenum, severity: GLenum, len: GLsizei, message: ptr GLchar, userParam: pointer) {.stdcall.} GLdebugProcKhr* = proc ( source, typ: GLenum, id: GLuint, severity: GLenum, length: GLsizei, message: ptr GLchar, userParam: pointer) {.stdcall.} type GLerrorCode* {.size: GLenum.sizeof.} = enum # XXX: can't be evaluated when # in the same type section as # GLenum. glErrNoError = (0, "no error") glErrInvalidEnum = (0x0500, "invalid enum") glErrInvalidValue = (0x0501, "invalid value") glErrInvalidOperation = (0x0502, "invalid operation") glErrStackOverflow = (0x0503, "stack overflow") glErrStackUnderflow = (0x0504, "stack underflow") glErrOutOfMem = (0x0505, "out of memory") glErrInvalidFramebufferOperation = (0x0506, "invalid framebuffer operation") glErrTableTooLarge = (0x8031, "table too large") const AllErrorCodes = { glErrNoError, glErrInvalidEnum, glErrInvalidValue, glErrInvalidOperation, glErrStackOverflow, glErrStackUnderflow, glErrOutOfMem, glErrInvalidFramebufferOperation, glErrTableTooLarge, } when defined(macosx): type GLhandleArb = pointer else: type GLhandleArb = uint32 {.deprecated: [ TGLerror: GLerrorCode, TGLhandleARB: GLhandleArb, TGLenum: GLenum, TGLboolean: GLboolean, TGLbitfield: GLbitfield, TGLvoid: GLvoid, TGLbyte: GLbyte, TGLshort: GLshort, TGLint: GLint, TGLclampx: GLclampx, TGLubyte: GLubyte, TGLushort: GLushort, TGLuint: GLuint, TGLsizei: GLsizei, TGLfloat: GLfloat, TGLclampf: GLclampf, TGLdouble: GLdouble, TGLclampd: GLclampd, TGLeglImageOES: GLeglImageOES, TGLchar: GLchar, TGLcharARB: GLcharArb, TGLfixed: GLfixed, TGLhalfNV: GLhalfNv, TGLvdpauSurfaceNv: GLvdpauSurfaceNv, TGLintptr: GLintptr, TGLintptrARB: GLintptrArb, TGLint64EXT: GLint64Ext, TGLuint64EXT: GLuint64Ext, TGLint64: GLint64, TGLsizeiptrARB: GLsizeiptrArb, TGLsizeiptr: GLsizeiptr, TGLsync: GLsync, TGLuint64: GLuint64, TCL_context: ClContext, TCL_event: ClEvent, TGLdebugProc: GLdebugProc, TGLDebugProcARB: GLdebugProcArb, TGLDebugProcAMD: GLdebugProcAmd, TGLDebugProcKHR: GLdebugProcKhr, TGLVectorub2: GLvectorub2, TGLVectori2: GLvectori2, TGLVectorf2: GLvectorf2, TGLVectord2: GLvectord2, TGLVectorp2: GLvectorp2, TGLVectorb3: GLvectorb3, TGLVectorub3: GLvectorub3, TGLVectori3: GLvectori3, TGLVectorui3: GLvectorui3, TGLVectorf3: GLvectorf3, TGLVectord3: GLvectord3, TGLVectorp3: GLvectorp3, TGLVectors3: GLvectors3, TGLVectorus3: GLvectorus3, TGLVectorb4: GLvectorb4, TGLVectorub4: GLvectorub4, TGLVectori4: GLvectori4, TGLVectorui4: GLvectorui4, TGLVectorf4: GLvectorf4, TGLVectord4: GLvectord4, TGLVectorp4: GLvectorp4, TGLVectors4: GLvectors4, TGLVectorus4: GLvectorus4, TGLArrayf4: GLarray4f, TGLArrayf3: GLarrayf3, TGLArrayd3: GLarrayd3, TGLArrayi4: GLarrayi4, TGLArrayp4: GLarrayp4, TGLMatrixub3: GLmatrixub3, TGLMatrixi3: GLmatrixi3, TGLMatrixf3: GLmatrixf3, TGLMatrixd3: GLmatrixd3, TGLMatrixub4: GLmatrixub4, TGLMatrixi4: GLmatrixi4, TGLMatrixf4: GLmatrixf4, TGLMatrixd4: GLmatrixd4, TGLVector3d: GLvectord3, TGLVector4i: GLvectori4, TGLVector4f: GLvectorf4, TGLVector4p: GLvectorp4, TGLMatrix4f: GLmatrixf4, TGLMatrix4d: GLmatrixd4, ].} proc `==`*(a, b: GLenum): bool {.borrow.} proc `==`*(a, b: GLbitfield): bool {.borrow.} proc `or`*(a, b: GLbitfield): GLbitfield {.borrow.} proc hash*(x: GLenum): int = result = x.int proc glGetError*: GLenum {.stdcall, importc, ogl.} proc getGLerrorCode*: GLerrorCode = glGetError().GLerrorCode ## Like ``glGetError`` but returns an enumerator instead. type GLerror* = object of Exception ## An exception for OpenGL errors. code*: GLerrorCode ## The error code. This might be invalid for two reasons: ## an outdated list of errors or a bad driver. proc checkGLerror* = ## Raise ``GLerror`` if the last call to an OpenGL function generated an error. ## You might want to call this once every frame for example if automatic ## error checking has been disabled. let error = getGLerrorCode() if error == glErrNoError: return var exc = new(GLerror) for e in AllErrorCodes: if e == error: exc.msg = "OpenGL error: " & $e raise exc exc.code = error exc.msg = "OpenGL error: unknown (" & $error & ")" raise exc {.push warning[User]: off.} const NoAutoGLerrorCheck* = defined(noAutoGLerrorCheck) ##\ ## This determines (at compile time) whether an exception should be raised ## if an OpenGL call generates an error. No additional code will be generated ## and ``enableAutoGLerrorCheck(bool)`` will have no effect when ## ``noAutoGLerrorCheck`` is defined. {.pop.} # warning[User]: off var gAutoGLerrorCheck = true gInsideBeginEnd* = false # do not change manually. proc enableAutoGLerrorCheck*(yes: bool) = ## This determines (at run time) whether an exception should be raised if an ## OpenGL call generates an error. This has no effect when ## ``noAutoGLerrorCheck`` is defined. gAutoGLerrorCheck = yes macro wrapErrorChecking(f: stmt): stmt {.immediate.} = f.expectKind nnkStmtList result = newStmtList() for child in f.children: if child.kind == nnkCommentStmt: continue child.expectKind nnkProcDef let params = toSeq(child.params.children) var glProc = copy child glProc.pragma = newNimNode(nnkPragma).add( newNimNode(nnkExprColonExpr).add( ident"importc" , newLit($child.name)) ).add(ident"ogl") let rawGLprocName = $glProc.name glProc.name = ident(rawGLprocName & "Impl") var body = newStmtList glProc returnsSomething = child.params[0].kind != nnkEmpty callParams = newSeq[when defined(nimnode): NimNode else: PNimrodNode]() for param in params[1 ..