Ocaml gl tut1

From Seoushi Games

Jump to: navigation, search

Contents

Introduction

My last article focused on making ocamlsdl work under mac os x. In this article I will be focusing on a simple application with glcaml and ocamlsdl on OS X, however the code itself should run on any system with glcaml and ocamlsdl installed. The application displays a red cube in the center of the screen and closes when a key is pressed, it is very simple.

Prerequisites

For this tutorial you will need ocaml, sdl, ocamlsdl and glcaml installed. For the mac I made a few scripts to automate the process of building ocamlsdl and glcaml. The scripts should work for ppc and intel macs. These scripts are included in the project zip located at the end of the tutorial.

Code Explaination

First I will start off with the main function and branch out from there to cover the rest of the source.

let main () =
	init ();
	
	let w = 800 and h = 600 and bpp = 32 in

	let screen = set_video_mode w h bpp [OPENGL] in
	init_gl w h;
	let texture = int_array_make 1 in
	glGenTextures 1 texture;
	
	let finished = ref false in
	
	while not !finished do
		glClear  [GL_COLOR_BUFFER_BIT; GL_DEPTH_BUFFER_BIT];
		drawCube ();
		Sdl.GL.swap_buffers ();
	
   		begin match poll_event () with
      	| Some (KeyDown _ | Quit) -> finished := true
   	  	| _ -> ()
    	end;
  	done;;
  
let _ = Printexc.catch main ()

If you've had experience with opengl and sdl before then the above code will be easy to follow but I will assume you don't so no one gets lost. Init() calls the setup routines which I will discuss later. Next I setup the opengl window with sdl, set_video_mode takes in 5 arguments: width of the screen, height of the screen, bits per pixel and sdl flags. For now the only flag you need to pass to sdl is OPENGL, there might be some other flags you would like to use such as fullscreen but I will cover that in another tutorial. init_gl takes in a width and a height and sets up opengl for rendering, I'll come back to this later. Last we have the application loop, while a key is not pressed the application clears the screen, draws the cube and swaps the buffers to the main screen.

let init () =
  try
    Sdl.init [VIDEO];
    show_cursor true
  with SDL_failure m ->
    Printf.eprintf "SDL init failure: %s\n" m;
    exit 1
;;

This is the initialization routine for sdl, it tells sdl that it needs to intialize the video and show the cursor on the window. If for some reason this fails an error message is printed out.

let init_gl width height =

	glViewport 0 0 width height;
	glClearColor 0.0 0.0 0.0 0.0;
	glClearDepth 1.0;
	glDepthFunc GL_LESS;
	glEnable GL_DEPTH_TEST;
	glShadeModel GL_SMOOTH;
	glMatrixMode GL_PROJECTION;
	glLoadIdentity ();

	let aspect = (float_of_int width) /. (float_of_int height) in
	perspective 45.0 aspect 1.0 100.0;
	glMatrixMode GL_MODELVIEW

in init_gl, opengl is setup to handle rendering in 3d space. I highly suggest that you take a look at the opengl redbook or api to understand what the gl* functions are doing, they aren't that complex. The only function here that is not in opengl function is perspective which takes the view angle of the screen, aspect ratio, near plane and far plane.

let perspective fov aspect zNear zFar =
	let pi = 4.0 *. (atan 1.0) in
	let fH = (tan (fov /. 360.0 *. pi )) *. zNear in
	let fW = fH *. aspect in
	glFrustum (-.fW) fW (-.fH) fH zNear zFar;;

All perspective does is setup the frustum. Again I implore you to check out the redbook, it can explain things like this a lot better then I can.

