Retour au sujet

Avatar de TrapHideux TrapHideux
Pour ceux que la programmation intéresse (bon je rêve pas trop on est sur avn) voilà comment on affiche des hapistes:


// -----------------------------------------------------------------------------
// CLASS DECLARATION
// -----------------------------------------------------------------------------

function PPU_SpritesLayer( tilesheetTexture, numSprites )
{
this.build( tilesheetTexture, numSprites );
return this;
}


// -----------------------------------------------------------------------------
// STATIC PROPS
// -----------------------------------------------------------------------------

// context

PPU_SpritesLayer.CONTEXT3D = null;
PPU_SpritesLayer.CRASHED = false;
PPU_SpritesLayer.SCREEN_WIDTH = 1;
PPU_SpritesLayer.SCREEN_HEIGHT = 1;

// static initialized

PPU_SpritesLayer.INITIALIZED = false;

// instance index

PPU_SpritesLayer.NUM_INSTANCES = 0;

// tilesheet dimensions
// for the moment we use fixed dimensions, GBA format.
// multi-resolution will be a later work and should impact only tilesheets

PPU_SpritesLayer.TILESHEET_WIDTH = 128, PPU_SpritesLayer.TILESHEET_HEIGHT = 128;

// vertex shader (for the moment, the same as tilemapLayer, but will be modified)

PPU_SpritesLayer.VERTEX_SHADER_SOURCE = `

attribute vec4 aVertexPosition;
attribute vec2 aTilesheetTextureCoord;
attribute vec2 aSpritesmapTextureCoord;

varying highp vec2 vTilesheetTextureCoord;
varying highp vec2 vSpritesmapTextureCoord;

void main(void) {
gl_Position = aVertexPosition;
vTilesheetTextureCoord = aTilesheetTextureCoord;
vSpritesmapTextureCoord = aSpritesmapTextureCoord;
}

`;
PPU_SpritesLayer.VERTEX_SHADER_ID = 0;

// fragment shader

PPU_SpritesLayer.FRAGMENT_SHADER_SOURCE = `

varying highp vec2 vTilesheetTextureCoord;
varying highp vec2 vSpritesmapTextureCoord;

uniform sampler2D uTilesheetSampler;
uniform sampler2D uTilemapSampler;
uniform sampler2D uPaletteSampler;

const highp float c05 = 0.5;
const highp float c255 = 255.0 ;
const highp float c256 = 256.0 ;

highp vec4 tile;

highp float sheetTexCoordX;
highp float sheetTexCoordY;
highp vec4 colorIndex;

void main(void) {

// get cell info in 64*32 tilemap

tile = texture2D( uTilemapSampler, vSpritesmapTextureCoord );

// get the color index in 16*16 tileSheet

sheetTexCoordX = vTilesheetTextureCoord.x + (tile.r*c255+c05)/c256 ;
sheetTexCoordY = vTilesheetTextureCoord.y + (tile.g*c255+c05)/c256 ;
colorIndex = texture2D( uTilesheetSampler, vec2( ( -2.0 * tile.a + 1.0 )* sheetTexCoordX , sheetTexCoordY ) );

// get the color in the 256x256 palette

gl_FragColor = texture2D( uPaletteSampler, vec2( (colorIndex.a*c255+c05)/c256, (tile.b*c255+c05)/c256 ) );

}

`;
PPU_SpritesLayer.FRAGMENT_SHADER_ID = 0;

// shader program

PPU_SpritesLayer.SHADER_PROGRAM_ID = 0;

// shader locations

PPU_SpritesLayer.XY_ATTRIB_LOCATION = 0;
PPU_SpritesLayer.TILESHEET_UV_ATTRIB_LOCATION = 0;
PPU_SpritesLayer.SPRITESMAP_UV_ATTRIB_LOCATION = 0;

PPU_SpritesLayer.TILESHEET_TEXTURE_UNIFORM_LOCATION = 0;
PPU_SpritesLayer.SPRITESMAP_TEXTURE_UNIFORM_LOCATION = 0;
PPU_SpritesLayer.PALETTE_TEXTURE_UNIFORM_LOCATION = 0;


// -----------------------------------------------------------------------------
// STATIC METHODS
// -----------------------------------------------------------------------------

