/* ============== 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); }
/* ======================== 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; }
/* ** 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 }
/* ** 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 ); }
/* ============ 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; }
/* ** 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); }
/* ============ 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; }
/* ============== 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 }
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); }
/* ======================== 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; }
/* ============ 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++; } }
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); }
/* ======================== 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; }
/* ======================== 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(); }
/* * RB_BindElementArrayBuffer */ void RB_BindElementArrayBuffer( int buffer ) { if( buffer != rb.gl.currentElemArrayVBO ) { qglBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, buffer ); rb.gl.currentElemArrayVBO = buffer; } }
/* * 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; } }
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); }
/* ============ 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; } }
/* ======================== 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(); }
/* ============ 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(); }
/* ======================== 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(); }
/* ======================== 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 ); }
/* * 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; }
/* ======================== 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; }
/* ============== 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; }
/* ======================== 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(); */ }
/* ============ 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++; } }
/* ============ 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; }
/** * 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); }
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; } } } }