let drawCube () =
	glLoadIdentity  () ;
	glTranslatef 0.0 0.0 (-.10.0) ;
	glBegin GL_QUADS ;		                 (* begin drawing a cube *)
	glColor3f 1.0 0.0 0.0 ;
    
     (* Front Face  note that the texture's corners have to match the quad's corners  *)
    glVertex3f (-.1.0)  (-.1.0)   1.0 ;	 (* Bottom Left Of The Texture and Quad *)
    glVertex3f  1.0  (-.1.0)   1.0 ;	 (* Bottom Right Of The Texture and Quad *)
    glVertex3f  1.0   1.0   1.0 ;	 (* Top Right Of The Texture and Quad *)
    glVertex3f (-.1.0)   1.0   1.0 ;	 (* Top Left Of The Texture and Quad *)

     (* Back Face *)
    glVertex3f (-.1.0)  (-.1.0)  (-.1.0) ;	 (* Bottom Right Of The Texture and Quad *)
    glVertex3f (-.1.0)   1.0  (-.1.0) ;	 (* Top Right Of The Texture and Quad *)
    glVertex3f  1.0   1.0  (-.1.0) ;	 (* Top Left Of The Texture and Quad *)
    glVertex3f  1.0  (-.1.0)  (-.1.0) ;	 (* Bottom Left Of The Texture and Quad *)

     (* Top Face *)
    glVertex3f (-.1.0)   1.0  (-.1.0) ;	 (* Top Left Of The Texture and Quad *)
    glVertex3f (-.1.0)   1.0   1.0 ;	 (* Bottom Left Of The Texture and Quad *)
    glVertex3f  1.0   1.0   1.0 ;	 (* Bottom Right Of The Texture and Quad *)
    glVertex3f  1.0   1.0  (-.1.0) ;	 (* Top Right Of The Texture and Quad *)

     (* Bottom Face   *)     
    glVertex3f (-.1.0)  (-.1.0)  (-.1.0) ;	 (* Top Right Of The Texture and Quad *)
    glVertex3f  1.0  (-.1.0)  (-.1.0) ;	 (* Top Left Of The Texture and Quad *)
    glVertex3f  1.0  (-.1.0)   1.0 ;	 (* Bottom Left Of The Texture and Quad *)
    glVertex3f (-.1.0)  (-.1.0)   1.0 ;	 (* Bottom Right Of The Texture and Quad *)

     (* Right face *)
    glVertex3f  1.0  (-.1.0)  (-.1.0) ;	 (* Bottom Right Of The Texture and Quad *)
    glVertex3f  1.0   1.0  (-.1.0) ;	 (* Top Right Of The Texture and Quad *)
    glVertex3f  1.0   1.0   1.0 ;	 (* Top Left Of The Texture and Quad *)
    glVertex3f  1.0  (-.1.0)   1.0 ;	 (* Bottom Left Of The Texture and Quad *)

     (* Left Face *)
    glVertex3f (-.1.0)  (-.1.0)  (-.1.0) ; (* Bottom Left Of The Texture and Quad *)
    glVertex3f (-.1.0)  (-.1.0)   1.0 ;	 (* Bottom Right Of The Texture and Quad *)
    glVertex3f (-.1.0)   1.0   1.0 ; (* Top Right Of The Texture and Quad *)
    glVertex3f (-.1.0)   1.0  (-.1.0) ; (* Top Left Of The Texture and Quad *)

    glEnd  ()

While the drawing code is a little long it is easy to understand, first it resets the modelview matrix to to origin then moves the camera back 10 units so what we are drawing doesn't take up the whole screen. Then it sets the color to red and draws all the faces. Each face is just a set of 4 vertices to define a quad in 3d space, note that the order of drawing the vertices is important. Depending on how opengl is setup you must draw the vertices in clockwise or counterclockwise order. The redbook should explain this more throughly.

Compiling the example

In the project zip all you have to do is run "./compilelibs.sh && ./compile.sh". Compilelibs will make ocamlsdl and glcaml and place the needed files in the project directory, you only need to run this once. Compile will build the tutorial source and output a file called tutorial1. For those that aren't using OS X and have ocamlsdl and glcaml installed you can issue this command to build the source. "ocamlopt -o tutorial1 glcaml.cmxa sdl.cmxa tut1.ml"

Download

project zip