Titanium Mobile: OpenGL ES Docs

OpenGL IOS Module (Docs)

Overview

Ti.OpenGL extends the Ti.View class with a Titanium view that responds to Open GL API commands and renders the resulting graphics. Ti.OpenGL views provide Javascript wrappers for almost all of the ES 1.1 and ES 2.0 API. In some cases, the Ti.OpenGL versions have been modified to accommodate the differences between Javascript and lower-level codes like Objective C and C++.

Get the Titanium module here (Pro subscription required)

Here’s  the documentation:

Creating the view

Load the module, as usual:

Ti.Opengl = require('Ti.OpenGL');

To create a view execute something like the following:

var opengl = Ti.Opengl.createView({
    version : 1,
    backgroundColor:"#aaa",
    top:10,
    left:10,
    width:300,
    height:420,
    depthbuffer:false
    multisampling:false
});
  • version: Can be either 1 or 2, for OpenGL ES 1.1 or 2.0
  • backgroundcolor: Select a background color to be used with the clear command. Background color can be changed later. Note: you can omit the background color and use glClearColor directly instead.
  • top, left, width, height: bounds in the containing view or window.
  • depthbuffer: indicates desire for a depthbuffer attachement to the framebuffer
  • multisampling: indicates use of multisampling. When multisampling is true, the depthbuffer property is ignored and a depthbuffer is used.

Ti.OpenGL view creation automates framebuffer, renderbuffer and depthbuffer initialization, along with sampling render- and depthbuffers for multisampling when indicated.

 

When can you issue OpenGL commands?

The OpenGL view created in the previous section will not initialize until it has been added to a parent view or window and opened. Once initialization is complete, the view issues a ready event with itself as the value of the property “view”. You should add an event listener containing your OpenGL setup and animation functions to be triggered once the view’s warmup has concluded. Example:

var opengl = Ti.Opengl.createView({
    version : 2,
        backgroundColor:"#aaa",
        top:10,
    left:10,
        width:300,
    height:420,
    initializer:false,
    multisampling:false
});

function doOpengl(e) {
    // e.view == opengl
    // issue opengl commands, etc.
}

opengl.addEventListener('ready', doOpengl);
window.add(opengl);
window.open();

In this example we create the opengl view and write a function doOpengl which contains the OpenGL API calls, as described below. These calls cannot be issued until the view is actually opened, so we add doOpengl to opengl (the view) as a listener for theready event. When this event fires, the view itself is bound to e.view and can be referenced this way in the body of doOpengl. Of course, it can also be accessed using the global variable opengl, however this way a single listener can be used for multiple views.

 

Using the OpenGL API

In the following, assume view represents a Ti.OpenGL view created as in the previous example. Ti.Opengl will refer to the module itself, bound with require('Ti.OpenGL').

 

Installing the context

Each view represents a separate OpenGL context. This context is installed as the current context when the view is created, and so if there is only 1 view the context will remain installed throughout the session. Otherwise, issuing view.setCurrentContext()will install the context associated with view. It is good practice to issue view.setCurrentContext() before a sequence of OpenGL commands.

 

Using the API

Most of the OpenGL API has been exposed as functions of the view object. So, for example, view.glLoadIdentity() corresponds to the API call glLoadIdentity(). OpenGL constants are properties of both the view and the module; for example,Ti.Opengl.GL_FLOAT and view.GL_FLOAT both refer to the OpenGL constant GL_FLOAT. So, for example, the following sequence of commands correspond to the setup and animation callback functions used in the Apple OpenGL template:

var setup = function(view) {
    view.setCurrentContext();
    view.glMatrixMode(Ti.Opengl.GL_PROJECTION);
    view.glLoadIdentity();
    view.glMatrixMode(Ti.Opengl.GL_MODELVIEW);
    view.glLoadIdentity();
    view.glVertexPointer(2, Ti.Opengl.GL_FLOAT, 0, squareVertices);
    view.glColorPointer(4, Ti.Opengl.GL_UNSIGNED_BYTE, 0, squareColors);
    view.glEnableClientState(Ti.Opengl.GL_VERTEX_ARRAY);
    view.glEnableClientState(Ti.Opengl.GL_COLOR_ARRAY);
}