PPU_SpritesLayer.Init = function (gl, screenWidth, screenHeight)
{
PPU_SpritesLayer.CONTEXT3D = gl;
PPU_SpritesLayer.SCREEN_WIDTH = screenWidth; // avoid spaghetti, use modular classes
PPU_SpritesLayer.SCREEN_HEIGHT = screenHeight;

console.log('PPU_SpritesLayer static shader compilation -----------------');

// compile vertex shader

PPU_SpritesLayer.VERTEX_SHADER_ID = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(PPU_SpritesLayer.VERTEX_SHADER_ID, PPU_SpritesLayer.VERTEX_SHADER_SOURCE);
gl.compileShader(PPU_SpritesLayer.VERTEX_SHADER_ID);

// compile error
if (!gl.getShaderParameter(PPU_SpritesLayer.VERTEX_SHADER_ID, gl.COMPILE_STATUS)) {
alert('PPU_SpritesLayer compile vertex shader error: ' + gl.getShaderInfoLog(PPU_SpritesLayer.VERTEX_SHADER_ID));
gl.deleteShader(PPU_SpritesLayer.VERTEX_SHADER_ID); // AJOUTER CA DANS LE CPP !!!
PPU_SpritesLayer.CRASHED = true;
return false;
} else
{
console.log("PPU_SpritesLayer vertex shader compiled.");
}

// compile fragment shader

PPU_SpritesLayer.FRAGMENT_SHADER_ID = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(PPU_SpritesLayer.FRAGMENT_SHADER_ID, PPU_SpritesLayer.FRAGMENT_SHADER_SOURCE);
gl.compileShader(PPU_SpritesLayer.FRAGMENT_SHADER_ID);

// compile error
if (!gl.getShaderParameter(PPU_SpritesLayer.FRAGMENT_SHADER_ID, gl.COMPILE_STATUS)) {
alert('PPU_SpritesLayer compile fragment shader error: ' + gl.getShaderInfoLog(PPU_SpritesLayer.FRAGMENT_SHADER_ID));
gl.deleteShader(PPU_SpritesLayer.FRAGMENT_SHADER_ID); // AJOUTER CA DANS LE CPP !!!
PPU_SpritesLayer.CRASHED = true;
return false;
} else
{
console.log("PPU_SpritesLayer fragment shader compiled");
}

// link the program shader

PPU_SpritesLayer.SHADER_PROGRAM_ID = gl.createProgram();
gl.attachShader(PPU_SpritesLayer.SHADER_PROGRAM_ID, PPU_SpritesLayer.VERTEX_SHADER_ID);
gl.attachShader(PPU_SpritesLayer.SHADER_PROGRAM_ID, PPU_SpritesLayer.FRAGMENT_SHADER_ID);
gl.linkProgram(PPU_SpritesLayer.SHADER_PROGRAM_ID);

// compile error
if (!gl.getProgramParameter(PPU_SpritesLayer.SHADER_PROGRAM_ID, gl.LINK_STATUS)) {
alert('PPU_SpritesLayer link shaders program error: ' + gl.getProgramInfoLog(PPU_SpritesLayer.SHADER_PROGRAM_ID));
gl.deleteShader(PPU_SpritesLayer.VERTEX_SHADER_ID); // AJOUTER CA DANS LE CPP !!!
gl.deleteShader(PPU_SpritesLayer.FRAGMENT_SHADER_ID); // AJOUTER CA DANS LE CPP !!!
PPU_SpritesLayer.CRASHED = true;
return false;
} else
{
console.log("PPU_SpritesLayer shader programs linked");
}

// shader locations

PPU_SpritesLayer.XY_ATTRIB_LOCATION = gl.getAttribLocation(PPU_SpritesLayer.SHADER_PROGRAM_ID, 'aVertexPosition');
PPU_SpritesLayer.TILESHEET_UV_ATTRIB_LOCATION = gl.getAttribLocation(PPU_SpritesLayer.SHADER_PROGRAM_ID, 'aTilesheetTextureCoord');
PPU_SpritesLayer.SPRITESMAP_UV_ATTRIB_LOCATION = gl.getAttribLocation(PPU_SpritesLayer.SHADER_PROGRAM_ID, 'aSpritesmapTextureCoord');

PPU_SpritesLayer.TILESHEET_TEXTURE_UNIFORM_LOCATION = gl.getUniformLocation(PPU_SpritesLayer.SHADER_PROGRAM_ID, 'uTilesheetSampler');
PPU_SpritesLayer.SPRITESMAP_TEXTURE_UNIFORM_LOCATION = gl.getUniformLocation(PPU_SpritesLayer.SHADER_PROGRAM_ID, 'uTilemapSampler');
PPU_SpritesLayer.PALETTE_TEXTURE_UNIFORM_LOCATION = gl.getUniformLocation(PPU_SpritesLayer.SHADER_PROGRAM_ID, 'uPaletteSampler');

// bool

PPU_SpritesLayer.INITIALIZED = true;

};

