KDvoid CCTextureAtlas::moveQuadsFromIndex ( KDuint uOldIndex, KDuint uAmount, KDuint uNewIndex )
{
    CCAssert ( uNewIndex + uAmount <= m_uTotalQuads, "insertQuadFromIndex:atIndex: Invalid index" );
    CCAssert ( uOldIndex < m_uTotalQuads, "insertQuadFromIndex:atIndex: Invalid index" );

    if ( uOldIndex == uNewIndex )
    {
        return;
    }

    //create buffer
    KDsize   nQuadSize = sizeof ( ccV3F_C4B_T2F_Quad );
    ccV3F_C4B_T2F_Quad*  pTempQuads = (ccV3F_C4B_T2F_Quad*) kdMalloc ( nQuadSize * uAmount );
    kdMemcpy ( pTempQuads, &m_pQuads [ uOldIndex ], nQuadSize * uAmount );

    if ( uNewIndex < uOldIndex )
    {
        // move quads from newIndex to newIndex + amount to make room for buffer
        kdMemmove ( &m_pQuads [ uNewIndex ], &m_pQuads [ uNewIndex + uAmount ], ( uOldIndex - uNewIndex ) * nQuadSize );
    }
    else
    {
        // move quads above back
        kdMemmove ( &m_pQuads [ uOldIndex ], &m_pQuads [ uOldIndex + uAmount ], ( uNewIndex - uOldIndex ) * nQuadSize );
    }
    kdMemcpy ( &m_pQuads [ uNewIndex ], pTempQuads, uAmount * nQuadSize );

    kdFree ( pTempQuads );

    m_bDirty = KD_TRUE;
}
Exemple #2
0
static void __kdExtractBlock(const KDuint8 *src, KDint32 x, KDint32 y, KDint32 w, KDint32 h, KDuint8 *block)
{
    if((w - x >= 4) && (h - y >= 4))
    {
        /* Full Square shortcut */
        src += x * 4;
        src += y * w * 4;
        for(KDint i = 0; i < 4; ++i)
        {
            kdMemcpy(block, src, sizeof(KDuint8));
            block += 4;
            src += 4;
            kdMemcpy(block, src, sizeof(KDuint8));
            block += 4;
            src += 4;
            kdMemcpy(block, src, sizeof(KDuint8));
            block += 4;
            src += 4;
            kdMemcpy(block, src, sizeof(KDuint8));
            block += 4;
            src += (w * 4) - 12;
        }
        return;
    }

    KDint32 bw = kdMinVEN(w - x, 4);
    KDint32 bh = kdMinVEN(h - y, 4);

    const KDint32 rem[] =
        {
            0, 0, 0, 0,
            0, 1, 0, 1,
            0, 1, 2, 0,
            0, 1, 2, 3};

    for(KDint i = 0; i < 4; ++i)
    {
        KDint32 by = rem[(bh - 1) * 4 + i] + y;
        for(KDint j = 0; j < 4; ++j)
        {
            KDint32 bx = rem[(bw - 1) * 4 + j] + x;
            block[(i * 4 * 4) + (j * 4) + 0] = src[(by * (w * 4)) + (bx * 4) + 0];
            block[(i * 4 * 4) + (j * 4) + 1] = src[(by * (w * 4)) + (bx * 4) + 1];
            block[(i * 4 * 4) + (j * 4) + 2] = src[(by * (w * 4)) + (bx * 4) + 2];
            block[(i * 4 * 4) + (j * 4) + 3] = src[(by * (w * 4)) + (bx * 4) + 3];
        }
    }
}
KDvoid M3GImage2D::set ( KDint x, KDint y, KDint width, KDint height, const KDubyte* image )
{
	if ( m_bImmutable )
	{
		M3GException ( "IllegalStateException", __FUNCTION__, "This image is immutable." );
	}

	if ( x < 0 || y >= m_nWidth || y < 0 || y >= m_nHeight ) 
	{
		M3GException ( "IllegalArgumentException", __FUNCTION__, "Coordinate ( x, y ) is invalid, x = %d, y = %d.", x, y );
	}

	if ( width < 0 || width > m_nWidth || height < 0 || height > m_nHeight )
	{
		M3GException ( "IllegalArgumentException", __FUNCTION__, "Size ( width, height ) is invalid, width = %d, height = %d.", width, height );
	}

	if ( image == KD_NULL ) 
	{
		M3GException ( "NullPointerException", __FUNCTION__, "Image is NULL." );
	}

    KDint  nBpp = m3gGetBpp ( m_nFormat );
  
	for ( KDint  j = y; j < y + height; j++ )
	{
		kdMemcpy ( m_pImage + j * m_nWidth * nBpp + x * nBpp, (KDchar*) image + ( j - y ) * width * nBpp, width * nBpp );
	}
}
Exemple #4
0
kmVec4* kmVec4Assign(kmVec4* pOut, const kmVec4* pIn) {
    kdAssert(pOut != pIn);

    kdMemcpy(pOut, pIn, sizeof(float) * 4);

    return pOut;
}
KDint xmReadRowsTIFF ( KDFile* file, XMImage* image )
{	
	TIFFDecode*		decode = (TIFFDecode*) image->decode;
	kdMemcpy ( image->rows, &decode->pixels[ decode->row_count * image->width ], image->width * sizeof (KDuint32) );	
	decode->row_count++;
	return 0;
}
KDvoid M3GVertexArray::get ( KDint firstVertex, KDint numVertices, KDint valueSize, KDvoid* values ) const
{
    if ( values == KD_NULL )
	{
		M3GException ( "NullPointerException", __FUNCTION__ , "Values is NULL." ); 
    }

    if ( firstVertex < 0 || firstVertex >= m_nVertexCount )
	{
        M3GException ( "IllegalArgumentException", __FUNCTION__, "First vertex is invalid, firstVertex = %d.", firstVertex );
    }

    if ( numVertices < 0 || firstVertex + numVertices > m_nVertexCount ) 
	{
		M3GException ( "IllegalArgumentException", __FUNCTION__, "Number of vertices is Invalid, firstVertex = %d, numVertices = %d.", firstVertex, numVertices );
    }

    if ( m_nComponentSize != valueSize ) 
	{
		M3GException ( "IllegalStateException", __FUNCTION__ , "Component size of this vertex array is not %d byte, componentSize = %d.", m_nComponentSize, valueSize ); 
    }

    KDint  nOffset = firstVertex * m_nComponentCount * valueSize;
    KDint  nSize   = numVertices * m_nComponentCount * valueSize;

    kdMemcpy ( values, &m_pValues8 [ nOffset ], nSize );
}
KDbool Image::initWithRawData ( const KDubyte* pData, KDint32 nDataLen, KDint32 nWidth, KDint32 nHeight, KDint32 nBitsPerComponent, KDbool bPreMulti )
{
	KDbool		bRet = false;
	do
	{
		CC_BREAK_IF ( 0 == nWidth || 0 == nHeight );

		m_nHeight		= nHeight;
		m_nWidth		= nWidth;
		m_bPreMulti		= bPreMulti;
		m_bHasPremultipliedAlpha = bPreMulti;

		switch ( nBitsPerComponent )
		{
			case  8 :	m_eRenderFormat = Texture2D::PixelFormat::I8;			break;
			case 16 :	m_eRenderFormat = Texture2D::PixelFormat::AI88;			break;
			case 24 :	m_eRenderFormat = Texture2D::PixelFormat::RGB888;		break;
			case 32 :	m_eRenderFormat = Texture2D::PixelFormat::RGBA8888;		break;

			default :
				CCAssert ( false, "Not Support BitsPerComponent" );
		}

		// only RGBA8888 supported
		KDint			bytesPerComponent = nBitsPerComponent >> 3;
		m_nDataLen		= nHeight * nWidth * bytesPerComponent;
		m_pData			= new KDubyte [ m_nDataLen ];
		CC_BREAK_IF ( !m_pData );
		kdMemcpy ( m_pData, pData, m_nDataLen );

		bRet = true;
	} while ( 0 );

	return bRet;
}
KDint xmReadRowsETC ( KDFile* file, XMImage* image )
{
	ETCDecode*		decode = (ETCDecode*) image->decode;

	kdMemcpy ( image->rows, &decode->pixels[ decode->row_count * image->ptr_tile->stride ], image->ptr_tile->stride );	
	decode->row_count++;

	return 0;
}
// kdThreadOnce : Wrap initialization code so it is executed only once.
KD_API KDint KD_APIENTRY kdThreadOnce ( KDThreadOnce *once_control, KDvoid (* init_routine) ( KDvoid ) )
{			
	if ( !once_control->impl )
	{
		pthread_once_t  ponce = PTHREAD_ONCE_INIT; 

		once_control->impl = kdMalloc ( sizeof ( pthread_once_t ) );
		kdMemcpy ( once_control->impl, (const KDvoid *) &ponce, sizeof ( pthread_once_t ) );
	}
	
	return pthread_once ( (pthread_once_t *) once_control->impl, init_routine );	
} 
KDvoid M3GImage2D::init ( KDint format, KDint width, KDint height, KDubyte* pixels, KDubyte* palette )
{
	m_nFormat = format;
	m_nWidth  = width;
	m_nHeight = height;

    KDint  nBpp = m3gGetBpp ( format );
    KDint  nLength = height * width * nBpp;

	m_pImage = new KDubyte [ nLength ];

	if ( pixels )
	{
		m_bImmutable = KD_TRUE;

		if ( palette )
		{
			for ( KDint  y = 0; y < height; y++ )
			{
				for ( KDint  x = 0; x < width; x++ ) 
				{
					KDint  nIndex = pixels [ y * width + x ];
					kdMemcpy ( m_pImage + ( y * width + x ) * nBpp, (KDubyte*) palette + nIndex * nBpp, nBpp );
				}
			}
		}
		else
		{
			 kdMemcpy ( m_pImage, pixels, nLength );
		}
	}
	else
	{
		kdMemset ( m_pImage, 0, nLength );
	}
}
KDvoid M3GVertexArray::set ( KDint firstVertex, KDint numVertices, KDint valueSize, const KDvoid* values )
{
    if ( values == KD_NULL )
	{
		M3GException ( "NullPointerException", __FUNCTION__ , "Values is NULL." ); 
    }

    if ( numVertices < 0 ) 
	{
		M3GException ( "IllegalArgumentException", __FUNCTION__, "Number of vertices is invalid, numVertices = %d.", numVertices );
    }

    if ( firstVertex < 0 || firstVertex + numVertices > m_nVertexCount )
	{
        M3GException ( "IndexOutOfBoundsException", __FUNCTION__, "Vertex is out of bounds, [%d, %d] in [0, %d].", firstVertex, firstVertex + numVertices, m_nVertexCount );
    }

    if ( m_nComponentSize != valueSize ) 
	{
		M3GException ( "IllegalStateException", __FUNCTION__ , "Component size of this vertex array is not %d byte, componentSize = %d.", m_nComponentSize, valueSize ); 
    }

	if ( m_uID == 0 ) 
	{
		M3GException ( "OpenGLException", __FUNCTION__, "Vertex Buffre Object is not ready." );
	}

    KDint  nOffset = firstVertex * m_nComponentCount * valueSize;
    KDint  nSize   = numVertices * m_nComponentCount * valueSize;

    kdMemcpy ( &m_pValues8 [ nOffset ], values, nSize );

    glBindBuffer ( GL_ARRAY_BUFFER, m_uID );
    glBufferSubData ( GL_ARRAY_BUFFER, nOffset, nSize, &m_pValues8 [ nOffset ] );

	GLenum  nErr = glGetError ( );
    if ( nErr != GL_NO_ERROR )
	{
		M3GException ( "OpenGLException", __FUNCTION__, "Can't send to GPU, err = %d.", nErr );
    }
}
// Allocate a node from the pool. Grow the pool if necessary.
int32 b2DynamicTree::AllocateNode()
{
	// Expand the node pool as needed.
	if (m_freeList == b2_nullNode)
	{
		b2Assert(m_nodeCount == m_nodeCapacity);

		// The free list is empty. Rebuild a bigger pool.
		b2TreeNode* oldNodes = m_nodes;
		m_nodeCapacity *= 2;
		m_nodes = (b2TreeNode*)b2Alloc(m_nodeCapacity * sizeof(b2TreeNode));
		kdMemcpy(m_nodes, oldNodes, m_nodeCount * sizeof(b2TreeNode));
		b2Free(oldNodes);

		// Build a linked list for the free list. The parent
		// pointer becomes the "next" pointer.
		for (int32 i = m_nodeCount; i < m_nodeCapacity - 1; ++i)
		{
			m_nodes[i].next = i + 1;
			m_nodes[i].height = -1;
		}
		m_nodes[m_nodeCapacity-1].next = b2_nullNode;
		m_nodes[m_nodeCapacity-1].height = -1;
		m_freeList = m_nodeCount;
	}

	// Peel a node off the free list.
	int32 nodeId = m_freeList;
	m_freeList = m_nodes[nodeId].next;
	m_nodes[nodeId].parent = b2_nullNode;
	m_nodes[nodeId].child1 = b2_nullNode;
	m_nodes[nodeId].child2 = b2_nullNode;
	m_nodes[nodeId].height = 0;
	m_nodes[nodeId].userData = NULL;
	++m_nodeCount;
	return nodeId;
}
// kdThreadMutexCreate : Create a mutex.
KD_API KDThreadMutex* KD_APIENTRY kdThreadMutexCreate ( const KDvoid* mutexattr )
{
	pthread_mutex_t pmutex = PTHREAD_MUTEX_INITIALIZER;
	KDThreadMutex*  mutex  = 0;	
	KDint           ret	   = 0;	
	
	if ( ( mutex = (KDThreadMutex *) kdMalloc ( sizeof ( KDThreadMutex ) ) ) )
	{
		kdMemcpy ( &mutex->pmutex, &pmutex, sizeof ( pthread_mutex_t ) );

		if ( ( ret = pthread_mutex_init ( &mutex->pmutex, (const pthread_mutexattr_t *) mutexattr ) ) )
		{
			kdSetError ( ret == ENOMEM ? KD_ENOMEM : KD_EAGAIN );
			kdFree ( mutex );
			mutex = 0;
		}
	}
	else
	{
		kdSetError ( KD_ENOMEM );
	}	
	
	return mutex;	
}
// kdThreadCondCreate : Create a condition variable.
KD_API KDThreadCond* KD_APIENTRY kdThreadCondCreate ( const KDvoid* attr )
{
	pthread_cond_t  pcond = PTHREAD_COND_INITIALIZER;
	KDThreadCond*   cond  = 0;
	KDint           ret	  = 0;	

	if ( ( cond = (KDThreadCond *) kdMalloc ( sizeof ( KDThreadCond ) ) ) )
	{
		kdMemcpy ( &cond->pcond, &pcond, sizeof ( pthread_cond_t ) );

		if ( ( ret = pthread_cond_init ( &cond->pcond, (const pthread_condattr_t *) attr) ) )
		{
			kdSetError ( ret == ENOMEM ? KD_ENOMEM : KD_EAGAIN );
			kdFree ( cond );
			cond = 0;
		}
	}
	else
	{
		kdSetError ( KD_ENOMEM );
	}

	return cond;
}
Exemple #15
0
KD_API KDImageATX KD_APIENTRY kdDXTCompressBufferATX(const void *buffer, KDint32 width, KDint32 height, KDint32 comptype, KDint32 levels)
{
    _KDImageATX *image = (_KDImageATX *)kdMalloc(sizeof(_KDImageATX));
    if(image == KD_NULL)
    {
        kdSetError(KD_ENOMEM);
        return KD_NULL;
    }
    image->levels = levels;
    image->width = width;
    image->height = height;

    switch(comptype)
    {
        case(KD_DXTCOMP_TYPE_DXT1_ATX):
        {
            image->format = KD_IMAGE_FORMAT_DXT1_ATX;
            image->alpha = KD_FALSE;
            break;
        }
        case(KD_DXTCOMP_TYPE_DXT1A_ATX):
        {
            kdFree(image);
            kdSetError(KD_EINVAL);
            return KD_NULL;
        }
        case(KD_DXTCOMP_TYPE_DXT3_ATX):
        {
            kdFree(image);
            kdSetError(KD_EINVAL);
            return KD_NULL;
        }
        case(KD_DXTCOMP_TYPE_DXT5_ATX):
        {
            image->format = KD_IMAGE_FORMAT_DXT5_ATX;
            image->alpha = KD_TRUE;
            break;
        }
        default:
        {
            kdFree(image);
            kdSetError(KD_EINVAL);
            return KD_NULL;
        }
    }
    image->bpp = image->alpha ? 16 : 8;
    image->size = (KDsize)image->width * (KDsize)image->height * (KDsize)(image->bpp / 8);

    KDint _width = image->width;
    KDint _height = image->height;
    for(KDint i = 0; i < image->levels; i++)
    {
        _width >>= 1;
        _height >>= 1;
        image->size += (KDsize)_width * (KDsize)_height * (KDsize)(image->bpp / 8);
    }

    image->buffer = kdMalloc(image->size);
    if(image->buffer == KD_NULL)
    {
        kdFree(image);
        kdSetError(KD_ENOMEM);
        return KD_NULL;
    }

    _width = image->width;
    _height = image->height;
    KDint channels = (image->alpha ? 4 : 3);
    for(KDint i = 0; i <= image->levels; i++)
    {
        KDsize size = (KDsize)_width * (KDsize)_height * (KDsize)channels;
        if(size)
        {
            void *tmp = kdMalloc(size);
            if((_width == image->width) && (_height == image->height))
            {
                kdMemcpy(tmp, buffer, size);
            }
            else
            {
                stbir_resize_uint8(buffer, image->width, image->height, 0, tmp, _width, _height, 0, channels);
            }
            for(KDint y = 0; y < _height; y += 4)
            {
                for(KDint x = 0; x < _width; x += 4)
                {
                    KDuint8 block[64];
                    __kdExtractBlock(tmp, x, y, _width, _height, block);
                    stb_compress_dxt_block(image->buffer, block, image->alpha, STB_DXT_NORMAL);
                    image->buffer += image->bpp;
                }
            }
            kdFree(tmp);
        }
        _width >>= 1;
        _height >>= 1;
    }

    return image;
}
Exemple #16
0
KD_API KDImageATX KD_APIENTRY kdGetImageFromStreamATX(KDFile *file, KDint format, KDint flags)
{
    _KDImageATX *image = (_KDImageATX *)kdMalloc(sizeof(_KDImageATX));
    if(image == KD_NULL)
    {
        kdSetError(KD_ENOMEM);
        return KD_NULL;
    }
    image->levels = 0;
    image->bpp = 8;

    KDStat st;
    if(kdFstat(file, &st) == -1)
    {
        kdFree(image);
        kdSetError(KD_EIO);
        return KD_NULL;
    }

    void *filedata = kdMalloc((KDsize)st.st_size);
    if(filedata == KD_NULL)
    {
        kdFree(image);
        kdSetError(KD_ENOMEM);
        return KD_NULL;
    }
    if(kdFread(filedata, 1, (KDsize)st.st_size, file) != (KDsize)st.st_size)
    {
        kdFree(filedata);
        kdFree(image);
        kdSetError(KD_EIO);
        return KD_NULL;
    }
    if(kdFseek(file, 0, KD_SEEK_SET) == -1)
    {
        kdFree(filedata);
        kdFree(image);
        kdSetError(KD_EIO);
        return KD_NULL;
    }

    KDint channels = 0;
    image->format = format;
    switch(image->format)
    {
        case(KD_IMAGE_FORMAT_RGBA8888_ATX):
        {
            channels = 4;
            image->alpha = KD_TRUE;
            break;
        }
        case(KD_IMAGE_FORMAT_RGB888_ATX):
        {
            channels = 3;
            image->alpha = KD_FALSE;
            break;
        }
        case(KD_IMAGE_FORMAT_LUMALPHA88_ATX):
        {
            channels = 2;
            image->alpha = KD_TRUE;
            break;
        }
        case(KD_IMAGE_FORMAT_LUM8_ATX):
        {
            channels = 1;
            image->alpha = KD_FALSE;
            break;
        }
        case(KD_IMAGE_FORMAT_COMPRESSED_ATX):
        {
            /* TODO: Load compressed formats (do not decode) */
        }
        default:
        {
            kdFree(filedata);
            kdFree(image);
            kdSetError(KD_EINVAL);
            return KD_NULL;
        }
    }

    if(kdStrstrVEN(file->pathname, ".pvr"))
    {
        if(channels == 4)
        {
            /* PVR v2 only*/
            struct PVR_Texture_Header {
                KDuint dwHeaderSize;      /* size of the structure */
                KDuint dwHeight;          /* height of surface to be created */
                KDuint dwWidth;           /* width of input surface */
                KDuint dwMipMapCount;     /* number of mip-map levels requested */
                KDuint dwpfFlags;         /* pixel format flags */
                KDuint dwTextureDataSize; /* Total size in bytes */
                KDuint dwBitCount;        /* number of bits per pixel  */
                KDuint dwRBitMask;        /* mask for red bit */
                KDuint dwGBitMask;        /* mask for green bits */
                KDuint dwBBitMask;        /* mask for blue bits */
                KDuint dwAlphaBitMask;    /* mask for alpha channel */
                KDuint dwPVR;             /* magic number identifying pvr file */
                KDuint dwNumSurfs;        /* the number of surfaces present in the pvr */
            };
            struct PVR_Texture_Header header;
            kdMemcpy(&header, filedata, sizeof(KDuint) * 13);

            image->height = (KDint)header.dwHeight;
            image->width = (KDint)header.dwWidth;
            image->size = (KDsize)image->width * (KDsize)image->height * (KDsize)channels * sizeof(KDuint);
            image->buffer = kdMalloc(image->size);
            /* PVRCT2/4 RGB/RGBA compressed formats for now */
            __kdDecompressPVRTC((const KDuint8 *)filedata + header.dwHeaderSize, 0, image->width, image->height, image->buffer);
        }
    }
    else
    {
        if(flags == KD_IMAGE_FLAG_FLIP_X_ATX)
        {
            stbi_set_flip_vertically_on_load(1);
        }
        image->buffer = stbi_load_from_memory(filedata, (KDint)st.st_size, &image->width, &image->height, (KDint[]) {0}, channels);
        image->size = (KDsize)image->width * (KDsize)image->height * (KDsize)channels * sizeof(KDuint);
    }

    kdFree(filedata);
    if(image->buffer == KD_NULL)
    {
        kdLogMessagefKHR("%s.\n", stbi_failure_reason());
        kdFree(image);
        kdSetError(KD_EILSEQ);
        return KD_NULL;
    }
    return image;
}
KDvoid CCTextureAtlas::drawNumberOfQuads ( KDuint uNumber, KDuint uStart )
{
	if ( 0 == uNumber )
	{
		return;
	}

    ccGLBindTexture2D ( m_pTexture->getName ( ) );

#if CC_TEXTURE_ATLAS_USE_VAO

    //
    // Using VBO and VAO
    //

    // XXX: update is done in draw... perhaps it should be done in a timer
    if ( m_bDirty ) 
    {
        glBindBuffer    ( GL_ARRAY_BUFFER, m_pBuffersVBO[0] );
		
		// option 1: subdata
        // glBufferSubData ( GL_ARRAY_BUFFER, sizeof ( m_pQuads[0] ) * uStart, sizeof ( m_pQuads[0] ) * uNumber , &m_pQuads [ uStart ] );

		// option 2: data
        // glBufferData ( GL_ARRAY_BUFFER, sizeof ( m_pQuads[0] ) * ( n - uStart ), &m_pQuads [ uStart ], GL_DYNAMIC_DRAW );
		
		// option 3: orphaning + glMapBuffer
		glBufferData    ( GL_ARRAY_BUFFER, sizeof ( m_pQuads[0] ) * ( n - uStart ), KD_NULL, GL_DYNAMIC_DRAW );
		KDvoid*  pBuff = glMapBuffer ( GL_ARRAY_BUFFER, GL_WRITE_ONLY );
		kdMemcpy ( pBuff, m_pQuads, sizeof ( m_pQuads [ 0 ] ) * ( n - uStart ) );
		glUnmapBuffer ( GL_ARRAY_BUFFER );

        glBindBuffer    ( GL_ARRAY_BUFFER, 0 );

        m_bDirty = KD_FALSE;
    }

    ccGLBindVAO ( m_uVAOname );

#if CC_REBIND_INDICES_BUFFER
    glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, m_pBuffersVBO[1] );