var drawsquare = function(view) {
    view.setFrameBuffer();
    view.clear();
    view.glLoadIdentity();
    view.glTranslatef(0.0, Math.sin(transY)/2.0, 0.0);
    transY += 0.075;
    view.glDrawArrays(Ti.Opengl.GL_TRIANGLE_STRIP, 0, 4);
    view.presentFrameBuffer();
};

Here squareVertices and squareColors are Javascript arrays

var squareVertices = [-0.5, -0.33, 0.5, -0.33,
                      -0.5,  0.33, 0.5,  0.33,];
var squareColors = [255, 255, 0, 255, 0, 255, 255, 255,
                     0, 0, 0, 0, 255, 0, 255, 255];

Each drawing sequence must begin with view.setFrameBuffer() and end with view.presentFrameBuffer()view.clear(); is a convenience function which clears the view as appropriate according to whether or not multisampling is enabled. The color specified by the backgroundcolor property is used. Alternatively, if multisampling is not enabled, the following may be used:

view.glClearColor(r, g, b);
view.glClear(TiOpengl.GL_COLOR_BUFFER_BIT | TiOpengl.GL_DEPTH_BUFFER_BIT);

The call view.presentFrameBuffer() performs all necessary post-rendering discarding and presents the renderbuffer to the context.

Below is a complete program that renders the Apple “bouncing square” demo template. The setup function is called once to identify the vertex and color arrays and enable their use. The animation callback (drawsquare) clears the screen and the pipeline, applies the translation transformation to the pipeline, and draws the arrays.


var window = Ti.UI.createWindow();
Ti.Opengl = require('Ti.OpenGL');
Ti.API.info("module is => " + TiOpengl);

var opengl = Ti.Opengl.createView({
    backgroundColor:"#aaa",
    top:10,
    left:10,
    width:300,
    height:420,
});

var squareVertices = [
   -0.5, -0.33,
    0.5, -0.33,
   -0.5,  0.33,
    0.5,  0.33,
];

var squareColors = [
    255, 255,   0, 255,
    0,   255, 255, 255,
    0,     0,   0,   0,
    255,   0, 255, 255,
];

var transY = 0.0;

var setup = function(view) {
    view.setCurrentContext();
    view.glMatrixMode(Ti.Opengl.GL_PROJECTION);
    view.glLoadIdentity();
    view.glMatrixMode(Ti.Opengl.GL_MODELVIEW);
    view.glLoadIdentity();
    view.glVertexPointer(2, Ti.Opengl.GL_FLOAT, 0, squareVertices);
    view.glColorPointer(4, Ti.Opengl.GL_UNSIGNED_BYTE, 0, squareColors);
    view.glEnableClientState(Ti.Opengl.GL_VERTEX_ARRAY);
    view.glEnableClientState(Ti.Opengl.GL_COLOR_ARRAY);
}

var drawsquare = function(view) {
    view.setFrameBuffer();
    view.clear();
    view.glLoadIdentity();
    view.glTranslatef(0.0, Math.sin(transY)/2.0, 0.0);
    transY += 0.075;
    view.glDrawArrays(Ti.Opengl.GL_TRIANGLE_STRIP, 0, 4);
    view.presentFrameBuffer();
};

function doOpengl(e) {
    setup(opengl);
    setInterval(function(e){drawsquare(opengl);}, 33.33333);
}

window.add(opengl);
opengl.addEventListener('ready', doOpengl);
window.open();

 

Ti.OpenGL does not support interleaving

For this release Ti.OpenGL does not support interleaving of vertex, color, texture, normal, etc. in a single data structure. You must use separate flat arrays for these parameters, and a stride value of 0 in glVertexPointer, etc. Future releases of Ti.OpenGL may provide support for interleaving.

 

Using DataBuffers

When Javascript arrays are passed as arguments, the module code must copy the contents of those arrays into contiguous memory. This happens in calls such as view.glVertexPointer and view.glColorPointer. This creates inefficiencies when large arrays are copied for each animation frame. Ti.OpenGL solves this problem by implementing a DataBuffer object that can substitute for a vertex, color or texture array in calls where those arrays are usually passed as arguments.

