Ejemplo n.º 1
0
/*
==============
idVertexCache::Position

this will be a real pointer with virtual memory,
but it will be an int offset cast to a pointer with
ARB_vertex_buffer_object

The ARB_vertex_buffer_object will be bound
==============
*/
void *idVertexCache::Position(vertCache_t *buffer)
{
	if (!buffer || buffer->tag == TAG_FREE) {
		common->FatalError("idVertexCache::Position: bad vertCache_t");
	}

	// the ARB vertex object just uses an offset
	if (buffer->vbo) {
		if (r_showVertexCache.GetInteger() == 2) {
			if (buffer->tag == TAG_TEMP) {
				common->Printf("GL_ARRAY_BUFFER_ARB = %i + %i (%i bytes)\n", buffer->vbo, buffer->offset, buffer->size);
			} else {
				common->Printf("GL_ARRAY_BUFFER_ARB = %i (%i bytes)\n", buffer->vbo, buffer->size);
			}
		}

		if (buffer->indexBuffer) {
			qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffer->vbo);
		} else {
			qglBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->vbo);
		}

		return (void *)buffer->offset;
	}

	// virtual memory is a real pointer
	return (void *)((byte *)buffer->virtMem + buffer->offset);
}
Ejemplo n.º 2
0
/*
========================
idJointBuffer::AllocBufferObject
========================
*/
bool idJointBuffer::AllocBufferObject( const float * joints, int numAllocJoints ) {
	assert( apiObject == NULL );
	assert_16_byte_aligned( joints );

	if ( numAllocJoints <= 0 ) {
		idLib::Error( "idJointBuffer::AllocBufferObject: joints = %i", numAllocJoints );
	}

	numJoints = numAllocJoints;

	bool allocationFailed = false;

	const int numBytes = GetAllocedSize();

	GLuint buffer = 0;
	qglGenBuffersARB( 1, &buffer );
	qglBindBufferARB( GL_UNIFORM_BUFFER, buffer );
	qglBufferDataARB( GL_UNIFORM_BUFFER, numBytes, NULL, GL_STREAM_DRAW_ARB );
	qglBindBufferARB( GL_UNIFORM_BUFFER, 0);
	apiObject = reinterpret_cast< void * >( buffer );

	if ( r_showBuffers.GetBool() ) {
		idLib::Printf( "joint buffer alloc %p, api %p (%i joints)\n", this, GetAPIObject(), GetNumJoints() );
	}

	// copy the data
	if ( joints != NULL ) {
		Update( joints, numAllocJoints );
	}

	return !allocationFailed;
}
Ejemplo n.º 3
0
/*
** GL_SetDefaultState
*/
void GL_SetDefaultState( void )
{
    qglClearDepth( 1.0f );

    qglCullFace(GL_FRONT);

    qglColor4f (1,1,1,1);

    // initialize downstream texture unit if we're running
    // in a multitexture environment
    if ( qglActiveTextureARB ) {
        GL_SelectTexture( 1 );
        GL_TextureMode( r_textureMode->string );
        GL_TexEnv( GL_MODULATE );
        qglDisable( GL_TEXTURE_2D );
        GL_SelectTexture( 0 );
    }

    qglEnable(GL_TEXTURE_2D);
    GL_TextureMode( r_textureMode->string );
    GL_TexEnv( GL_MODULATE );

    //qglShadeModel( GL_SMOOTH );
    qglDepthFunc( GL_LEQUAL );

    //
    // make sure our GL state vector is set correctly
    //
    glState.glStateBits = GLS_DEPTHTEST_DISABLE | GLS_DEPTHMASK_TRUE;
    glState.storedGlState = 0;
    glState.faceCulling = CT_TWO_SIDED;
    glState.faceCullFront = qtrue;

    glState.currentProgram = 0;
    qglUseProgramObjectARB(0);

    if (glRefConfig.vertexArrayObject)
        qglBindVertexArrayARB(0);

    qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
    qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
    glState.currentVao = NULL;
    glState.vertexAttribsEnabled = 0;

    qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
    qglDepthMask( GL_TRUE );
    qglDisable( GL_DEPTH_TEST );
    qglEnable( GL_SCISSOR_TEST );
    qglDisable( GL_CULL_FACE );
    qglDisable( GL_BLEND );

    if (glRefConfig.seamlessCubeMap)
        qglEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);

    // GL_POLYGON_OFFSET_FILL will be glEnable()d when this is used
    qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value );

    qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f );	// FIXME: get color of sky
}
Ejemplo n.º 4
0
/*
** GL_SetDefaultState
*/
void GL_SetDefaultState( void )
{
	qglClearDepth( 1.0f );

	qglCullFace(GL_FRONT);

	qglColor4f (1,1,1,1);

	// initialize downstream texture unit if we're running
	// in a multitexture environment
	if ( qglActiveTextureARB ) {
		GL_SelectTexture( 1 );
		GL_TextureMode( r_textureMode->string );
		GL_TexEnv( GL_MODULATE );
		qglDisable( GL_TEXTURE_2D );
		GL_SelectTexture( 0 );
	}

	qglEnable(GL_TEXTURE_2D);
	GL_TextureMode( r_textureMode->string );
	GL_TexEnv( GL_MODULATE );

	//qglShadeModel( GL_SMOOTH );
	qglDepthFunc( GL_LEQUAL );

	//
	// make sure our GL state vector is set correctly
	//
	glState.glStateBits = GLS_DEPTHTEST_DISABLE | GLS_DEPTHMASK_TRUE;

	glState.vertexAttribsState = 0;
	glState.vertexAttribPointersSet = 0;
	glState.currentProgram = 0;
	qglUseProgramObjectARB(0);

	qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
	qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
	glState.currentVBO = NULL;
	glState.currentIBO = NULL;

	qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
	qglDepthMask( GL_TRUE );
	qglDisable( GL_DEPTH_TEST );
	qglEnable( GL_SCISSOR_TEST );
	qglDisable( GL_CULL_FACE );
	qglDisable( GL_BLEND );

	qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
	qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
	qglClearDepth( 1.0 );

	qglDrawBuffer( GL_FRONT );
	qglClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_ACCUM_BUFFER_BIT|GL_STENCIL_BUFFER_BIT );

	qglDrawBuffer( GL_BACK );
	qglClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_ACCUM_BUFFER_BIT|GL_STENCIL_BUFFER_BIT );
}
Ejemplo n.º 5
0
/*
============
R_CreateVBO
============
*/
VBO_t          *R_CreateVBO(const char *name, byte * vertexes, int vertexesSize, vboUsage_t usage)
{
	VBO_t          *vbo;
	int				glUsage;

	switch (usage)
	{
		case VBO_USAGE_STATIC:
			glUsage = GL_STATIC_DRAW_ARB;
			break;

		case VBO_USAGE_DYNAMIC:
			glUsage = GL_DYNAMIC_DRAW_ARB;
			break;

		default:
			Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage);
			return NULL;
	}

	if(strlen(name) >= MAX_QPATH)
	{
		ri.Error(ERR_DROP, "R_CreateVBO: \"%s\" is too long\n", name);
	}

	if ( tr.numVBOs == MAX_VBOS ) {
		ri.Error( ERR_DROP, "R_CreateVBO: MAX_VBOS hit\n");
	}

	// make sure the render thread is stopped
	R_SyncRenderThread();

	vbo = tr.vbos[tr.numVBOs] = ri.Hunk_Alloc(sizeof(*vbo), h_low);
	tr.numVBOs++;

	memset(vbo, 0, sizeof(*vbo));

	Q_strncpyz(vbo->name, name, sizeof(vbo->name));

	vbo->vertexesSize = vertexesSize;

	qglGenBuffersARB(1, &vbo->vertexesVBO);

	qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vertexesVBO);
	qglBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexesSize, vertexes, glUsage);

	qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);

	glState.currentVBO = NULL;

	GL_CheckErrors();

	return vbo;
}
Ejemplo n.º 6
0
/*
** GL_SetDefaultState
*/
void
GL_SetDefaultState(void)
{
	qglClearDepth(1.0f);

	qglCullFace(GL_FRONT);

	qglColor4f (1,1,1,1);

	/* initialize downstream texture unit if we're running
	 * in a multitexture environment */
	if(qglActiveTextureARB){
		GL_SelectTexture(1);
		GL_TextureMode(r_textureMode->string);
		GL_TexEnv(GL_MODULATE);
		qglDisable(GL_TEXTURE_2D);
		GL_SelectTexture(0);
	}

	qglEnable(GL_TEXTURE_2D);
	GL_TextureMode(r_textureMode->string);
	GL_TexEnv(GL_MODULATE);

	qglShadeModel(GL_SMOOTH);
	qglDepthFunc(GL_LEQUAL);

	/* the vertex array is always enabled, but the color and texture
	 * arrays are enabled and disabled around the compiled vertex array call */
	qglEnableClientState (GL_VERTEX_ARRAY);

	/*
	 * make sure our GL state vector is set correctly
	 *  */
	glState.glStateBits = GLS_DEPTHTEST_DISABLE | GLS_DEPTHMASK_TRUE;

	glState.vertexAttribsState = 0;
	glState.vertexAttribPointersSet = 0;
	glState.currentProgram = 0;
	qglUseProgramObjectARB(0);

	qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
	qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
	glState.currentVBO	= NULL;
	glState.currentIBO	= NULL;

	qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
	qglDepthMask(GL_TRUE);
	qglDisable(GL_DEPTH_TEST);
	qglEnable(GL_SCISSOR_TEST);
	qglDisable(GL_CULL_FACE);
	qglDisable(GL_BLEND);
}
Ejemplo n.º 7
0
/*
============
R_CreateIBO
============
*/
IBO_t          *R_CreateIBO(const char *name, byte * indexes, int indexesSize, vboUsage_t usage)
{
	IBO_t          *ibo;
	int				glUsage;

	switch (usage)
	{
		case VBO_USAGE_STATIC:
			glUsage = GL_STATIC_DRAW_ARB;
			break;

		case VBO_USAGE_DYNAMIC:
			glUsage = GL_DYNAMIC_DRAW_ARB;
			break;

		default:
			Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage);
			return NULL;
	}

	if(strlen(name) >= MAX_QPATH)
	{
		ri.Error(ERR_DROP, "R_CreateIBO: \"%s\" is too long", name);
	}

	if ( tr.numIBOs == MAX_IBOS ) {
		ri.Error( ERR_DROP, "R_CreateIBO: MAX_IBOS hit");
	}

	R_IssuePendingRenderCommands();

	ibo = tr.ibos[tr.numIBOs] = ri.Hunk_Alloc(sizeof(*ibo), h_low);
	tr.numIBOs++;

	Q_strncpyz(ibo->name, name, sizeof(ibo->name));

	ibo->indexesSize = indexesSize;

	qglGenBuffersARB(1, &ibo->indexesVBO);

	qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ibo->indexesVBO);
	qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexesSize, indexes, glUsage);

	qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);

	glState.currentIBO = NULL;

	GL_CheckErrors();

	return ibo;
}
Ejemplo n.º 8
0
/*
==============
idVertexCache::BeginBackEnd
==============
*/
void idVertexCache::BeginBackEnd() {
	mostUsedVertex = Max( mostUsedVertex, frameData[listNum].vertexMemUsed.GetValue() );
	mostUsedIndex = Max( mostUsedIndex, frameData[listNum].indexMemUsed.GetValue() );
	mostUsedJoint = Max( mostUsedJoint, frameData[listNum].jointMemUsed.GetValue() );

	if ( r_showVertexCache.GetBool() ) {
		idLib::Printf( "%08d: %d allocations, %dkB vertex, %dkB index, %kB joint : %dkB vertex, %dkB index, %kB joint\n", 
			currentFrame, frameData[listNum].allocations,
			frameData[listNum].vertexMemUsed.GetValue() / 1024,
			frameData[listNum].indexMemUsed.GetValue() / 1024,
			frameData[listNum].jointMemUsed.GetValue() / 1024,
			mostUsedVertex / 1024,
			mostUsedIndex / 1024,
			mostUsedJoint / 1024 );
	}

	// unmap the current frame so the GPU can read it
	const int startUnmap = Sys_Milliseconds();
	UnmapGeoBufferSet( frameData[listNum] );
	UnmapGeoBufferSet( staticData );
	const int endUnmap = Sys_Milliseconds();
	if ( endUnmap - startUnmap > 1 ) {
		idLib::PrintfIf( r_showVertexCacheTimings.GetBool(), "idVertexCache::unmap took %i msec\n", endUnmap - startUnmap );
	}
	drawListNum = listNum;

	// prepare the next frame for writing to by the CPU
	currentFrame++;

	listNum = currentFrame % VERTCACHE_NUM_FRAMES;
	const int startMap = Sys_Milliseconds();
	MapGeoBufferSet( frameData[listNum] );
	const int endMap = Sys_Milliseconds();
	if ( endMap - startMap > 1 ) {
		idLib::PrintfIf( r_showVertexCacheTimings.GetBool(), "idVertexCache::map took %i msec\n", endMap - startMap );
	}

	ClearGeoBufferSet( frameData[listNum] );


#if 0
	const int startBind = Sys_Milliseconds();
	qglBindBufferARB( GL_ARRAY_BUFFER_ARB, (GLuint)frameData[drawListNum].vertexBuffer.GetAPIObject() );
	qglBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, (GLuint)frameData[drawListNum].indexBuffer.GetAPIObject() );
	const int endBind = Sys_Milliseconds();
	if ( endBind - startBind > 1 ) {
		idLib::Printf( "idVertexCache::bind took %i msec\n", endBind - startBind );
	}