PPU_SpritesLayer.ShutDown = function ()
{
if (!PPU_SpritesLayer.CRASHED && PPU_SpritesLayer.INITIALIZED)
{
const gl = PPU_SpritesLayer.CONTEXT3D;
gl.detachShader(PPU_SpritesLayer.SHADER_PROGRAM_ID,PPU_SpritesLayer.VERTEX_SHADER_ID);
gl.detachShader(PPU_SpritesLayer.SHADER_PROGRAM_ID,PPU_SpritesLayer.FRAGMENT_SHADER_ID);
gl.deleteShader(PPU_SpritesLayer.VERTEX_SHADER_ID);
gl.deleteShader(PPU_SpritesLayer.FRAGMENT_SHADER_ID);
console.log("PPU_SpritesLayer shaders deleted");
}

// bool

PPU_SpritesLayer.INITIALIZED = false;
};


// -----------------------------------------------------------------------------
// INSTANCE PROPS
// -----------------------------------------------------------------------------

// instance index

PPU_SpritesLayer.prototype.m_instanceIndex = 0;

// num sprites

PPU_SpritesLayer.prototype.m_numSprites = 0;

// vertex arrays & buffers

PPU_SpritesLayer.prototype.m_sprites_YX = null; //new Float32Array( 8 * this.m_numSprites ); // updated every frame, from uv * matrix
PPU_SpritesLayer.prototype.m_sprites_tilesheet_UV = null; //new Float32Array( 8 * this.m_numSprites ); // updated at init. default 0.0-1.0
PPU_SpritesLayer.prototype.m_spritemap_UV = null; //new Float32Array( 8 * this.m_numSprites ); // theorically updated at init
PPU_SpritesLayer.prototype.m_sprites_indexes = null; //new Uint16Array( 6 * this.m_numSprites );

PPU_SpritesLayer.prototype.m_sprites_XY_buffer = null;
PPU_SpritesLayer.prototype.m_sprites_tileSheet_UV_buffer = null;
PPU_SpritesLayer.prototype.m_spritemap_UV_buffer = null; // all at 0.5 centered on pixels
PPU_SpritesLayer.prototype.m_sprites_indexes_buffer = null;

// arrays & textures for spritemap, palette and scanlines

PPU_SpritesLayer.prototype.m_palette_array = null ; //new Uint8Array( 4 * 16 * 16 );
PPU_SpritesLayer.prototype.m_spritemap_array = null ; //new Uint8Array( 4 * this.m_numSprites );

PPU_SpritesLayer.prototype.m_tileSheet_texture = null; // managed elsewhere
PPU_SpritesLayer.prototype.m_palette_texture = null;
PPU_SpritesLayer.prototype.m_spritemap_texture = null;


// -----------------------------------------------------------------------------
// INSTANCE METHODS
// -----------------------------------------------------------------------------

// build-delete