To create DataBuffers for the arrays in our example program, do the following:

var vertexDB = Ti.Opengl.createDataBuffer({
    data : squareVertices,
    type : Ti.Opengl.GL_FLOAT
});
var colorDB = Ti.Opengl.createDataBuffer({
    data : squareColors,
    type : Ti.Opengl.GL_UNSIGNED_BYTE
});

In the call to createDataBuffer you supply the array and the OpenGL type of the data. Now, you may substitute DataBuffer arguments for array arguments in calls to glVertexPointer and glColorPointer:

view.glVertexPointer(2, Ti.Opengl.GL_FLOAT, 0, vertexDB);
view.glColorPointer(4, Ti.Opengl.GL_UNSIGNED_BYTE, 0, colorDB);

Our complete program becomes:

var window = Ti.UI.createWindow();
Ti.Opengl = require('Ti.OpenGL');
Ti.API.info("module is => " + Ti.Opengl);

var opengl = Ti.Opengl.createView({
    backgroundColor:"#aaa",
    top:10,
    left:10,
    width:300,
    height:420,
});

var squareVertices = [
   -0.5, -0.33,
    0.5, -0.33,
   -0.5,  0.33,
    0.5,  0.33,
];

var squareColors = [
    255, 255,   0, 255,
    0,   255, 255, 255,
    0,     0,   0,   0,
    255,   0, 255, 255,
];

var transY = 0.0;

var vertexDB = Ti.Opengl.createDataBuffer({
    data : squareVertices,
    type : Ti.Opengl.GL_FLOAT
});
var colorDB = Ti.Opengl.createDataBuffer({
    data : squareColors,
    type : Ti.Opengl.GL_UNSIGNED_BYTE
});

var setup = function(view) {
    view.setCurrentContext();
    view.glMatrixMode(Ti.Opengl.GL_PROJECTION);
    view.glLoadIdentity();
    view.glMatrixMode(Ti.Opengl.GL_MODELVIEW);
    view.glLoadIdentity();
    view.glVertexPointer(2, Ti.Opengl.GL_FLOAT, 0, vertexDB);
    view.glColorPointer(4, Ti.Opengl.GL_UNSIGNED_BYTE, 0, colorDB);
    view.glEnableClientState(Ti.Opengl.GL_VERTEX_ARRAY);
    view.glEnableClientState(Ti.Opengl.GL_COLOR_ARRAY);
}

var drawsquare = function(view) {
    view.setFrameBuffer();
    view.clear();
    view.glLoadIdentity();
    view.glTranslatef(0.0, Math.sin(transY)/2.0, 0.0);
    transY += 0.075;
    view.glDrawArrays(Ti.Opengl.GL_TRIANGLE_STRIP, 0, 4);
    view.presentFrameBuffer();
};

function doOpengl(e) {
    setup(opengl);
    setInterval(function(e){drawsquare(opengl);}, 33.33333);
}

window.add(opengl);
opengl.addEventListener('ready', doOpengl);
window.open();

A complete list of API calls in which a DataBuffer is acceptable (or required) is given in the appendix.

DataBuffers have a size property that contains the number of bytes actually used by the buffer. This is important for using vertex buffers, as described in the next section.

 

Using Open GL vertex buffers

Open GL EXT provides an even more efficient protocol through the use of vertex buffers objects (vbo’s) in the GPU. See http://www.opengl.org/wiki/Vertex_Buffer_Object for details on using vbo’s. Ti.OpenGL supports sequential vbo use (i.e., the contents of the vertex vbo contain vertex, color, normal, etc. data sequentially rather than interleaved).

Ti.OpenGL implements the glGenBuffersglBindBuffer and glBufferData API calls required to create vbo’s (note that glGenBuffers is modified from its native form; see API Function Modifications below). Ti.OpenGL also implements a modified version of glMapBufferOES, called simply mapBuffer, that is more suitable for the Javascript environment. mapBuffer uses DataBuffers to create sequential maps. Further discussion is in the section Special Functions.

 