#endif

}
Ejemplo n.º 9
0
void Gui_FillCrosshairBuffer()
{
    GLfloat x = (GLfloat)screen_info.w / 2.0f;
    GLfloat y = (GLfloat)screen_info.h / 2.0f;
    GLfloat *v, crosshairArray[32];
    const GLfloat size = 8.0f;
    const GLfloat color[4] = {1.0f, 0.0f, 0.0f, 1.0f};

    v = crosshairArray;
   *v++ = x; *v++ = y - size;
    vec4_copy(v, color);
    v += 4;
   *v++ = 0.0; *v++ = 0.0;

   *v++ = x; *v++ = y + size;
    vec4_copy(v, color);
    v += 4;
   *v++ = 0.0; *v++ = 0.0;

   *v++ = x - size; *v++ = y;
    vec4_copy(v, color);
    v += 4;
   *v++ = 0.0; *v++ = 0.0;

   *v++ = x + size; *v++ = y;
    vec4_copy(v, color);
    v += 4;
   *v++ = 0.0; *v++ = 0.0;

    // copy vertices into GL buffer
    qglBindBufferARB(GL_ARRAY_BUFFER, crosshairBuffer);
    qglBufferDataARB(GL_ARRAY_BUFFER, sizeof(GLfloat[32]), crosshairArray, GL_STATIC_DRAW);
}
Ejemplo n.º 10
0
/*
========================
idIndexBuffer::MapBuffer
========================
*/
void * idIndexBuffer::MapBuffer( bufferMapType_t mapType ) const {

	assert( apiObject != NULL );
	assert( IsMapped() == false );

	void * buffer = NULL;

	GLuint bufferObject = reinterpret_cast< GLuint >( apiObject );
	qglBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, bufferObject );
	if ( mapType == BM_READ ) {
		//buffer = qglMapBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB );
		buffer = qglMapBufferRange( GL_ELEMENT_ARRAY_BUFFER_ARB, 0, GetAllocedSize(), GL_MAP_READ_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT );
		if ( buffer != NULL ) {
			buffer = (byte *)buffer + GetOffset();
		}
	} else if ( mapType == BM_WRITE ) {
		//buffer = qglMapBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB );
		buffer = qglMapBufferRange( GL_ELEMENT_ARRAY_BUFFER_ARB, 0, GetAllocedSize(), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT );
		if ( buffer != NULL ) {
			buffer = (byte *)buffer + GetOffset();
		}
		assert( IsWriteCombined( buffer ) );
	} else {
		assert( false );
	}

	SetMapped();

	if ( buffer == NULL ) {
		idLib::FatalError( "idIndexBuffer::MapBuffer: failed" );
	}
	return buffer;
}
Ejemplo n.º 11
0
/*
============
R_BindVBO
============
*/
void R_BindVBO(VBO_t * vbo)
{
	if(!vbo)
	{
		//R_BindNullVBO();
		ri.Error(ERR_DROP, "R_BindNullVBO: NULL vbo");
		return;
	}

	if(r_logFile->integer)
	{
		// don't just call LogComment, or we will get a call to va() every frame!
		GLimp_LogComment(va("--- R_BindVBO( %s ) ---\n", vbo->name));
	}

	if(glState.currentVBO != vbo)
	{
		glState.currentVBO = vbo;
		glState.vertexAttribPointersSet = 0;

		glState.vertexAttribsInterpolation = 0;
		glState.vertexAttribsOldFrame = 0;
		glState.vertexAttribsNewFrame = 0;
		glState.vertexAnimation = qfalse;

		qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vertexesVBO);

		backEnd.pc.c_vboVertexBuffers++;
	}
}
Ejemplo n.º 12
0
void Gui_FillBackgroundBuffer()
{
    GLfloat x0 = 0.0f;
    GLfloat y0 = 0.0f;
    GLfloat x1 = screen_info.w;
    GLfloat y1 = screen_info.h;
    GLfloat *v, backgroundArray[32];
    GLfloat color[4] = {0.0f, 0.0f, 0.0f, 0.5f};

    v = backgroundArray;
   *v++ = x0; *v++ = y0;
    vec4_copy(v, color);
    v += 4;
   *v++ = 0.0f; *v++ = 0.0f;

   *v++ = x1; *v++ = y0;
    vec4_copy(v, color);
    v += 4;
   *v++ = 1.0f; *v++ = 0.0f;

   *v++ = x1; *v++ = y1;
    vec4_copy(v, color);
    v += 4;
   *v++ = 1.0f; *v++ = 1.0f;

   *v++ = x0; *v++ = y1;
    vec4_copy(v, color);
    v += 4;
   *v++ = 0.0f; *v++ = 1.0f;

    qglBindBufferARB(GL_ARRAY_BUFFER, backgroundBuffer);
    qglBufferDataARB(GL_ARRAY_BUFFER, sizeof(GLfloat[32]), backgroundArray, GL_STATIC_DRAW);
}
Ejemplo n.º 13
0
/*
========================
idJointBuffer::MapBuffer
========================
*/
float * idJointBuffer::MapBuffer( bufferMapType_t mapType ) const {
	assert( IsMapped() == false );
	assert( mapType == BM_WRITE );
	assert( apiObject != NULL );

	int numBytes = GetAllocedSize();

	void * buffer = NULL;

	qglBindBufferARB( GL_UNIFORM_BUFFER, reinterpret_cast< GLuint >( apiObject ) );
	numBytes = numBytes;
	assert( GetOffset() == 0 );
	//buffer = qglMapBufferARB( GL_UNIFORM_BUFFER, GL_WRITE_ONLY_ARB );
	buffer = qglMapBufferRange( GL_UNIFORM_BUFFER, 0, GetAllocedSize(), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT );
	if ( buffer != NULL ) {
		buffer = (byte *)buffer + GetOffset();
	}

	SetMapped();

	if ( buffer == NULL ) {
		idLib::FatalError( "idJointBuffer::MapBuffer: failed" );
	}
	return (float *) buffer;
}
Ejemplo n.º 14
0
/*
========================
idJointBuffer::FreeBufferObject
========================
*/
void idJointBuffer::FreeBufferObject() {
	if ( IsMapped() ) {
		UnmapBuffer();
	}

	// if this is a sub-allocation inside a larger buffer, don't actually free anything.
	if ( OwnsBuffer() == false ) {
		ClearWithoutFreeing();
		return;
	}

	if ( apiObject == NULL ) {
		return;
	}

	if ( r_showBuffers.GetBool() ) {
		idLib::Printf( "joint buffer free %p, api %p (%i joints)\n", this, GetAPIObject(), GetNumJoints() );
	}

	GLuint buffer = reinterpret_cast< GLuint > ( apiObject );
	qglBindBufferARB( GL_UNIFORM_BUFFER, 0 );
	qglDeleteBuffersARB( 1, & buffer );

	ClearWithoutFreeing();
}
Ejemplo n.º 15
0
/*
* RB_BindElementArrayBuffer
*/
void RB_BindElementArrayBuffer( int buffer )
{
    if( buffer != rb.gl.currentElemArrayVBO )
    {
        qglBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, buffer );
        rb.gl.currentElemArrayVBO = buffer;
    }
}
Ejemplo n.º 16
0
/*
* RB_BindArrayBuffer
*/
void RB_BindArrayBuffer( int buffer )
{
    if( buffer != rb.gl.currentArrayVBO )
    {
        qglBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer );
        rb.gl.currentArrayVBO = buffer;
        rb.gl.lastVAttribs = 0;
    }
}
Ejemplo n.º 17
0
void Gui_DrawCrosshair()
{
    // TBI: actual ingame crosshair
    BindWhiteTexture();
    qglBindBufferARB(GL_ARRAY_BUFFER_ARB, crosshairBuffer);
    qglVertexPointer(2, GL_FLOAT, 8 * sizeof(GLfloat), (void *)0);
    qglColorPointer(4, GL_FLOAT, 8 * sizeof(GLfloat), (void *)sizeof(GLfloat[2]));
    qglTexCoordPointer(2, GL_FLOAT, 8 * sizeof(GLfloat), (void *)sizeof(GLfloat[6]));
    qglDrawArrays(GL_LINES, 0, 4);
}
Ejemplo n.º 18
0
/*
============
R_BindNullIBO
============
*/
void R_BindNullIBO(void)
{
	GLimp_LogComment("--- R_BindNullIBO ---\n");

	if(glState.currentIBO)
	{
		qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
		glState.currentIBO = NULL;
		glState.vertexAttribPointersSet = 0;
	}
}
Ejemplo n.º 19
0
/*
========================
idJointBuffer::UnmapBuffer
========================
*/
void idJointBuffer::UnmapBuffer() const {
	assert( apiObject != NULL );
	assert( IsMapped() );

	qglBindBufferARB( GL_UNIFORM_BUFFER, reinterpret_cast< GLuint >( apiObject ) );
	if ( !qglUnmapBufferARB( GL_UNIFORM_BUFFER ) ) {
		idLib::Printf( "idJointBuffer::UnmapBuffer failed\n" );
	}

	SetUnmapped();
}
Ejemplo n.º 20
0
/*
============
R_BindNullVBO
============
*/
void R_BindNullVBO(void)
{
	GLimp_LogComment("--- R_BindNullVBO ---\n");

	if(glState.currentVBO)
	{
		qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
		glState.currentVBO = NULL;
	}

	GL_CheckErrors();
}
Ejemplo n.º 21
0
/*
========================
idIndexBuffer::UnmapBuffer
========================
*/
void idIndexBuffer::UnmapBuffer() const {
	assert( apiObject != NULL );
	assert( IsMapped() );

	GLuint bufferObject = reinterpret_cast< GLuint >( apiObject );
	qglBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, bufferObject );
	if ( !qglUnmapBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB ) ) {
		idLib::Printf( "idIndexBuffer::UnmapBuffer failed\n" );
	}

	SetUnmapped();
}
Ejemplo n.º 22
0
/*
========================
idJointBuffer::Update
========================
*/
void idJointBuffer::Update( const float * joints, int numUpdateJoints ) const {
	assert( apiObject != NULL );
	assert( IsMapped() == false );
	assert_16_byte_aligned( joints );
	assert( ( GetOffset() & 15 ) == 0 );

	if ( numUpdateJoints > numJoints ) {
		idLib::FatalError( "idJointBuffer::Update: size overrun, %i > %i\n", numUpdateJoints, numJoints );
	}

	const int numBytes = numUpdateJoints * 3 * 4 * sizeof( float );

	qglBindBufferARB( GL_UNIFORM_BUFFER, reinterpret_cast< GLuint >( apiObject ) );
	qglBufferSubDataARB( GL_UNIFORM_BUFFER, GetOffset(), (GLsizeiptrARB)numBytes, joints );
}
Ejemplo n.º 23
0
/*
* R_ReleaseMeshVBO
*/
void R_ReleaseMeshVBO( mesh_vbo_t *vbo )
{
	GLuint vbo_id;

	assert( vbo != NULL );

	qglBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
	qglBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 );

	if( vbo->vertexId ) {
		vbo_id = vbo->vertexId;
		qglDeleteBuffersARB( 1, &vbo_id );
	}

	if( vbo->elemId ) {
		vbo_id = vbo->elemId;
		qglDeleteBuffersARB( 1, &vbo_id );
	}

	if( vbo->index >= 1 && vbo->index <= MAX_MESH_VERTEX_BUFFER_OBJECTS ) {
		vbohandle_t *vboh = &r_vbohandles[vbo->index - 1];

		// remove from linked active list
		vboh->prev->next = vboh->next;
		vboh->next->prev = vboh->prev;

		// insert into linked free list
		vboh->next = r_free_vbohandles;
		r_free_vbohandles = vboh;

		r_num_active_vbos--;
	}

	memset( vbo, 0, sizeof( *vbo ) );
	vbo->tag = VBO_TAG_NONE;
}
Ejemplo n.º 24
0
/*
========================
idIndexBuffer::AllocBufferObject
========================
*/
bool idIndexBuffer::AllocBufferObject( const void * data, int allocSize ) {
	assert( apiObject == NULL );
	assert_16_byte_aligned( data );

	if ( allocSize <= 0 ) {
		idLib::Error( "idIndexBuffer::AllocBufferObject: allocSize = %i", allocSize );
	}

	size = allocSize;

	bool allocationFailed = false;

	int numBytes = GetAllocedSize();


	// clear out any previous error
	qglGetError();

	GLuint bufferObject = 0xFFFF;
	qglGenBuffersARB( 1, & bufferObject );
	if ( bufferObject == 0xFFFF ) {
		GLenum error = qglGetError();
		idLib::FatalError( "idIndexBuffer::AllocBufferObject: failed - GL_Error %d", error );
	}
	qglBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, bufferObject );

	// these are rewritten every frame
	qglBufferDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB, numBytes, NULL, bufferUsage );
	apiObject = reinterpret_cast< void * >( bufferObject );

	GLenum err = qglGetError();
	if ( err == GL_OUT_OF_MEMORY ) {
		idLib::Warning( "idIndexBuffer:AllocBufferObject: allocation failed" );
		allocationFailed = true;
	}


	if ( r_showBuffers.GetBool() ) {
		idLib::Printf( "index buffer alloc %p, api %p (%i bytes)\n", this, GetAPIObject(), GetSize() );
	}

	// copy the data
	if ( data != NULL ) {
		Update( data, allocSize );
	}

	return !allocationFailed;
}
Ejemplo n.º 25
0
/*
==============
idVertexCache::ActuallyFree
==============
*/
void idVertexCache::ActuallyFree(vertCache_t *block)
{
	if (!block) {
		common->Error("idVertexCache Free: NULL pointer");
	}

	if (block->user) {
		// let the owner know we have purged it
		*block->user = NULL;
		block->user = NULL;
	}

	// temp blocks are in a shared space that won't be freed
	if (block->tag != TAG_TEMP) {
		staticAllocTotal -= block->size;
		staticCountTotal--;

		if (block->vbo) {
#if 0		// this isn't really necessary, it will be reused soon enough
			// filling with zero length data is the equivalent of freeing
			qglBindBufferARB(GL_ARRAY_BUFFER_ARB, block->vbo);
			qglBufferDataARB(GL_ARRAY_BUFFER_ARB, 0, 0, GL_DYNAMIC_DRAW_ARB);
#endif
		} else if (block->virtMem) {
			Mem_Free(block->virtMem);
			block->virtMem = NULL;
		}
	}

	block->tag = TAG_FREE;		// mark as free

	// unlink stick it back on the free list
	block->next->prev = block->prev;
	block->prev->next = block->next;

#if 1
	// stick it on the front of the free list so it will be reused immediately
	block->next = freeStaticHeaders.next;
	block->prev = &freeStaticHeaders;
#else
	// stick it on the back of the free list so it won't be reused soon (just for debugging)
	block->next = &freeStaticHeaders;
	block->prev = freeStaticHeaders.prev;
#endif

	block->next->prev = block;
	block->prev->next = block;
}
Ejemplo n.º 26
0
/*
========================
idVertexBuffer::Update
========================
*/
void idVertexBuffer::Update( const void * data, int updateSize ) const {
	assert( apiObject != NULL );
	assert( IsMapped() == false );
	assert_16_byte_aligned( data );
	assert( ( GetOffset() & 15 ) == 0 );

	if ( updateSize > size ) {
		idLib::FatalError( "idVertexBuffer::Update: size overrun, %i > %i\n", updateSize, GetSize() );
	}

	int numBytes = ( updateSize + 15 ) & ~15;

	GLuint bufferObject = reinterpret_cast< GLuint >( apiObject );
	qglBindBufferARB( GL_ARRAY_BUFFER_ARB, bufferObject );
	qglBufferSubDataARB( GL_ARRAY_BUFFER_ARB, GetOffset(), (GLsizeiptrARB)numBytes, data );
/*
	void * buffer = MapBuffer( BM_WRITE );
	CopyBuffer( (byte *)buffer + GetOffset(), (byte *)data, numBytes );
	UnmapBuffer();
*/
}
Ejemplo n.º 27
0
/*
============
R_BindIBO
============
*/
void R_BindIBO(IBO_t * ibo)
{
	if(!ibo)
	{
		//R_BindNullIBO();
		ri.Error(ERR_DROP, "R_BindIBO: NULL ibo");
		return;
	}

	if(r_logFile->integer)
	{
		// don't just call LogComment, or we will get a call to va() every frame!
		GLimp_LogComment(va("--- R_BindIBO( %s ) ---\n", ibo->name));
	}

	if(glState.currentIBO != ibo)
	{
		qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ibo->indexesVBO);

		glState.currentIBO = ibo;

		backEnd.pc.c_vboIndexBuffers++;
	}
}
Ejemplo n.º 28
0
/*
============
R_CreateVBO2
============
*/
VBO_t          *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * verts, unsigned int stateBits, vboUsage_t usage)
{
	VBO_t          *vbo;
	int             i;

	byte           *data;
	int             dataSize;
	int             dataOfs;

	int				glUsage;

	switch (usage)
	{
		case VBO_USAGE_STATIC:
			glUsage = GL_STATIC_DRAW_ARB;
			break;

		case VBO_USAGE_DYNAMIC:
			glUsage = GL_DYNAMIC_DRAW_ARB;
			break;

		default:
			Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage);
			return NULL;
	}

	if(!numVertexes)
		return NULL;

	if(strlen(name) >= MAX_QPATH)
	{
		ri.Error(ERR_DROP, "R_CreateVBO2: \"%s\" is too long", name);
	}

	if ( tr.numVBOs == MAX_VBOS ) {
		ri.Error( ERR_DROP, "R_CreateVBO2: MAX_VBOS hit");
	}

	R_IssuePendingRenderCommands();

	vbo = tr.vbos[tr.numVBOs] = ri.Hunk_Alloc(sizeof(*vbo), h_low);
	tr.numVBOs++;

	memset(vbo, 0, sizeof(*vbo));

	Q_strncpyz(vbo->name, name, sizeof(vbo->name));

	if (usage == VBO_USAGE_STATIC)
	{
		// since these vertex attributes are never altered, interleave them
		vbo->ofs_xyz = 0;
		dataSize = sizeof(verts[0].xyz);

		if(stateBits & ATTR_NORMAL)
		{
			vbo->ofs_normal = dataSize;
			dataSize += sizeof(uint8_t) * 4;
		}

#ifdef USE_VERT_TANGENT_SPACE
		if(stateBits & ATTR_TANGENT)
		{
			vbo->ofs_tangent = dataSize;
			dataSize += sizeof(uint8_t) * 4;
		}
#endif

		if(stateBits & ATTR_TEXCOORD)
		{
			vbo->ofs_st = dataSize;
			dataSize += sizeof(verts[0].st);
		}

		if(stateBits & ATTR_LIGHTCOORD)
		{
			vbo->ofs_lightmap = dataSize;
			dataSize += sizeof(verts[0].lightmap);
		}

		if(stateBits & ATTR_COLOR)
		{
			vbo->ofs_vertexcolor = dataSize;
			dataSize += sizeof(verts[0].vertexColors);
		}

		if(stateBits & ATTR_LIGHTDIRECTION)
		{
			vbo->ofs_lightdir = dataSize;
			dataSize += sizeof(verts[0].lightdir);
		}

		vbo->stride_xyz         = dataSize;
		vbo->stride_normal      = dataSize;
#ifdef USE_VERT_TANGENT_SPACE
		vbo->stride_tangent     = dataSize;
#endif
		vbo->stride_st          = dataSize;
		vbo->stride_lightmap    = dataSize;
		vbo->stride_vertexcolor = dataSize;
		vbo->stride_lightdir    = dataSize;

		// create VBO
		dataSize *= numVertexes;
		data = ri.Hunk_AllocateTempMemory(dataSize);
		dataOfs = 0;

		//ri.Printf(PRINT_ALL, "CreateVBO: %d, %d %d %d %d %d, %d %d %d %d %d\n", dataSize, vbo->ofs_xyz, vbo->ofs_normal, vbo->ofs_st, vbo->ofs_lightmap, vbo->ofs_vertexcolor,
			//vbo->stride_xyz, vbo->stride_normal, vbo->stride_st, vbo->stride_lightmap, vbo->stride_vertexcolor);

		for (i = 0; i < numVertexes; i++)
		{
			// xyz
			memcpy(data + dataOfs, &verts[i].xyz, sizeof(verts[i].xyz));
			dataOfs += sizeof(verts[i].xyz);

			// normal
			if(stateBits & ATTR_NORMAL)
			{
				uint8_t *p = data + dataOfs;

				p[0] = (uint8_t)(verts[i].normal[0] * 127.5f + 128.0f);
				p[1] = (uint8_t)(verts[i].normal[1] * 127.5f + 128.0f);
				p[2] = (uint8_t)(verts[i].normal[2] * 127.5f + 128.0f);
				p[3] = 0;

				dataOfs += sizeof(uint8_t) * 4;
			}

#ifdef USE_VERT_TANGENT_SPACE
			// tangent
			if(stateBits & ATTR_TANGENT)
			{
				vec3_t nxt;
				uint8_t *p = data + dataOfs;

				CrossProduct(verts[i].normal, verts[i].tangent, nxt);

				p[0] = (uint8_t)(verts[i].tangent[0] * 127.5f + 128.0f);
				p[1] = (uint8_t)(verts[i].tangent[1] * 127.5f + 128.0f);
				p[2] = (uint8_t)(verts[i].tangent[2] * 127.5f + 128.0f);				
				p[3] = (uint8_t)(verts[i].tangent[3] * 127.5f + 128.0f);

				dataOfs += sizeof(uint8_t) * 4;
			}
#endif

			// vertex texcoords
			if(stateBits & ATTR_TEXCOORD)
			{
				memcpy(data + dataOfs, &verts[i].st, sizeof(verts[i].st));
				dataOfs += sizeof(verts[i].st);
			}

			// feed vertex lightmap texcoords
			if(stateBits & ATTR_LIGHTCOORD)
			{
				memcpy(data + dataOfs, &verts[i].lightmap, sizeof(verts[i].lightmap));
				dataOfs += sizeof(verts[i].lightmap);
			}

			// feed vertex colors
			if(stateBits & ATTR_COLOR)
			{
				memcpy(data + dataOfs, &verts[i].vertexColors, sizeof(verts[i].vertexColors));
				dataOfs += sizeof(verts[i].vertexColors);
			}

			// feed vertex light directions
			if(stateBits & ATTR_LIGHTDIRECTION)
			{
				memcpy(data + dataOfs, &verts[i].lightdir, sizeof(verts[i].lightdir));
				dataOfs += sizeof(verts[i].lightdir);
			}
		}
	}
	else
	{
		// since these vertex attributes may be changed, put them in flat arrays
		dataSize = sizeof(verts[0].xyz);

		if(stateBits & ATTR_NORMAL)
		{
			dataSize += sizeof(uint8_t) * 4;
		}

#ifdef USE_VERT_TANGENT_SPACE
		if(stateBits & ATTR_TANGENT)
		{
			dataSize += sizeof(uint8_t) * 4;
		}
#endif

		if(stateBits & ATTR_TEXCOORD)
		{
			dataSize += sizeof(verts[0].st);
		}

		if(stateBits & ATTR_LIGHTCOORD)
		{
			dataSize += sizeof(verts[0].lightmap);
		}

		if(stateBits & ATTR_COLOR)
		{
			dataSize += sizeof(verts[0].vertexColors);
		}

		if(stateBits & ATTR_LIGHTDIRECTION)
		{
			dataSize += sizeof(verts[0].lightdir);
		}

		// create VBO
		dataSize *= numVertexes;
		data = ri.Hunk_AllocateTempMemory(dataSize);
		dataOfs = 0;

		vbo->ofs_xyz            = 0;
		vbo->ofs_normal         = 0;
#ifdef USE_VERT_TANGENT_SPACE
		vbo->ofs_tangent        = 0;
#endif
		vbo->ofs_st             = 0;
		vbo->ofs_lightmap       = 0;
		vbo->ofs_vertexcolor    = 0;
		vbo->ofs_lightdir       = 0;

		vbo->stride_xyz         = sizeof(verts[0].xyz);
		vbo->stride_normal      = sizeof(uint8_t) * 4;
#ifdef USE_VERT_TANGENT_SPACE
		vbo->stride_tangent     = sizeof(uint8_t) * 4;
#endif
		vbo->stride_vertexcolor = sizeof(verts[0].vertexColors);
		vbo->stride_st          = sizeof(verts[0].st);
		vbo->stride_lightmap    = sizeof(verts[0].lightmap);
		vbo->stride_lightdir    = sizeof(verts[0].lightdir);

		//ri.Printf(PRINT_ALL, "2CreateVBO: %d, %d %d %d %d %d, %d %d %d %d %d\n", dataSize, vbo->ofs_xyz, vbo->ofs_normal, vbo->ofs_st, vbo->ofs_lightmap, vbo->ofs_vertexcolor,
			//vbo->stride_xyz, vbo->stride_normal, vbo->stride_st, vbo->stride_lightmap, vbo->stride_vertexcolor);

		// xyz
		for (i = 0; i < numVertexes; i++)
		{
			memcpy(data + dataOfs, &verts[i].xyz, sizeof(verts[i].xyz));
			dataOfs += sizeof(verts[i].xyz);
		}

		// normal
		if(stateBits & ATTR_NORMAL)
		{
			vbo->ofs_normal = dataOfs;
			for (i = 0; i < numVertexes; i++)
			{
				uint8_t *p = data + dataOfs;

				p[0] = (uint8_t)(verts[i].normal[0] * 127.5f + 128.0f);
				p[1] = (uint8_t)(verts[i].normal[1] * 127.5f + 128.0f);
				p[2] = (uint8_t)(verts[i].normal[2] * 127.5f + 128.0f);
				p[3] = 0;

				dataOfs += sizeof(uint8_t) * 4;
			}
		}

#ifdef USE_VERT_TANGENT_SPACE
		// tangent
		if(stateBits & ATTR_TANGENT)
		{
			vbo->ofs_tangent = dataOfs;
			for (i = 0; i < numVertexes; i++)
			{
				vec3_t nxt;
				uint8_t *p = data + dataOfs;

				CrossProduct(verts[i].normal, verts[i].tangent, nxt);

				p[0] = (uint8_t)(verts[i].tangent[0] * 127.5f + 128.0f);
				p[1] = (uint8_t)(verts[i].tangent[1] * 127.5f + 128.0f);
				p[2] = (uint8_t)(verts[i].tangent[2] * 127.5f + 128.0f);
				p[3] = (uint8_t)(verts[i].tangent[3] * 127.5f + 128.0f);

				dataOfs += sizeof(uint8_t) * 4;
			}
		}
#endif

		// vertex texcoords
		if(stateBits & ATTR_TEXCOORD)
		{
			vbo->ofs_st = dataOfs;
			for (i = 0; i < numVertexes; i++)
			{
				memcpy(data + dataOfs, &verts[i].st, sizeof(verts[i].st));
				dataOfs += sizeof(verts[i].st);
			}
		}

		// feed vertex lightmap texcoords
		if(stateBits & ATTR_LIGHTCOORD)
		{
			vbo->ofs_lightmap = dataOfs;
			for (i = 0; i < numVertexes; i++)
			{
				memcpy(data + dataOfs, &verts[i].lightmap, sizeof(verts[i].lightmap));
				dataOfs += sizeof(verts[i].lightmap);
			}
		}

		// feed vertex colors
		if(stateBits & ATTR_COLOR)
		{
			vbo->ofs_vertexcolor = dataOfs;
			for (i = 0; i < numVertexes; i++)
			{
				memcpy(data + dataOfs, &verts[i].vertexColors, sizeof(verts[i].vertexColors));
				dataOfs += sizeof(verts[i].vertexColors);
			}
		}

		// feed vertex lightdirs
		if(stateBits & ATTR_LIGHTDIRECTION)
		{
			vbo->ofs_lightdir = dataOfs;
			for (i = 0; i < numVertexes; i++)
			{
				memcpy(data + dataOfs, &verts[i].lightdir, sizeof(verts[i].lightdir));
				dataOfs += sizeof(verts[i].lightdir);
			}
		}
	}


	vbo->vertexesSize = dataSize;

	qglGenBuffersARB(1, &vbo->vertexesVBO);

	qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vertexesVBO);
	qglBufferDataARB(GL_ARRAY_BUFFER_ARB, dataSize, data, glUsage);

	qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);

	glState.currentVBO = NULL;

	GL_CheckErrors();

	ri.Hunk_FreeTempMemory(data);

	return vbo;
}
Ejemplo n.º 29
0
/**
 * Draws simple colored rectangle with given parameters.
 */