PPU_SpritesLayer.prototype.build = function( tilesheetTexture, numSprites )
{
// do nothing if not init

if (!PPU_SpritesLayer.INITIALIZED)
{
return null;
}

// instance index

this.m_instanceIndex = PPU_SpritesLayer.NUM_INSTANCES;
PPU_SpritesLayer.NUM_INSTANCES++;

// cache context

const gl = PPU_SpritesLayer.CONTEXT3D;

// args

this.m_numSprites = numSprites;


// alloc CPU arrays and GPU vertex buffers ---------------------------------

// dimension sprites vertex arrays
this.m_sprites_YX = new Float32Array( 8 * this.m_numSprites ); // updated every frame, from uv * matrix
this.m_sprites_tilesheet_UV = new Float32Array( 8 * this.m_numSprites ); // updated at init. default 0.0-1.0
this.m_spritemap_UV = new Float32Array( 8 * this.m_numSprites ); // theorically updated at init, col-row offsets are in spritemap texture
this.m_sprites_indexes = new Uint16Array( 6 * this.m_numSprites );

// cache arrays
var tshUV = this.m_sprites_tilesheet_UV;
var mapUV = this.m_spritemap_UV;
var indxs = this.m_sprites_indexes;

// compute initial values
for ( var iSp = 0; iSp < this.m_numSprites; iSp++ )
{
// uv coords in tileSheet

var it = iSp*8;

// 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0

tshUV[ it + 0 ] = 0.0/16.0 ; tshUV[ it + 1 ] = 1.0/16.0 ;
tshUV[ it + 2 ] = 1.0/16.0 ; tshUV[ it + 3 ] = 1.0/16.0 ;
tshUV[ it + 4 ] = 1.0/16.0 ; tshUV[ it + 5 ] = 0.0/16.0 ;
tshUV[ it + 6 ] = 0.0/16.0 ; tshUV[ it + 7 ] = 0.0/16.0 ;

// uv coords in spriteemap 1-dimension

var im = iSp * 8;

for ( var i=0; i<4; i++ )
{
mapUV[ im + i*2 + 0 ] = ( iSp + 0.5 ) / this.m_numSprites ;
mapUV[ im + i*2 + 1 ] = 0.5 ;
}

// indexes

var ii = iSp * 6;

indxs[ ii + 0 ] = 0 + 4*iSp;
indxs[ ii + 1 ] = 1 + 4*iSp;
indxs[ ii + 2 ] = 2 + 4*iSp;

indxs[ ii + 3 ] = 0 + 4*iSp;
indxs[ ii + 4 ] = 2 + 4*iSp;
indxs[ ii + 5 ] = 3 + 4*iSp;
}

// sprites GPU verts buffers

this.m_sprites_XY_buffer = gl.createBuffer(); // updated at runtime only

this.m_sprites_tileSheet_UV_buffer = gl.createBuffer(); // defaut 0.0 - 1.0
gl.bindBuffer(gl.ARRAY_BUFFER, this.m_sprites_tileSheet_UV_buffer );
gl.bufferData(gl.ARRAY_BUFFER, this.m_sprites_tilesheet_UV, gl.STATIC_DRAW); // will be updated at init later

// for these two ones i could discard array member, we'll see

this.m_spritemap_UV_buffer = gl.createBuffer(); // .5 everywhere, never updated
gl.bindBuffer(gl.ARRAY_BUFFER, this.m_spritemap_UV_buffer );
gl.bufferData(gl.ARRAY_BUFFER, this.m_spritemap_UV, gl.STATIC_DRAW);

this.m_sprites_indexes_buffer = gl.createBuffer(); // never updated
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.m_sprites_indexes_buffer );
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.m_sprites_indexes, gl.STATIC_DRAW); // static buffer, won't be streamed

console.log(" PPU_SpritesLayer instance "+this.m_instanceIndex+" vertices buffers created");


// alloc CPU arrays and GPU textures ---------------------------------------

this.m_tileSheet_texture = tilesheetTexture; // managed elsewhere

this.m_palette_array = new Uint8Array( 4 * 16 * 16 );
this.m_palette_texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, this.m_palette_texture);
// oldschool rendering
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
// initialize data (may be removed)
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 16 , 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, this.m_palette_array);

this.m_spritemap_array = new Uint8Array( 4 * this.m_numSprites );
this.m_spritemap_texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, this.m_spritemap_texture);
// oldschool rendering
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
// initialize data (may be removed)
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.m_numSprites, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, this.m_spritemap_array);

console.log(" PPU_SpritesLayer instance "+this.m_instanceIndex+" textures created");

};

PPU_SpritesLayer.prototype.delete = function()
{
// do nothing if not init

if (!PPU_SpritesLayer.INITIALIZED)
{
console.log('TilesheetTester not initialized');
return null;
}

// cache context

const gl = PPU_SpritesLayer.CONTEXT3D;

// delete arrays and textures ----------------------------------------------

gl.deleteTexture(this.m_palette_texture);
this.m_palette_array = null;
gl.deleteTexture(this.m_spritemap_texture);
this.m_spritemap_array = null;

console.log(" PPU_SpritesLayer instance "+this.m_instanceIndex+" textures deleted");

// delete verts buffers ----------------------------------------------------

gl.deleteBuffer(this.m_sprites_XY_buffer);
this.m_sprites_YX = null;
gl.deleteBuffer(this.m_sprites_tileSheet_UV_buffer);
this.m_sprites_tilesheet_UV = null;
gl.deleteBuffer(this.m_spritemap_UV_buffer);
this.m_spritemap_UV = null;
gl.deleteBuffer(this.m_sprites_indexes_buffer);
this.m_sprites_indexes = null;

console.log(" PPU_SpritesLayer instance "+this.m_instanceIndex+" vertices buffers deleted");

};


// update sprites and palette

PPU_SpritesLayer.prototype.setColor = function ( y, x, r, g, b, a)
{
// voir si ce bordel là est optimisable avec des array 32 (là y'a dla doc webgl à fouiller)

const addr = ( (x&15) | ((y&15)<<4) ) * 4;
let pa = this.m_palette_array;
pa[ addr + 0 ] = r ;
pa[ addr + 1 ] = g ;
pa[ addr + 2 ] = b ;
pa[ addr + 3 ] = a ;
};