Implemented API functions

* = implementation differs from Open GL API in a significant way — see API Function Modifications and the appendix.

ES 1.1

glActiveTexture
glAlphaFunc
glAlphaFuncx
glBindBuffer
glBindTexture
glBlendFunc
glBufferData
glBufferSubData
glClear
glClearColor
glClearDepthf
glClientActiveTexture
glClipPlanef
glClipPlanex
glColor4f
glColor4x
glColor4ub
glColorPointer
glCompressedTexImage2D
glCompressedTexSubImage2D
glCopyTexImage2D
glCopyTexSubImage2D
glCullFace
glDeleteBuffers
glDeleteTextures
glDepthFunc
glDepthMask
glDepthRangef
glDepthRangex
glDisable
glDisableClientState
glDrawArrays
glDrawElements
glEnable
glEnableClientState
glFinish
glFlush
glFogf
glFogx
glFrontFace
glFrustumf
glGenBuffers
glGenTextures
glGetBooleanv
glGetFixedv
glGetFloatv
glGetIntegerv
glGetBufferParameteriv
glGetClipPlanef
glGetClipPlanex
glGetLightfv
glGetLightxv
glGetMaterialfv
glGetMaterialxv
glGetString
glGetTexEnvfv
glGetTexEnvxv
glGetTexEnviv
glGetTexParameterfv
glGetTexParameteriv
glHint
glIsBuffer
glIsEnabled
glIsFramebuffer
glIsTexture
glLightf
glLightx
glLightfv
glLightxv
glLightModelf
glLightModelx
glLightModelfv
glLightModelxv
glLineWidth
glLoadIdentity
glLoadMatrixf
glLoadMatrixx
glLogicOp
glMaterialf
glMaterialx
glMaterialfv
glMaterialxv
glMatrixMode
glMultMatrixf
glMultMatrixx
glMultiTexCoord4f
glMultiTexCoord4x
glNormal3f
glNormal3x
glNormalPointer
glOrthof
glPixelStorei
glPointParameterf
glPointParameterx
glPointParameterfv
glPointParameterxv
glPointSize
glPointSizex
glPointSizePointerOES
glPopMatrix
glPushMatrix
glReadPixels
glRotatef
glRotatex
glSampleCoverage
glScalef
glScalex
glScissor
glShadeModel
glStencilFunc
glStencilMask
glStencilOp
glTexCoordPointer
glTexEnvf
glTexEnvi
glTexEnvx
glTexParameterf
glTexParameteri
glTexParameterx
glTranslatef
glTranslatex
glVertexPointer
glViewport

ES 2

glActiveTexture
glAttachShader
glBindAttribLocation
glBindBuffer
glBindFramebuffer
glBindRenderbuffer
glBindTexture
glBlendColor
glBlendEquation
glBlendEquationSeparate
glBlendFunc
glBlendFuncSeparate
glBufferData
glBufferSubData
glCheckFramebufferStatus
glClear
glClearColor
glClearDepthf
glClearStencil
glColorMask
glCompileShader
glCompressedTexImage2D
glCompressedTexSubImage2D
glCopyTexImage2D
glCopyTexSubImage2D
glCreateProgram
glCreateShader
glCullFace
glDeleteBuffers
glDeleteFramebuffers
glDeleteProgram
glDeleteRenderbuffers
glDeleteShader
glDeleteTextures
glDepthFunc
glDepthMask
glDepthRangef
glDetachShader
glDisable
glDisableVertexAttribArray
glDisable
glDisableVertexAttribArray
glDrawArrays
glDrawElements
glEnable
glEnableVertexAttribArray
glFinish
glFlush
glFramebufferRenderbuffer
glFramebufferTexture2D
glFrontFace
glGenBuffers
glGenFramebuffers
glGenRenderbuffers
glGenTextures
glGenerateMipmap
glGetBooleanv
glGetFloatv
glGetIntegerv
glGetActiveAttrib
glGetActiveUniform
glGetAttachedShaders
glGetAttribLocation
glGetBufferParameteriv
glGetError
glGetFramebufferAttachmentParameteriv
glGetProgramInfoLog
glGetProgramiv
glGetRenderbufferParameteriv
glGetShaderInfoLog
glGetShaderPrecisionFormat
glGetShaderSource
glGetShaderiv
glGetString
glGetTexParameterfv
glGetTexParameteriv
glGetUniformfv
glGetUniformiv
glGetUniformLocation
glGetVertexAttribfv
glGetVertexAttribiv
glHint
glIsBuffer
glIsEnabled
glIsFramebuffer
glIsProgram
glIsRenderbuffer
glIsShader
glIsTexture
glLineWidth
glLinkProgram
glPixelStorei
glPolygonOffset
glReadPixels
glReleaseShaderCompiler
glRenderBufferStorage
glSampleCoverage
glScissor
glShaderSource
glStencilFunc
glStencilFuncSeparate
glStencilMask
glStencilMaskSeparate
glStencilOp
glStencilOpSeparate
glTexParameterf
glTexParameteri
glUniform1f
glUniform2f
glUniform3f
glUniform4f
glUniform1i
glUniform2i
glUniform3i
glUniform4i
glUseProgram
glValidateProgram
glVertexAttrib1f
glVertexAttrib2f
glVertexAttrib3f
glVertexAttrib4f
glVertexAttribPointer
glViewport

 