#endif

    glDrawElements ( GL_TRIANGLES, (GLsizei) uNumber * 6, GL_UNSIGNED_SHORT, (GLvoid*) ( uStart * 6 * sizeof ( m_pIndices[0] ) ) );

#if CC_REBIND_INDICES_BUFFER
    glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, 0 );
#endif

//    glBindVertexArray ( 0 );

#else // CC_TEXTURE_ATLAS_USE_VAO

    //
    // Using VBO without VAO
    //

#define kQuadSize sizeof(m_pQuads[0].bl)
    glBindBuffer ( GL_ARRAY_BUFFER, m_pBuffersVBO[0] );

    // XXX: update is done in draw... perhaps it should be done in a timer
    if ( m_bDirty ) 
    {
		glBufferSubData ( GL_ARRAY_BUFFER, sizeof ( m_pQuads[0] ) * uStart, sizeof ( m_pQuads[0] ) * uNumber , &m_pQuads[ uStart ] );
        m_bDirty = KD_FALSE;
    }

	ccGLEnableVertexAttribs ( kCCVertexAttribFlag_PosColorTex );

    ccGLVertexAttribPointer ( kCCVertexAttrib_Position , 3, GL_FLOAT        , GL_FALSE, kQuadSize, (GLvoid*) offsetof ( ccV3F_C4B_T2F, vertices  ) );
    ccGLVertexAttribPointer ( kCCVertexAttrib_Color    , 4, GL_UNSIGNED_BYTE, GL_TRUE , kQuadSize, (GLvoid*) offsetof ( ccV3F_C4B_T2F, colors    ) );
    ccGLVertexAttribPointer ( kCCVertexAttrib_TexCoords, 2, GL_FLOAT        , GL_FALSE, kQuadSize, (GLvoid*) offsetof ( ccV3F_C4B_T2F, texCoords ) );

    glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, m_pBuffersVBO[1] );
    glDrawElements ( GL_TRIANGLES, (GLsizei) uNumber * 6, GL_UNSIGNED_SHORT, (GLvoid*) ( uStart * 6 * sizeof ( m_pIndices[0] ) ) );

    glBindBuffer ( GL_ARRAY_BUFFER, 0 );
    glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, 0 );

#endif // CC_TEXTURE_ATLAS_USE_VAO

    CC_INCREMENT_GL_DRAWS ( 1 );
    CHECK_GL_ERROR_DEBUG ( );
}