OSX 10.8.3, Python, PyOpenGL.
I'm trying to put together a basic terrain-drawing function in PyOpenGL using VBOs. Having a couple of problems I don't know how to resolve, mostly because I don't fully understand the way VBOs work. This is a basic test sandbox I started when I had too much difficulty changing my project over to VBOs, so it's sloppy in places (see: frame counter).
I've hardcoded a basic 3x3 terrain array and corresponding index array, but it seems to be only drawing two of three rows (it does the y=0 row and y=0.5 but not y=2.0). I'm not entirely comfortable with numpy, so that might be the cause.
The contents of the colour array have only erratic bearing on the final colours: assigning numpy.zeros() to the array produces a black screen, assigning numpy.ones() produces green and purple stripes rather than the white surface I'm expecting. Was initially using random colours but that didn't do anything different from ones(). I don't really understand how OpenGL is supposed to determine that this is a color VBO rather than anything else.
The triangle-drawing algorithm will be problematic, when I get to it - I don't know how best to draw multiple rows without using GL_PRIMITIVE_RESTART, which isn't available in GLUT (I'd rather only change to GLFW or similar as a last resort). Right now, I'm not too concerned about it. Drawing in strips like this isn't quite what I want: http:// www.matrix44.net/cms/notes/opengl-3d-graphics/understanding-gl_triangle_strip (sorry, don't have 10 reputation)
How it currently looks, when rotating: http://i.imgur.com/4Db4qYJ.png
Have been using http://www.mbsoftworks.sk/index.php?page=tutorials&series=1&tutorial=8 as my most successful guide.
I'd really appreciate some guidance with this - no single resource I've found on the web has explained it all, and this isn't exactly a complex topic.
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
from OpenGL.arrays import vbo
from math import sin, cos, tan, radians, sqrt
from numpy import *
from random import random
hWindow = 0
frameno = 0
sr2 = sqrt(0.75)
def InitGL( nWidth, nHeight ):
glClearColor( 0.0, 0.0, 0.0, 0.0 )
glClearDepth( 1.0 )
glDepthFunc( GL_LESS )
glEnable( GL_DEPTH_TEST )
glShadeModel( GL_SMOOTH )
print str(glGetString( GL_VERSION ))
global terrain_vbo, index_vbo, color_vbo
# these two will produce a working (huge) triangle
#terrain_array = array([[ 0,0,0 ], [ 9,0,0 ], [ 0,9,0 ], [ 0,0,9 ]], dtype=float32)
#index_array = array([ 0,1, 0,2, 0,3, 2,3, 2,1],dtype=ubyte)
terrain_array = array([ [[0,0,0], [0,0,1], [0,0,2]],
[[1,0.5,0], [1,0.5,1], [1,0.5,2]],
[[2,2,0], [2,2,1], [2,2,2]] ], dtype=float32)
index_array = array([ 0, 3, 1, 4, 2, 5,
8, 4, 7, 3, 6 ], dtype=ubyte )
color_array = zeros( (9, 3) )
for i in range(9):
color_array[i] += (1.0, 1.0, 1.0)
'''
color_array[0] = [1.0, 0.0, 0.0]
color_array[1] = [0.0, 1.0, 0.0]
color_array[2] = [0.0, 0.0, 1.0]
color_array[3] = [1.0, 1.0, 1.0]
color_array[4] = [1.0, 1.0, 0.0]
'''
#for i in range(len(terrain_array)):
#index_array[i][0] = i
for i in range(len(terrain_array)):
print terrain_array[i]
terrain_vbo = vbo.VBO(terrain_array)
#index_vbo = vbo.VBO( zeros((1,3)), target=GL_ELEMENT_ARRAY_BUFFER )
index_vbo = vbo.VBO(index_array, target=GL_ELEMENT_ARRAY_BUFFER)
color_vbo = vbo.VBO(color_array)
ResizeGLScene( nWidth, nHeight )
def ResizeGLScene( nWidth, nHeight ):
# prevent a divide-by-zero error if the window is too small
if nHeight == 0:
nHeight = 1
# reset the current viewport and recalculate the perspective transformation
# for the projection matrix
glViewport( 0, 0, nWidth, nHeight )
glMatrixMode( GL_PROJECTION )
glLoadIdentity( )
gluPerspective( 45.0, float( nWidth )/float( nHeight ), 0.1, 100.0 )
# return to the modelview matrix mode
glMatrixMode( GL_MODELVIEW )
#
# Draw the scene.
#
def DrawGLScene( ):
# clear the screen and depth buffer
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )
# reset the matrix stack with the identity matrix
glLoadIdentity( )
global frameno
frameno = frameno + 1
glTranslatef( 0.0, -0.2, -2.0 )
glRotatef( frameno/6, 0.0, sr2, 0.0 )
# draw code
#glTranslatef( 0.0, 0.0, -3.0 )
glScalef( 0.5, 0.5, 0.5 )
glColor3f( 1.0, 1.0, 1.0 )
global index_vbo, terrain_vbo, color_vbo
color_vbo.bind()
glEnableClientState( GL_COLOR_ARRAY )
glColorPointer( 3, GL_FLOAT, 0, color_vbo )
terrain_vbo.bind()
glEnableClientState(GL_VERTEX_ARRAY)
glVertexPointer( 3, GL_FLOAT, 0, None )
index_vbo.bind()
glDrawElements(GL_TRIANGLE_STRIP, 6, GL_UNSIGNED_BYTE,None)
glDisableClientState( GL_COLOR_ARRAY )
glDisableClientState( GL_VERTEX_ARRAY )
index_vbo.unbind()
terrain_vbo.unbind()
color_vbo.unbind()
glutSwapBuffers( )
def KeyPressed( key, x, y ):
key = ord(key)
if key == 27:
glutDestroyWindow( hWindow )
sys.exit( )
def main( ):
global hWindow
# initialise GLUT and a few other things
glutInit( "" )
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH )
glutInitWindowSize( 640, 480 )
glutInitWindowPosition( 0, 0 )
# create our window
hWindow = glutCreateWindow( "VBO testing" )
# setup the display function callback
glutDisplayFunc( DrawGLScene )
# go full-screen if we want to
glutFullScreen( )
# setup the idle function callback -- if we idle, we just want to keep
# drawing the screen
glutIdleFunc( DrawGLScene )
# setup the window resize callback -- this is only needed if we arent going
# full-screen
glutReshapeFunc( ResizeGLScene )
# setup the keyboard function callback to handle key presses
glutKeyboardFunc( KeyPressed )
# call our init function
InitGL( 640, 480 )
# enter the window's main loop to set things rolling
glutMainLoop( )
print "Hit ESC key to quit."
main( )
Related
I would like to know how to simply reverse the color order of a given colormap in order to use it with plot_surface.
The standard colormaps also all have reversed versions. They have the same names with _r tacked on to the end. (Documentation here.)
The solution is pretty straightforward. Suppose you want to use the "autumn" colormap scheme. The standard version:
cmap = matplotlib.cm.autumn
To reverse the colormap color spectrum, use get_cmap() function and append '_r' to the colormap title like this:
cmap_reversed = matplotlib.cm.get_cmap('autumn_r')
In matplotlib a color map isn't a list, but it contains the list of its colors as colormap.colors. And the module matplotlib.colors provides a function ListedColormap() to generate a color map from a list. So you can reverse any color map by doing
colormap_r = ListedColormap(colormap.colors[::-1])
As of Matplotlib 2.0, there is a reversed() method for ListedColormap and LinearSegmentedColorMap objects, so you can just do
cmap_reversed = cmap.reversed()
Here is the documentation.
As a LinearSegmentedColormaps is based on a dictionary of red, green and blue, it's necessary to reverse each item:
import matplotlib.pyplot as plt
import matplotlib as mpl
def reverse_colourmap(cmap, name = 'my_cmap_r'):
"""
In:
cmap, name
Out:
my_cmap_r
Explanation:
t[0] goes from 0 to 1
row i: x y0 y1 -> t[0] t[1] t[2]
/
/
row i+1: x y0 y1 -> t[n] t[1] t[2]
so the inverse should do the same:
row i+1: x y1 y0 -> 1-t[0] t[2] t[1]
/
/
row i: x y1 y0 -> 1-t[n] t[2] t[1]
"""
reverse = []
k = []
for key in cmap._segmentdata:
k.append(key)
channel = cmap._segmentdata[key]
data = []
for t in channel:
data.append((1-t[0],t[2],t[1]))
reverse.append(sorted(data))
LinearL = dict(zip(k,reverse))
my_cmap_r = mpl.colors.LinearSegmentedColormap(name, LinearL)
return my_cmap_r
See that it works:
my_cmap
<matplotlib.colors.LinearSegmentedColormap at 0xd5a0518>
my_cmap_r = reverse_colourmap(my_cmap)
fig = plt.figure(figsize=(8, 2))
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15])
ax2 = fig.add_axes([0.05, 0.475, 0.9, 0.15])
norm = mpl.colors.Normalize(vmin=0, vmax=1)
cb1 = mpl.colorbar.ColorbarBase(ax1, cmap = my_cmap, norm=norm,orientation='horizontal')
cb2 = mpl.colorbar.ColorbarBase(ax2, cmap = my_cmap_r, norm=norm, orientation='horizontal')
EDIT
I don't get the comment of user3445587. It works fine on the rainbow colormap:
cmap = mpl.cm.jet
cmap_r = reverse_colourmap(cmap)
fig = plt.figure(figsize=(8, 2))
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15])
ax2 = fig.add_axes([0.05, 0.475, 0.9, 0.15])
norm = mpl.colors.Normalize(vmin=0, vmax=1)
cb1 = mpl.colorbar.ColorbarBase(ax1, cmap = cmap, norm=norm,orientation='horizontal')
cb2 = mpl.colorbar.ColorbarBase(ax2, cmap = cmap_r, norm=norm, orientation='horizontal')
But it especially works nice for custom declared colormaps, as there is not a default _r for custom declared colormaps. Following example taken from http://matplotlib.org/examples/pylab_examples/custom_cmap.html:
cdict1 = {'red': ((0.0, 0.0, 0.0),
(0.5, 0.0, 0.1),
(1.0, 1.0, 1.0)),
'green': ((0.0, 0.0, 0.0),
(1.0, 0.0, 0.0)),
'blue': ((0.0, 0.0, 1.0),
(0.5, 0.1, 0.0),
(1.0, 0.0, 0.0))
}
blue_red1 = mpl.colors.LinearSegmentedColormap('BlueRed1', cdict1)
blue_red1_r = reverse_colourmap(blue_red1)
fig = plt.figure(figsize=(8, 2))
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15])
ax2 = fig.add_axes([0.05, 0.475, 0.9, 0.15])
norm = mpl.colors.Normalize(vmin=0, vmax=1)
cb1 = mpl.colorbar.ColorbarBase(ax1, cmap = blue_red1, norm=norm,orientation='horizontal')
cb2 = mpl.colorbar.ColorbarBase(ax2, cmap = blue_red1_r, norm=norm, orientation='horizontal')
There is no built-in way (yet) of reversing arbitrary colormaps, but one simple solution is to actually not modify the colorbar but to create an inverting Normalize object:
from matplotlib.colors import Normalize
class InvertedNormalize(Normalize):
def __call__(self, *args, **kwargs):
return 1 - super(InvertedNormalize, self).__call__(*args, **kwargs)
You can then use this with plot_surface and other Matplotlib plotting functions by doing e.g.
inverted_norm = InvertedNormalize(vmin=10, vmax=100)
ax.plot_surface(..., cmap=<your colormap>, norm=inverted_norm)
This will work with any Matplotlib colormap.
There are two types of LinearSegmentedColormaps. In some, the _segmentdata is given explicitly, e.g., for jet:
>>> cm.jet._segmentdata
{'blue': ((0.0, 0.5, 0.5), (0.11, 1, 1), (0.34, 1, 1), (0.65, 0, 0), (1, 0, 0)), 'red': ((0.0, 0, 0), (0.35, 0, 0), (0.66, 1, 1), (0.89, 1, 1), (1, 0.5, 0.5)), 'green': ((0.0, 0, 0), (0.125, 0, 0), (0.375, 1, 1), (0.64, 1, 1), (0.91, 0, 0), (1, 0, 0))}
For rainbow, _segmentdata is given as follows:
>>> cm.rainbow._segmentdata
{'blue': <function <lambda> at 0x7fac32ac2b70>, 'red': <function <lambda> at 0x7fac32ac7840>, 'green': <function <lambda> at 0x7fac32ac2d08>}
We can find the functions in the source of matplotlib, where they are given as
_rainbow_data = {
'red': gfunc[33], # 33: lambda x: np.abs(2 * x - 0.5),
'green': gfunc[13], # 13: lambda x: np.sin(x * np.pi),
'blue': gfunc[10], # 10: lambda x: np.cos(x * np.pi / 2)
}
Everything you want is already done in matplotlib, just call cm.revcmap, which reverses both types of segmentdata, so
cm.revcmap(cm.rainbow._segmentdata)
should do the job - you can simply create a new LinearSegmentData from that. In revcmap, the reversal of function based SegmentData is done with
def _reverser(f):
def freversed(x):
return f(1 - x)
return freversed
while the other lists are reversed as usual
valnew = [(1.0 - x, y1, y0) for x, y0, y1 in reversed(val)]
So actually the whole thing you want, is
def reverse_colourmap(cmap, name = 'my_cmap_r'):
return mpl.colors.LinearSegmentedColormap(name, cm.revcmap(cmap._segmentdata))
I found examples on how to create (axonometric) isometric camera in Isometric camera with THREE.js, but how can I create an axonometric oblique?
You can render a scene with an oblique cabinet perspective using a work-around in which the camera is an orthographic one, and the geometry of your mesh is skewed with a shear matrix prior to rendering.
// create shear matrix
var alpha = Math.PI / 6; // or Math.PI / 4
var Syx = 0,
Szx = - 0.5 * Math.cos( alpha ),
Sxy = 0,
Szy = - 0.5 * Math.sin( alpha ),
Sxz = 0,
Syz = 0;
var matrix = new THREE.Matrix4();
matrix.set( 1, Syx, Szx, 0,
Sxy, 1, Szy, 0,
Sxz, Syz, 1, 0,
0, 0, 0, 1 );
// apply shear matrix to geometry
mesh.geometry.applyMatrix4( matrix ); // this is the work-around
EDIT: You can alternatively use the method Matrix4.makeShear() to populate a shear matrix.
three.js r.144
Based on #WestLangley's code, here's how you can do an oblique projection without modifying the geometry, just the camera's matrix.
// shear matrix
// ref: http://www.flipcode.com/documents/matrfaq.html#Q43
// | 1 Syx Szx 0 |
// | |
// | Sxy 1 Szy 0 |
// M = | |
// | Sxz Syz 1 0 |
// | |
// | 0 0 0 1 |
// | |
var alpha = Math.PI / 6; // or Math.PI / 4
var Syx = 0,
Szx = - 0.5 * Math.cos( alpha ),
Sxy = 0,
Szy = - 0.5 * Math.sin( alpha ),
Sxz = 0,
Syz = 0;
var matrix = new THREE.Matrix4();
matrix.set( 1, Syx, Szx, 0,
Sxy, 1, Szy, 0,
Sxz, Syz, 1, 0,
0, 0, 0, 1 );
// apply shear matrix to camera
camera.projectionMatrix.multiply(matrix);
camera.projectionMatrixInverse.getInverse( camera.projectionMatrix );
You would make these projectionMatrix modifications after calling camera.updateProjectionMatrix(). I looked inside the code of camera.updateProjectionMatrix to figure out how to do this, including learning of the inverse matrix that it stores.
One slight downside to this is it moves the view somewhat, but you can just move the camera position or frustum boundaries to account for that. (Maybe there's a better way.)
Fiddle
three.js r.120
Using a texture, I'm trying to pass data to my shader so it knows what color each fragment should be. I'm attempting to create a voxel-type terrain (Minecraft style voxels) using 8-bit ints, with each RGBA value being a different color specified on the shader. The value 1 might be green and 2 might be brown for example.
If my math is correct, a 2048 x 2048 sized texture is the exact size needed for the voxel terrain data:
2048 x 2048 sized texture = 4194304 pixels.
8 x 8 = 64 "chunks" loaded at once.
32 x 32 x 256 = 262144 voxels in a chunk.
64 x 262144 = 16777216 voxels.
For each pixel in the texture I can use RGBA as individual values, so divide it by 4: (Each voxel is therefore 1 byte which is fine as values will be less than 200.)
16777216 / 4 = 4194304 pixels.
That said, I'm having trouble getting the correct texture coordinates to represent the 3D terrain. This is my code at the moment which works fine for a flat plane:
Fragment shader:
int modint( int a, int b )
{
return a - int( floor( float( a ) / float( b ) ) * float( b ) );
}
void main() {
// divide by 4096 because we're using the same pixel twice in each axis
vec4 data = texture2D(uSampler, vec2(verpos.x / 4096.0, verpos.z / 4096.0));
vec2 pixel_of_target = verpos.xz;
int _x = int( pixel_of_target.x );
int _y = int( pixel_of_target.y );
int X = modint( _y, 2 ) * 2 + modint( _x, 2 );
vec4 colorthing;
float blockID;
if (X == 0) blockID = data.x;
else if (X == 1) blockID = data.y;
else if (X == 2) blockID = data.z;
else if (X == 3) blockID = data.w;
if (blockID == 1.0) gl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
else if (blockID == 2.0) gl_FragColor = vec4( 0.0, 1.0, 0.0, 1.0 );
else if (blockID == 3.0) gl_FragColor = vec4( 0.0, 0.0, 1.0, 1.0 );
else if (blockID == 4.0) gl_FragColor = vec4( 1.0, 0.0, 1.0, 1.0 );
}
So basically my texture is a 2D map containing slices of my 3D data, and I need to modify this code so it calculates the correct coordinates. Anyone know how I would do this?
Assuming that your texture will contain 64 slices of your terrain in a 8x8 grid, the following lookup should work:
vec2 texCoord = vec2((verpos.x / 8.0 + mod(verpos.y, 8.0)) / 4096.0,
(verpos.x / 8.0 + floor(verpos.y / 8.0)) / 4096.0));
vec4 data = texture2D(uSampler, texCoord);
... Rest of your shader as above
Your texture then should contain a full 2D slice of the terrain at height 0, then next to it a slice at height 1, until height 7 at the rightmost position. In the next row are heights 8 - 15 and so on.
Having said that, you should normally try to avoid ifs in shader code, because it slows down shader processing quite a bit. If webGL supports arrays (which it does to my knowledge), you can store all your colors in an array and do an array-lookup instead of the if-chain
the texture coordinate should be
vec4 data = texture2D(uSampler, vec2(verpos.x / (4 * 2048.0), verpos.z / 2048.0));
and then the byte to read would be given by
int index = (verpos.x/2048) % 4;
if index == 0 pick data.r, if 1 data.g, if 2 data.b and so on...
I asked this question before about how to pass a data array to a fragment shader for coloring a terrain, and it was suggested I could use a texture's RGBA values.
I'm now stuck trying to work out how I would also use the yzw values. This is my fragment shader code:
vec4 data = texture2D(texture, vec2(verpos.x / 32.0, verpos.z / 32.0));
float blockID = data.x;
vec4 color;
if (blockID == 1.0) {
color = vec4(0.28, 0.52, 0.05, 1.0);
}
else if (blockID == 2.0) {
color = vec4(0.25, 0.46, 0.05, 1.0);
}
else if (blockID == 3.0) {
color = vec4(0.27, 0.49, 0.05, 1.0);
}
gl_FragColor = color;
This works fine, however as you can see it's only using the float from the x-coordinate. If it was also using the yzw coordinates the texture size could be reduced to 16x16 instead of 32x32 (four times smaller).
The aim of this is to create a voxel-type terrain, where each 'block' is 1x1 in space coordinates and is colored based on the blockID. Looks like this:
Outside of GLSL this would be simple, however with no ability to store which blocks have been computed I'm finding this difficult. No doubt, I'm over thinking things and it can be done with some simple math.
EDIT:
Code based on Wagner Patriota's answer:
vec2 pixel_of_target = vec2( verpos.xz * 32.0 - 0.5 ); // Assuming verpos.xz == uv_of_target ?
// For some reason mod() doesn't support integers so I have to convert it using int()
int X = int(mod(pixel_of_target.y, 2.0) * 2.0 + mod(pixel_of_target.x, 2.0));
// Gives the error "Index expression must be constant"
float blockID = data[ X ];
About the error, I asked a question about that before which actually led to me asking this one. :P
Any ideas? Thanks! :)
The idea is to replace:
float blockID = data.x;
By
float blockID = data[ X ];
Where X is a integer that allows you to pick the R, G, B or A from your 16x16 data image.
The thing is how to calculate X in function of your UV?
Ok, you have a target image (32x32) and the data image (16x16). So let's do:
ivec pixel_of_target = ivec( uv_of_target * 32.0 - vec2( 0.5 ) ); // a trick!
Multiplying your UV with the texture dimesions (32 in this case) you find the exact pixel. The -0.5 is necessary because you are trying "to find a pixel from a texture". And of course the texture has interpolated values between the "center of the pixels". You need the exact center of the pixel...
Your pixel_of_target is an ivec (integers) and you can identify exactly where you are drawing! So the thing now is to identify (based on the pixel you are drawing) which channel you should get from the 16x16 texture.
int X = ( pixel_of_target.y % 2 ) * 2 + pixel_of_target.x % 2;
float blockID = data[ X ]; // party on!
This expression above allows you to pick up the correct index X based on the target pixel! On your "data texture" 16x16 map your (R,G,B,A) to (top-left, top-right, bottom-left, bottom-right) of every group of 4 pixels on your target (or maybe upside-down if you prefer... you can figure it out)
UPDATE:
Because you are using WebGL, some details should be changed. I did this and it worked.
vec2 pixel_of_target = vTextureCoord * 32.0 + vec2( 0.5 ); // the signal changed!
int _x = int( pixel_of_target.x );
int _y = int( pixel_of_target.y );
int X = mod( _y, 2 ) * 2 + mod( _x, 2 );
I used this for my test:
if ( X == 0 )
gl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
else if ( X == 1 )
gl_FragColor = vec4( 0.0, 1.0, 0.0, 1.0 );
else if ( X == 2 )
gl_FragColor = vec4( 0.0, 0.0, 1.0, 1.0 );
else if ( X == 3 )
gl_FragColor = vec4( 1.0, 0.0, 1.0, 1.0 );
My image worked perfectly fine:
Here i zommed with Photoshop to see the deatails of the pixels.
PS1: Because I am not familiar with WebGL, I could not run WebGL in Chrome, I tried with Firefox, and I didn't find the mod() function either... So I did:
int mod( int a, int b )
{
return a - int( floor( float( a ) / float( b ) ) * float( b ) );
}
PS2: I don't know why I had to sum vec2( 0.5 ) instead of subtract. WebGL is a little bit different. It probably has this shift. I don't know... It just works.
I am rewriting in GL some core animation code that wasn't performing fast enough.
on my previous version each button was represented by a CALayer, containing sublayers for the overall shape and the text content.
what I would like to do is set .setRasterize = YES on this layer, force it to render onto its own internal bitmap, then send that over to my GL code, currently:
// Create A 512x512 greyscale texture
{
// MUST be power of 2 for W & H or FAILS!
GLuint W = 512, H = 512;
printf("Generating texture: [%d, %d]\n", W, H);
// Create a pretty greyscale pixel pattern
GLubyte *P = calloc( 1, ( W * H * 4 * sizeof( GLubyte ) ) );
for ( GLuint i = 0; ( i < H ); ++i )
{
for ( GLuint j = 0; ( j < W ); ++j )
{
P[( ( i * W + j ) * 4 + 0 )] =
P[( ( i * W + j ) * 4 + 1 )] =
P[( ( i * W + j ) * 4 + 2 )] =
P[( ( i * W + j ) * 4 + 3 )] = ( i ^ j );
}
}
// Ask GL to give us a texture-ID for us to use
glGenTextures( 1, & greyscaleTexture );
// make it the ACTIVE texture, ie functions like glTexImage2D will
// automatically know to use THIS texture
glBindTexture( GL_TEXTURE_2D, greyscaleTexture );
// set some params on the ACTIVE texture
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
// WRITE/COPY from P into active texture
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, W, H, 0, GL_RGBA, GL_UNSIGNED_BYTE, P );
free( P );
glLogAndFlushErrors();
}
could someone help me patch this together?
EDIT: I actually want to create a black and white mask, so every pixel would either be 0x00 or 0xFF, then I can make a bunch of quads, and for each quad I can set all of its vertices to a particular colour. hence I can easily get different coloured buttons from the same stencil...
http://iphone-3d-programming.labs.oreilly.com/ch05.html#GeneratingTexturesWithQuartz
GLSprite example here,
http://developer.apple.com/library/ios/navigation/#section=Frameworks&topic=OpenGLES