PPU_SpritesLayer.prototype.setSprite = function ( index, visible, x, y, indexAscii, paletteY, flipX )
{
x = Math.floor(x); // round coords
y = Math.floor(y);

let xys = this.m_sprites_YX;
const uvs = this.m_sprites_tilesheet_UV;
const iF = index * 8; // index first double

// hide unactive sprite and return

if ( ! visible )
{
for ( let i=0; i<8; i++ )
{
xys[ iF + i ] = -1024 ; // x/y outField
}
return;
}

// compute the pseudo-matrix

const imgW = 128.0, imgH = 128.0; // x y coordinates based on sheet dimensions
const matw = imgW / PPU_SpritesLayer.SCREEN_WIDTH * 2 ;
const math = -imgH / PPU_SpritesLayer.SCREEN_HEIGHT * 2 ;
const matx = x * matw / imgW;
const maty = y * math / imgH;

// tileSheet UV coords are converted to XY coords with "matrix"

for ( let i=0; i<4; i++ )
{
const ix = iF + i*2;
xys[ ix+0 ] = uvs[ ix+0 ] * matw + matx ; // x
xys[ ix+1 ] = uvs[ ix+1 ] * math + maty ; // y
}

// update pixel data in cellList

let colInSheet = indexAscii & 15 ;
if ( flipX )
{
colInSheet = 127 - colInSheet;
}
let rowInSheet = Math.floor( (indexAscii & 255) / 16 );
let colOffset = colInSheet & 15;
let rowOffset = rowInSheet & 15;

let map = this.m_spritemap_array;
const c = index % this.m_numSprites;

map[ 4*c + 0 ] = colOffset << 4 ; // 255->1.0, so 16*16
map[ 4*c + 1 ] = rowOffset << 4 ;
map[ 4*c + 2 ] = paletteY << 4 ;
map[ 4*c + 3 ] = flipX * 255 ; // glsl reads 0.0 / 1.0

};

// drawcall render

PPU_SpritesLayer.prototype.drawCall = function()
{
// cache context

const gl = PPU_SpritesLayer.CONTEXT3D;


// CPU->GPU STREAM PHASE ----------------------------------------------------

// update textures

gl.bindTexture(gl.TEXTURE_2D, this.m_spritemap_texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.m_numSprites, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, this.m_spritemap_array);

gl.bindTexture(gl.TEXTURE_2D, this.m_palette_texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, this.m_palette_array);

// update vertices

gl.bindBuffer(gl.ARRAY_BUFFER, this.m_sprites_XY_buffer);
gl.bufferData(gl.ARRAY_BUFFER, this.m_sprites_YX, gl.STATIC_DRAW);


// DRAW PHASE --------------------------------------------------------------

// bind vertex buffers

gl.bindBuffer(gl.ARRAY_BUFFER, this.m_sprites_XY_buffer);
gl.vertexAttribPointer(PPU_SpritesLayer.XY_ATTRIB_LOCATION, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(PPU_SpritesLayer.XY_ATTRIB_LOCATION);

gl.bindBuffer(gl.ARRAY_BUFFER, this.m_sprites_tileSheet_UV_buffer);
gl.vertexAttribPointer(PPU_SpritesLayer.TILESHEET_UV_ATTRIB_LOCATION, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(PPU_SpritesLayer.TILESHEET_UV_ATTRIB_LOCATION);

gl.bindBuffer(gl.ARRAY_BUFFER, this.m_spritemap_UV_buffer);
gl.vertexAttribPointer(PPU_SpritesLayer.SPRITESMAP_UV_ATTRIB_LOCATION, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(PPU_SpritesLayer.SPRITESMAP_UV_ATTRIB_LOCATION);

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.m_sprites_indexes_buffer);

// select shader program (revoir si c'est dans le bon ordre)

gl.useProgram(PPU_SpritesLayer.SHADER_PROGRAM_ID);

// bind textures

gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, this.m_tileSheet_texture);
gl.uniform1i(PPU_SpritesLayer.TILESHEET_TEXTURE_UNIFORM_LOCATION, 0);

gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, this.m_spritemap_texture);
gl.uniform1i(PPU_SpritesLayer.SPRITESMAP_TEXTURE_UNIFORM_LOCATION, 1);

gl.activeTexture(gl.TEXTURE2);
gl.bindTexture(gl.TEXTURE_2D, this.m_palette_texture);
gl.uniform1i(PPU_SpritesLayer.PALETTE_TEXTURE_UNIFORM_LOCATION, 2);

// draw triangles

gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);

gl.drawElements(gl.TRIANGLES, 6 * this.m_numSprites, gl.UNSIGNED_SHORT, 0);

gl.disable(gl.BLEND);

};