void Gui_DrawRect(const GLfloat &x, const GLfloat &y,
                  const GLfloat &width, const GLfloat &height,
                  const float colorUpperLeft[], const float colorUpperRight[],
                  const float colorLowerLeft[], const float colorLowerRight[],
                  const int &blendMode,
                  const GLuint texture)
{
    switch(blendMode)
    {
        case BM_HIDE:
            return;
        case BM_MULTIPLY:
            qglBlendFunc(GL_SRC_ALPHA, GL_ONE);
            break;
        case BM_SIMPLE_SHADE:
            qglBlendFunc(GL_ONE_MINUS_SRC_COLOR, GL_ONE_MINUS_SRC_ALPHA);
            break;
        case BM_SCREEN:
            qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
            break;
        default:
        case BM_OPAQUE:
            qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
            break;
    };

    GLfloat x0 = x;
    GLfloat y0 = y + height;
    GLfloat x1 = x + width;
    GLfloat y1 = y;
    GLfloat *v, rectArray[32];

    v = rectArray;
   *v++ = x0; *v++ = y0;
   *v++ = 0.0f; *v++ = 0.0f;
    vec4_copy(v, colorUpperLeft);
    v += 4;

   *v++ = x1; *v++ = y0;
   *v++ = 1.0f; *v++ = 0.0f;
    vec4_copy(v, colorUpperRight);
    v += 4;

   *v++ = x1; *v++ = y1;
   *v++ = 1.0f; *v++ = 1.0f;
    vec4_copy(v, colorLowerRight);
    v += 4;

   *v++ = x0; *v++ = y1;
   *v++ = 0.0f; *v++ = 1.0f;
    vec4_copy(v, colorLowerLeft);

    if(qglIsTexture(texture))
    {
        qglBindTexture(GL_TEXTURE_2D, texture);
    }
    else
    {
        BindWhiteTexture();
    }
    qglBindBufferARB(GL_ARRAY_BUFFER, rectBuffer);
    qglBufferDataARB(GL_ARRAY_BUFFER, sizeof(GLfloat[32]), rectArray, GL_DYNAMIC_DRAW);
    qglVertexPointer(2, GL_FLOAT, 8 * sizeof(GLfloat), (void *)0);
    qglTexCoordPointer(2, GL_FLOAT, 8 * sizeof(GLfloat), (void *)sizeof(GLfloat[2]));
    qglColorPointer(4, GL_FLOAT, 8 * sizeof(GLfloat), (void *)sizeof(GLfloat[4]));
    qglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
Ejemplo n.º 30
0
void glf_render_str(gl_tex_font_p glf, GLfloat x, GLfloat y, const char *text, int32_t n_sym)
{
    if(glf && glf->ft_face && text && (text[0] != 0))
    {
        uint8_t *nch, *ch = (uint8_t*)text;
        FT_Vector kern;
        int32_t x_pt = 0;
        int32_t y_pt = 0;
        if(glf->gl_real_tex_indexes_count == 1)
        {
            GLuint elements_count = 0;
            uint32_t curr_utf32, next_utf32;
            GLfloat *p, *buffer;

            buffer = (GLfloat*)malloc(48 * utf8_strlen(text) * sizeof(GLfloat));
            nch = utf8_to_utf32(ch, &curr_utf32);
            curr_utf32 = FT_Get_Char_Index(glf->ft_face, curr_utf32);

            qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
            for(p = buffer; *ch && n_sym--;)
            {
                char_info_p g;
                uint8_t *nch2 = utf8_to_utf32(nch, &next_utf32);

                next_utf32 = FT_Get_Char_Index(glf->ft_face, next_utf32);
                ch = nch;
                nch = nch2;

                g = glf->glyphs + curr_utf32;
                FT_Get_Kerning(glf->ft_face, curr_utf32, next_utf32, FT_KERNING_UNSCALED, &kern);   // kern in 1/64 pixel
                curr_utf32 = next_utf32;

                if(g->tex_index != 0)
                {
                    GLfloat x0 = x  + g->left + x_pt / 64.0f;
                    GLfloat x1 = x0 + g->width;
                    GLfloat y0 = y  + g->top + y_pt / 64.0f;
                    GLfloat y1 = y0 - g->height;

                    *p = x0;            p++;
                    *p = y0;            p++;
                    *p = g->tex_x0;     p++;
                    *p = g->tex_y0;     p++;
                    vec4_copy(p, glf->gl_font_color);   p += 4;

                    *p = x1;            p++;
                    *p = y0;            p++;
                    *p = g->tex_x1;     p++;
                    *p = g->tex_y0;     p++;
                    vec4_copy(p, glf->gl_font_color);   p += 4;

                    *p = x1;            p++;
                    *p = y1;            p++;
                    *p = g->tex_x1;     p++;
                    *p = g->tex_y1;     p++;
                    vec4_copy(p, glf->gl_font_color);   p += 4;
                    elements_count++;

                    *p = x0;            p++;
                    *p = y0;            p++;
                    *p = g->tex_x0;     p++;
                    *p = g->tex_y0;     p++;
                    vec4_copy(p, glf->gl_font_color);   p += 4;

                    *p = x1;            p++;
                    *p = y1;            p++;
                    *p = g->tex_x1;     p++;
                    *p = g->tex_y1;     p++;
                    vec4_copy(p, glf->gl_font_color);   p += 4;

                    *p = x0;            p++;
                    *p = y1;            p++;
                    *p = g->tex_x0;     p++;
                    *p = g->tex_y1;     p++;
                    vec4_copy(p, glf->gl_font_color);   p += 4;
                    elements_count++;
                }
                x_pt += kern.x + g->advance_x_pt;
                y_pt += kern.y + g->advance_y_pt;
            }
            ///RENDER
            if(elements_count != 0)
            {
                qglBindTexture(GL_TEXTURE_2D, glf->gl_tex_indexes[0]);
                qglVertexPointer(2, GL_FLOAT, 8 * sizeof(GLfloat), buffer+0);
                qglTexCoordPointer(2, GL_FLOAT, 8 * sizeof(GLfloat), buffer+2);
                qglColorPointer(4, GL_FLOAT, 8 * sizeof(GLfloat), buffer+4);
                qglDrawArrays(GL_TRIANGLES, 0, elements_count * 3);
            }
            qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
            free(buffer);
        }
        else
        {
            GLfloat *p, buffer[32];
            GLuint active_texture = 0;
            uint32_t curr_utf32, next_utf32;
            nch = utf8_to_utf32(ch, &curr_utf32);
            curr_utf32 = FT_Get_Char_Index(glf->ft_face, curr_utf32);
            qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
            for(; *ch && n_sym--;)
            {
                char_info_p g;
                uint8_t *nch2 = utf8_to_utf32(nch, &next_utf32);

                next_utf32 = FT_Get_Char_Index(glf->ft_face, next_utf32);
                ch = nch;
                nch = nch2;

                g = glf->glyphs + curr_utf32;
                FT_Get_Kerning(glf->ft_face, curr_utf32, next_utf32, FT_KERNING_UNSCALED, &kern);   // kern in 1/64 pixel
                curr_utf32 = next_utf32;

                if(g->tex_index != 0)
                {
                    ///RENDER
                    GLfloat x0 = x  + g->left + x_pt / 64.0f;
                    GLfloat x1 = x0 + g->width;
                    GLfloat y0 = y  + g->top + y_pt / 64.0f;
                    GLfloat y1 = y0 - g->height;

                    p = buffer;
                    *p = x0;            p++;
                    *p = y0;            p++;
                    *p = g->tex_x0;     p++;
                    *p = g->tex_y0;     p++;
                    vec4_copy(p, glf->gl_font_color);   p += 4;

                    *p = x1;            p++;
                    *p = y0;            p++;
                    *p = g->tex_x1;     p++;
                    *p = g->tex_y0;     p++;
                    vec4_copy(p, glf->gl_font_color);   p += 4;

                    *p = x1;            p++;
                    *p = y1;            p++;
                    *p = g->tex_x1;     p++;
                    *p = g->tex_y1;     p++;
                    vec4_copy(p, glf->gl_font_color);   p += 4;

                    *p = x0;            p++;
                    *p = y1;            p++;
                    *p = g->tex_x0;     p++;
                    *p = g->tex_y1;     p++;
                    vec4_copy(p, glf->gl_font_color);

                    if(active_texture != g->tex_index)
                    {
                        qglBindTexture(GL_TEXTURE_2D, g->tex_index);
                        active_texture = g->tex_index;
                    }
                    qglVertexPointer(2, GL_FLOAT, 8 * sizeof(GLfloat), buffer+0);
                    qglTexCoordPointer(2, GL_FLOAT, 8 * sizeof(GLfloat), buffer+2);
                    qglColorPointer(4, GL_FLOAT, 8 * sizeof(GLfloat), buffer+4);
                    qglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
                }
                x_pt += kern.x + g->advance_x_pt;
                y_pt += kern.y + g->advance_y_pt;
            }
        }
    }
}