User:Raul Miller/OpenGL/Page3

From J Wiki
Jump to: navigation, search

[[../../../Raul Miller/OpenGL/Page2|Prev]] Next

This is a hopefully temporary page. At least, in its current form. (However, I might wind up leaving this up in some stale form, long after I should have updated it.)

I'm trying to figure out how to use opengl shaders, and I've gotten stuck.

Shaders let you use your own algorithms to determine where vertices appear on the screen, and what color to use for pixels. http://www.3dshaders.com/ seems like a plausible overview site for this issue. Or, maybe http://www.lighthouse3d.com/opengl/glsl/index.php

Shaders are a relatively recent part of OpenGL, and some systems will not support them. Some systems will support them, but as an extension. How do you figure out what you've got?

You can check what version you are running. If you're running OpenGL Version 2, then shaders are supported.

To find out what version you're running, you can use

   require 'jzopengl'
   coinsert 'jgl3'
   glGetString GL_VERSION

Except, that only works if you also have a valid opengl context (in which case you don't really need the require). If it doesn't work right, you'll see something like:

+-+----+
|0|7938|
+-+----+

The first box is the result. J follows the result with the parameters, because sometimes they are effectively a part of the result. In this case, the zero means I didn't get a result.

If I did have a result, it would be the address of a memory location of a null terminated string which would tell me what version I've got for opengl. See http://www.jsoftware.com/help/user/memory_management.htm for more details on using addresses like that.

Anyways, here's a verb to tell you what OpenGL version you are using (assuming it's installed at all). It opens a small window, creates and OpenGL rendering context in that window, gets the requested value, closes the window, destroys the rendering context, then returns that version. Its argument is either a special OpenGL constant, or the name of one of those constants.

glString=:3 :0
 require 'dll jzopengl'
 wd'pc p;xywh 0 0 1 1;cc c isigraph opengl;pas 0 0;pshow;'
 ogl=: ''conew'jzopengl'
 rc__ogl''
 if.2=3!:0 y do.y=.do__ogl y end.
 v=.memr(0{::glGetString__ogl y),0,_1
 wd'pclose'
 destroy__ogl''
 v
)

For example:

   glString 'GL_VERSION'
2.0.0
   (#~ 'shader' +./@E."1 ])>;:glString 'GL_EXTENSIONS'
GL_ARB_fragment_shader
GL_ARB_shader_objects
GL_ARB_vertex_shader
GL_EXT_Cg_shader
GL_NV_texture_shader
GL_NV_texture_shader2
GL_NV_texture_shader3

Or:

   glString 'GL_VERSION'
1.4.0 - Build 4.14.10.4497

In "real life", I'd probably not be creating/discarding a window, because I'd already have one, but I think it's important to keep an eye on just what I'm getting into.

Anyways, here, I've got a version of opengl which should support shaders. Next question is, how?

The first routine you need to use, with a shader is glCreateShader. Or, glCreateShaderObjectARB (for some earlier versions of OpenGL). Unfortunately, this isn't a part of j6.01.

Also, glCreateShader is implemented as an opengl "extension", even when you've got an opengl 2.0 system.

http://glew.sourceforge.net/ has some documentation on extensions. Poking around in it, it looks like the routine to get access to one of these extensions is (system dependent):

windows: wglGetProcAddress
apple:   NSGLGetProcAddress
sgi/sun: dlGetProcAddress
linux:   glXGetProcAddressARB

And, near as I can tell, the system specific routine is a part of the opengl library under each of these systems. In each case, you pass this routine a name, and it gives you back the address of the routine you want to call... But for whatever reason, the actual name of this routine does not seem to be standardized. (You pass standardized names to it, but ... oh well...)

Which brings me back to: how do I call one of those "extension" routines?

J's 15!: mechanism doesn't seem to give me a direct way of approaching this problem. I could, hypothetically, build some native C code and link to it, but... I'd rather avoid that if possible.

So, anyways, I'm still poking around to see if I can figure out how to approach this issue.

One possibility: these routines are probably in some shared library somewhere. Perhaps a vendor specific library -- so referencing it directly is not portable -- but at least I'm not forced to build any glue just to get at them.

Another possibility: Assuming these routines are contained in shared libraries, and assuming that the shared library mechanism lets us associate the shared library file name with the routine entry point (for example, if the OS provides mapped file names, and mapped files are used to implement shared libraries and the entry points remain within the mapped region), we could use the entry point provided by opengl to find the library name needed by J 6.01's 15!: mechanism.

Discussion

  • See Addons/general/pcall as a practicall tool for making Pointer Calls, and a proposal to extend the 15!:0 cd call. This is just another use case to warrant pointer and interface call functionality to be essential. The addon is currently for Windows, so it try it there. If necessary could be extended for other platforms. The interface is straightforward. -- Oleg Kobchenko <<DateTime(2007-01-19T07:21:06Z)>>

Update

J has incorporated that pcall mechanism in its 15!:0. And a small experiment seems to show that things are working properly. Now I just need to come up with a good "hello world" type example program and test it out.

For now, here's where I am at (note that this code requires that I have a valid opengl rendering context active -- for now, I am using J's built in opengl demo code for that purpose).

coinsert 'jgl3'

NB.
ListProgramExtensions=: 3 :0
  ptr=. 0{::glGetString GL_EXTENSIONS
  ptr assert~'Need a valid opengl context'
   >(#~ ('program' +./@E. tolower)&>) ;:memr ptr,0 _1
)

SetFragmentProgram=: 3 :0
  FRAGMENT_PROGRAM_ARB=. 16b8804
  PROGRAM_FORMAT_ASCII_ARB=. 16b8875
  glProgramStringARB 16b8804; 16b8875; (#y); y
)

glGetProcAddress=: 0 {:: ((('darwin linux win'i.&;:tolower UNAME){::;:'NSGLGetProcAddress glXGetProcAddressARB wglGetProcAddress'),' * *c')openglCall
arbCall=: 1 :0
   'nm sig'=.({.&.;: ; }.&.;:) m
   addr=. glGetProcAddress<nm
   addr assert~nm,' not defined'
   (nm)=: ((":0,addr),' ',sig) &(15!:0)
)

'glProgramStringARB v i i i *c' arbCall

Example session, with the above code loaded (which can only succeed when I have a valid opengl rendering context):

   ListProgramExtensions''
GL_ARB_fragment_program
   glProgramStringARB
'0 37809744 v i i i * c'&(15!:0)

Unfortunately, I get a domain error when I try passing example code to SetFragmentProgram, and I have not yet figured out what I am doing wrong.