API Function Modifications

 

Passing Objects

For any API or special function with 2 or more parameters the user may pass an object containing parameters bound to the standard keywords used in the OpenGL reference pages to describe that function. For example, the description for glActiveShadernames the arguments as folows:

void glAttachShader(GLuint program, GLuint shader);

In Javascript, this function may be called in either of 2 ways:

view.glAttachShader(myprogram, myshader);

or view.glAttachShader({program: myprogram, shader: myshader})

The OpenGL API reference pages can be found at http://www.khronos.org/opengles/sdk/1.1/docs/man/ (ES 1.1) and http://www.khronos.org/opengles/sdk/docs/man/ (ES 2)

 

Reference parameters

Many OpenGL functions return values in buffers passed in as reference paramenters. Since Javascript does not support reference parameters, the Ti.OpenGL versions of these functions instead return single values, arrays or objects. This protocol is most visible in the glGet… functions. The appendix contains details regarding those API functions that return values.

glTexImage and glTexSubimage

These API functions require significant low-level preprocessing of images and so have been omitted. They have been replaced by 2 special functions, texImage and texSubimage that include image process in their definitions. For convenience, special functionscompressedTexImage and compressedTexSubImage are also included, although versions of the API functions for compressed texture images are implemented. All such functions, including the API functions glCompressedTexImage andglCompressedTexSubImage accept as arguments Ti file objects referencing image files instead of image buffers. See Special Functions and the appendix for details.

Titanium Extension Functions

The following special functions are properties of the view object and extend the API.

void setCurrentContext()

Installs the context associated with the view. Does nothing if that view is already installed.


void setFrameBuffer()

  • Creates framebuffers if necessary (i.e., on the first call)
  • Sets up multisampling if selected Should be called before any sequence of drawing commands.

void presentFrameBuffer()

  • Performs necessary discards
  • Resolves multisampling if selected
  • Binds and presents the color renderbuffer to the context for rendering. Should be the last call in any drawing sequence.

void resetFrameBuffer()

Rebuilds frame buffers.


void clear()

  • executes glClearColor(...) with the current background color
  • executes glClear(GL_COLOR_BIT | GL_DEPTHBUFFER_BIT)
  • executes glClear on the sample framebuffer if multisampling is selected

void mapBuffer(target, usage, databuffer databuffer, ...)
void mapBuffer(target, usage, [databuffer, databuffer, ...])

mapBuffer maps the data contained in the databuffer parameters to GPU memory by executing glMapBufferOES to obtain a pointer to GPU memory, then using memcpy to sequentially copy the data in the databuffers to the GPU buffer. It performs the following in sequence:

  • Calls glBufferData(target, tot, 0, usage) to create a data store for targettot is computed by summing the sizes of the databuffers.
  • Calls p = glMapBufferOES(target, GL_WRITE_ONLY_OES) to obtain pointer p into GPU memory.
  • Calls memcpy(p, databuffer.contents, databuffer.size); p += databuffer.size on each of the databuffers in sequence
  • Calls glUnmapBufferOES(target)

void texImage2D(level, internalformat, width, height, border, type, file)`

void texSubImage2D(level, xoffset, yoffset, width, height, format, type, file)`

Analogous to glTexImage2D and glTexSubImage2D, where file is a Ti.Filesystem.File containing the image. These functions process the image file before calling the corresponding API functions. If width and/or height are 0, their values are obtained from the image file.


void compressedTexImage2D(level, width, height, border, file)`

void compressedTexSubImage2D(level, xoffset, yoffset, width, height, file)`

Analogous to glCompressedTexImage2D and glCompressedSubImage2D, where file is a Ti.Filesystem.File referencing a .pvtrc file of the type GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG. This type of file is obtained using Apple’s texturetool with default options. If width and/or height are 0, their values default to 512.


 

Appendix: Ti OpenGL API

The principal references for the Ti OpenGL API are the Khronos man pages at http://www.khronos.org/opengles/sdk/1.1/docs/man/ (ES 1.1) and http://www.khronos.org/opengles/sdk/docs/man/ (ES 2). In this section we fully document differences between standard API calls and Ti.OpenGL API calls.

“glGet” and “glGen” functions

In general, OpenGL void glGet... void glGen ... calls (and a few others) include a reference parameter pointing to an array in which the result of the request is returned. TiOpenGL implements these by returning a Javascript scalar value (number or string) or array containing the result. The Ti.OpenGL version of the function aloways has one fewer parameter. For example:

OpenGL (C): returns the result in the C array params

float params[4];
glGetFloatv(GL_COLOR_CLEAR_VALUE, params);

Ti.OpenGL (Javascript): result is a Javascript array returned and assigned to params

params = view.glGetFloatv(Ti.Opengl.GL_COLOR_CLEAR);

This pattern applies to all of the following:

ES 1.1:
glGenBuffers
glGenTextures
glGetFixedv
glGetFloatv
glGetIntegerv
glGetBufferParameteriv
glGetClipPlanef
glGetClipPlanex
glGetLightfv
glGetLightxv
glGetMaterialfv
glGetMaterialxv
glGetString
glGetTexEnvfv
glGetTexEnvxv
glGetTexEnviv
glGetTexParameterfv
glGetTexParameteriv
glReadPixels
ES 2:
glGenBuffers
glGenFramebuffers
glGenRenderbuffers
glGenTextures
glGetBooleanv
glGetFloatv
glGetIntegerv
glGetActiveAttrib
glGetActiveUniform
glGetAttachedShaders
glGetAttribLocation
glGetBufferParameteriv
glGetError
glGetFramebufferAttachmentParameteriv
glGetProgramInfoLog
glGetProgramiv
glGetRenderbufferParameteriv
glGetShaderInfoLog
glGetShaderPrecisionFormat
glGetShaderSource
glGetShaderiv
glGetString
glGetTexParameterfv
glGetTexParameteriv
glGetUniformfv
glGetUniformiv
glGetUniformLocation
glGetVertexAttribfv
glGetVertexAttribiv
glReadPixels

 

Use of DataBuffers in place of pointers

The following API functions that pass pointers to arrays of data will accept either a Javascript array or DataBuffer in place of that parameter:

ES 1.1:
glColorPointer
glLight
glLightModelv
glLoadMatrix
glMaterial
glMultMatrix
glNormalPointer
glPointParameter
glPointSizePointerOES
glTexCoordPointer
glVertexPointer
ES 2:
glDrawElements
glVertexAttribPointer

The following API functions that pass pointers to arrays of data will only accept a DataBuffer in place of that parameter:

ES 1.1 and ES 2:
glBufferData
glBufferSubData

 

Author

Developed for Appcelerator by Logical Labs

License

Copyright(c) 2011 by Appcelerator, Inc. All Rights Reserved.

 

Advertisements

%d bloggers like this: