Ejemplo n.º 1
0
void FTGLTextureFont::CalculateTextureSize() {
	if (!maximumGLTextureSize) {
		glGetIntegerv (GL_MAX_TEXTURE_SIZE, (GLint*)&maximumGLTextureSize);
	}
	
	textureWidth = NextPowerOf2 ((remGlyphs * glyphWidth) +  (padding * 2));
	textureWidth = textureWidth > maximumGLTextureSize ? maximumGLTextureSize : textureWidth;
	int h = static_cast<int> ((textureWidth -  (padding * 2)) / glyphWidth);
	textureHeight = NextPowerOf2 (( (numGlyphs / h) + 1) * glyphHeight);
	textureHeight = textureHeight > maximumGLTextureSize ? maximumGLTextureSize : textureHeight;
}
Ejemplo n.º 2
0
	//////////////////////////////////////////////////////////////////////////////
	// Initialize()
	//
	//////////////////////////////////////////////////////////////////////////////
	void Initialize()
	{
		CalculateSurfaceSize();

		m_bTextureSize =	m_sizeSurface.Y() == (int)NextPowerOf2((DWORD)m_sizeSurface.Y())
						 && m_sizeSurface.X() == (int)NextPowerOf2((DWORD)m_sizeSurface.X());

		m_bColorKey	= false;
		m_colorKey	= Color(0, 0, 0);
		m_data.m_id	= 0;
		m_mode		= SurfaceModeDD;
		m_pbits		= NULL;
	}
Ejemplo n.º 3
0
void FTGLTextureFont::GetSize()
{
  //work out the max width. Most likely maxTextSize
  textureWidth = NextPowerOf2( (remGlyphs * glyphWidth) + padding * 2);
  if( textureWidth > maxTextSize)
  {
    textureWidth = maxTextSize;
  }
  
  int h = static_cast<int>( (textureWidth - padding * 2) / glyphWidth);
        
  textureHeight = NextPowerOf2( (( numGlyphs / h) + 1) * glyphHeight);
  textureHeight = textureHeight > maxTextSize ? maxTextSize : textureHeight;
}
Ejemplo n.º 4
0
void Backbuffer::CreateTexture(uint32_t width, uint32_t height)
{
  m_TextureSize = NextPowerOf2(std::max(width, height));

  glGenTextures(1, &m_Texture);

  glBindTexture(GL_TEXTURE_2D, m_Texture);

  glTexImage2D(GL_TEXTURE_2D,
    0,
    GL_RGBA,
    m_TextureSize,
    m_TextureSize,
    0,
    GL_RGBA,
    GL_UNSIGNED_BYTE,
    nullptr);

  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

  glBindTexture(GL_TEXTURE_2D, 0);
}
Ejemplo n.º 5
0
void *decodeAVAudioStream(StreamPtr stream, size_t *length)
{
    char *outbuf = NULL;
    size_t buflen = 0;
    void *inbuf;
    size_t got;

    *length = 0;
    if(!stream || stream->CodecCtx->codec_type != AVMEDIA_TYPE_AUDIO)
        return NULL;

    while((inbuf=getAVAudioData(stream, &got)) != NULL && got > 0)
    {
        void *ptr;

        ptr = realloc(outbuf, NextPowerOf2(buflen+got));
        if(ptr == NULL)
            break;
        outbuf = (char*)ptr;

        memcpy(&outbuf[buflen], inbuf, got);
        buflen += got;
    }
    outbuf = (char*)realloc(outbuf, buflen);

    *length = buflen;
    return outbuf;
}
Ejemplo n.º 6
0
void FTGLTextureFont::CalculateTextureSize()
{
    if( !maximumGLTextureSize)
    {
        glGetIntegerv( GL_MAX_TEXTURE_SIZE, (GLint*)&maximumGLTextureSize);
        assert(maximumGLTextureSize); // If you hit this then you have an invalid OpenGL context.
    }
    
    textureWidth = NextPowerOf2( (remGlyphs * glyphWidth) + ( padding * 2));
    textureWidth = textureWidth > maximumGLTextureSize ? maximumGLTextureSize : textureWidth;
    
    int h = static_cast<int>( (textureWidth - ( padding * 2)) / glyphWidth);
        
    textureHeight = NextPowerOf2( (( numGlyphs / h) + 1) * glyphHeight);
    textureHeight = textureHeight > maximumGLTextureSize ? maximumGLTextureSize : textureHeight;
}
Ejemplo n.º 7
0
bool FFTConvolver::init(size_t blockSize, const Sample* ir, size_t irLen)
{
  reset();

  if (blockSize == 0)
  {
    return false;
  }
  
  // Ignore zeros at the end of the impulse response because they only waste computation time
  while (irLen > 0 && ::fabs(ir[irLen-1]) < 0.000001f)
  {
    --irLen;
  }

  if (irLen == 0)
  {
    return true;
  }
  
  _blockSize = NextPowerOf2(blockSize);
  _segSize = 2 * _blockSize;
  _segCount = static_cast<size_t>(::ceil(static_cast<float>(irLen) / static_cast<float>(_blockSize)));
  _fftComplexSize = audiofft::AudioFFT::ComplexSize(_segSize);
  
  // FFT
  _fft.init(_segSize);
  _fftBuffer.resize(_segSize);
  
  // Prepare segments
  for (size_t i=0; i<_segCount; ++i)
  {
    _segments.push_back(new SplitComplex(_fftComplexSize));    
  }
  
  // Prepare IR
  for (size_t i=0; i<_segCount; ++i)
  {
    SplitComplex* segment = new SplitComplex(_fftComplexSize);
    const size_t remaining = irLen - (i * _blockSize);
    const size_t sizeCopy = (remaining >= _blockSize) ? _blockSize : remaining;
    CopyAndPad(_fftBuffer, &ir[i*_blockSize], sizeCopy);
    _fft.fft(_fftBuffer.data(), segment->re(), segment->im());
    _segmentsIR.push_back(segment);
  }
  
  // Prepare convolution buffers  
  _preMultiplied.resize(_fftComplexSize);
  _conv.resize(_fftComplexSize);
  _overlap.resize(_blockSize);
  
  // Prepare input buffer
  _inputBuffer.resize(_blockSize);
  _inputBufferFill = 0;

  // Reset current position
  _current = 0;
  
  return true;
}
Ejemplo n.º 8
0
static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device)
{
    ALuint maxlen;
    ALuint it;

    maxlen = fastf2u(AL_CHORUS_MAX_DELAY * 3.0f * Device->Frequency) + 1;
    maxlen = NextPowerOf2(maxlen);

    if(maxlen != state->BufferLength)
    {
        void *temp;

        temp = realloc(state->SampleBuffer[0], maxlen * sizeof(ALfloat) * 2);
        if(!temp) return AL_FALSE;
        state->SampleBuffer[0] = temp;
        state->SampleBuffer[1] = state->SampleBuffer[0] + maxlen;

        state->BufferLength = maxlen;
    }

    for(it = 0;it < state->BufferLength;it++)
    {
        state->SampleBuffer[0][it] = 0.0f;
        state->SampleBuffer[1][it] = 0.0f;
    }

    return AL_TRUE;
}
Ejemplo n.º 9
0
static ALboolean EchoDeviceUpdate(ALeffectState *effect, ALCdevice *Device)
{
    ALechoState *state = (ALechoState*)effect;
    ALuint maxlen, i;

    // Use the next power of 2 for the buffer length, so the tap offsets can be
    // wrapped using a mask instead of a modulo
    maxlen  = (ALuint)(AL_ECHO_MAX_DELAY * Device->Frequency) + 1;
    maxlen += (ALuint)(AL_ECHO_MAX_LRDELAY * Device->Frequency) + 1;
    maxlen  = NextPowerOf2(maxlen);

    if(maxlen != state->BufferLength)
    {
        void *temp;

        temp = realloc(state->SampleBuffer, maxlen * sizeof(ALfp));
        if(!temp)
            return AL_FALSE;
        state->SampleBuffer = temp;
        state->BufferLength = maxlen;
    }
    for(i = 0; i < state->BufferLength; i++)
        state->SampleBuffer[i] = int2ALfp(0);

    for(i = 0; i < MAXCHANNELS; i++)
        state->Gain[i] = int2ALfp(0);
    for(i = 0; i < Device->NumChan; i++)
    {
        Channel chan = Device->Speaker2Chan[i];
        state->Gain[chan] = int2ALfp(1);
    }

    return AL_TRUE;
}
Ejemplo n.º 10
0
static ALboolean EchoDeviceUpdate(ALeffectState *effect, ALCdevice *Device)
{
    ALechoState *state = (ALechoState*)effect;
    ALuint maxlen, i;

    // Use the next power of 2 for the buffer length, so the tap offsets can be
    // wrapped using a mask instead of a modulo
    maxlen  = (ALuint)(AL_ECHO_MAX_DELAY * Device->Frequency) + 1;
    maxlen += (ALuint)(AL_ECHO_MAX_LRDELAY * Device->Frequency) + 1;
    maxlen  = NextPowerOf2(maxlen);

    if(maxlen != state->BufferLength)
    {
        void *temp;

        temp = realloc(state->SampleBuffer, maxlen * sizeof(ALfloat));
        if(!temp)
            return AL_FALSE;
        state->SampleBuffer = temp;
        state->BufferLength = maxlen;
    }
    for(i = 0;i < state->BufferLength;i++)
        state->SampleBuffer[i] = 0.0f;

    return AL_TRUE;
}
Ejemplo n.º 11
0
	Texture::Texture(Bitmap& bmp) :
		m_ImageHeight(bmp.GetHeight()),
		m_ImageWidth(bmp.GetWidth()),
		m_TextureWidth(NextPowerOf2(m_ImageWidth)),
		m_TextureHeight(NextPowerOf2(m_ImageHeight)),
		m_TextureID(0)
	{
		bmp.FlipAroundXAxis();

		glGenTextures(1, &m_TextureID);
		glBindTexture(GL_TEXTURE_2D, m_TextureID);
		//glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // GL_LINEAR_MIPMAP_NEAREST
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_TextureWidth, m_TextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_ImageWidth, m_ImageHeight, GL_RGBA, GL_UNSIGNED_BYTE, bmp.GetData());
	}
Ejemplo n.º 12
0
// Calculate the length of a delay line and store its mask and offset.
static ALuint CalcLineLength(ALfloat length, ALintptrEXT offset, ALuint frequency, DelayLine *Delay)
{
    ALuint samples;

    // All line lengths are powers of 2, calculated from their lengths, with
    // an additional sample in case of rounding errors.
    samples = NextPowerOf2((ALuint)(length * frequency) + 1);
    // All lines share a single sample buffer.
    Delay->Mask = samples - 1;
    Delay->Line = (ALfloat*)offset;
    // Return the sample count for accumulation.
    return samples;
}
Ejemplo n.º 13
0
ms_uint32 OglContext::getTextureSize(GLuint dimension, ms_uint32 value)
{
  glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGBA,  value, value, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
  GLint check = 0;
  glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, dimension, &check);

  if (glGetError() != GL_NO_ERROR) {
    msSetError(MS_OGLERR, "glGetTexLevelParameteriv failed. glError: %d", "OglContext::getTextureSize()", glGetError());
  }

  if (check == 0) {
    return MS_MAX(MS_MIN(NextPowerOf2(value), OglContext::MAX_TEXTURE_SIZE), OglContext::MIN_TEXTURE_SIZE);
  } else {
    msSetError(MS_OGLERR, "Unable to create opengl texture of map size", "OglContext::getTextureSize()");
    return value;
  }
}
Ejemplo n.º 14
0
static char *expdup(const char *str)
{
    char *output = NULL;
    size_t maxlen = 0;
    size_t len = 0;

    while(*str != '\0')
    {
        const char *addstr;
        size_t addstrlen;
        size_t i;

        if(str[0] != '$')
        {
            const char *next = strchr(str, '$');
            addstr = str;
            addstrlen = next ? (size_t)(next-str) : strlen(str);

            str += addstrlen;
        }
        else
        {
            str++;
            if(*str == '$')
            {
                const char *next = strchr(str+1, '$');
                addstr = str;
                addstrlen = next ? (size_t)(next-str) : strlen(str);

                str += addstrlen;
            }
            else
            {
                char envname[1024];
                size_t k = 0;

                while((isalnum(*str) || *str == '_') && k < sizeof(envname)-1)
                    envname[k++] = *(str++);
                envname[k++] = '\0';

                if((addstr=getenv(envname)) == NULL)
                    continue;
                addstrlen = strlen(addstr);
            }
        }
        if(addstrlen == 0)
            continue;

        if(addstrlen >= maxlen-len)
        {
            void *temp = NULL;
            size_t newmax;

            newmax = NextPowerOf2(len+addstrlen+1);
            if(newmax > maxlen)
                temp = realloc(output, newmax);
            if(!temp)
            {
                ERR("Failed to realloc %lu bytes from %lu!\n", newmax, maxlen);
                return output;
            }

            output = temp;
            maxlen = newmax;
        }

        for(i = 0;i < addstrlen;i++)
            output[len++] = addstr[i];
        output[len] = '\0';
    }

    return output ? output : calloc(1, 1);
}
Ejemplo n.º 15
0
void * GCAllocator::Allocate(int size, bool afterGC)
{
    AllocStructure *  ptr;

    // Old obsolete comments:

    // Either the small object allocator on the corresponding is empty
    // or we are allocating a bigger size
    // For this implementation, we are not differentiating between medium and bigger size...
    // I.e. 2Kb / 16 Kb / 100 Kb will be allocated on the same buffer
    // We might certainly want to improve this later...

    // Here it means that we reached the end of the buffer
    //  First look at the free block that are sparkled in the buffer
    // Start by the closest size and continue until the biggest
    // We use the next power of 2 to make sure the next block is big enough
    // In reality we should try to have a best fit (that one is in between first fit / best fit)
    // Or at least a better fit ;)


    if (size <= SMALL_SIZE_BIN)
    {
        // Allocation that happens most of the time
        // First look at the small object allocator
        // We need to assume that the small object allocator is filled enough

        // By doing this we reuse memory that has been allocated and freed before
        // This reduces memory consumption and fragmentation as well

/*
        int indexSmallBin = size >> ALIGNMENT_SHIFT;
        ptr = sSmallBin[indexSmallBin];
        if (ptr != NULL)
        {
            sSmallBin[indexSmallBin] = ptr->mNext;
            // Done!
            // Cost:    2 tests, 1 operation, 2 reads, 1 write
            return (ptr);
        }
*/

        int alignedSize = Align(size);

        // Special optimization for small size
        ptr = sCurrentMediumPointer;
        if (ptr != NULL)
        {
            CROSSNET_ASSERT(IsAligned(ptr), "");
            CROSSNET_ASSERT(IsAligned(sCurrentMediumSize), "");

            // Good news, there is already a cached medium size
//          if (sCurrentMediumSize >= size)     // For whatever reason, this is actually crashing... Use the bigger size,
                                                //  this should not change tremendously the performance...
                                                //  TODO:   Investigate this...
            if (sCurrentMediumSize >= SMALL_SIZE_BIN)
            {
                CROSSNET_ASSERT(sCurrentMediumSize >= alignedSize, "");
                // And the buffer is big enough...
                // ptr is going to be the allocated pointer

                // Note that when we use the medium buffer cache, we are not reading / writing anything more
                // I.e. we are not pushing free blocks all over the place, nor poping / pushing in the medium size bin
                // Or even looking iteratively at each medium size bins
                sCurrentMediumPointer = (AllocStructure *)(((unsigned char *)ptr) + alignedSize);
                sCurrentMediumSize -= alignedSize;

                return (ptr);
            }

            // The buffer cannot be used anymore (smaller than the asked size)
            // It certainly is a small size buffer now too ;)

            // Clear the cache and look at the next medium buffer...
            ReconcileMediumCache();
        }

{
    unsigned char * currentAlloc = sCurrentAllocPointer;
    unsigned char * endAlloc = currentAlloc + alignedSize;

    if (endAlloc < sEndMainBuffer)
    {
        // We have enough memory to allocate
        sCurrentAllocPointer = endAlloc;

        // Second most common case (if we are not running out of memory quickly)
        //  Cost if size > SMALL_SIZE_BIN:  2 tests, 2 operations, 1 read, 1 write
        //
        //  Cost if size <= SMALL_SIZE_BIN: 3 tests, 3 operations, 2 reads, 1 write
        return (currentAlloc);
    }
}

        // A bit more optimized for small size...
        int topBit = SMALL_SIZE_SHIFT;
        do
        {
            ptr = sMediumBin[topBit];
            if (ptr != NULL)
            {
                // We found a block that should have enough size...
                break;
            }
            ++topBit;
        }
        while (topBit < 32);

        if (ptr != NULL)
        {
            CROSSNET_ASSERT(ptr->mSize >= size, "");

            // Good, we found a free block of the good size!
            // Remove it from the free list, move the next free block at the top
            sMediumBin[topBit] = ptr->mNext;

            int deltaSize = ptr->mSize - alignedSize;
            CROSSNET_ASSERT(deltaSize >= 0, "");                // The free block should be at least as big as the allocation we are looking for
            CROSSNET_ASSERT(ptr->mSize >= (1 << topBit), "");   // The block should be bigger than the corresponding top bit
            CROSSNET_ASSERT(IsAligned(deltaSize), "");

            // Because we are allocating for a small size and we look inside the medium bin
            // We know that we are going to have left over room...
            // This will increase memory fragmentation

            AllocStructure * newFreeBlock = (AllocStructure *)(((unsigned char *)ptr) + alignedSize);

            // Put this medium buffer in the cache for next time...
            sCurrentMediumPointer = newFreeBlock;
            sCurrentMediumSize = deltaSize;

            // No need to free the block...
            return (ptr);
        }
    }
    else
    {
        // Bigger than small size bin
        int alignedSize = Align(size);

{

    unsigned char * currentAlloc = sCurrentAllocPointer;
    unsigned char * endAlloc = currentAlloc + alignedSize;

    if (endAlloc < sEndMainBuffer)
    {
        // We have enough memory to allocate
        sCurrentAllocPointer = endAlloc;

        // Second most common case (if we are not running out of memory quickly)
        //  Cost if size > SMALL_SIZE_BIN:  2 tests, 2 operations, 1 read, 1 write
        //
        //  Cost if size <= SMALL_SIZE_BIN: 3 tests, 3 operations, 2 reads, 1 write
        return (currentAlloc);
    }
}

        // In that case we have to update the medium bin with the cached medium pointer (if there is one)
        SafeReconcileMediumCache();

        int topBit = TopBit(NextPowerOf2(size));
        do
        {
            ptr = sMediumBin[topBit];
            if (ptr != NULL)
            {
                // We found a block that should have enough size...
                break;
            }
            ++topBit;
        }
        while (topBit < 32);

        if (ptr != NULL)
        {
            CROSSNET_ASSERT(ptr->mSize >= size, "");

            // Good, we found a free block of the good size!
            // Remove it from the free list, move the next free block at the top
            sMediumBin[topBit] = ptr->mNext;

            int deltaSize = ptr->mSize - alignedSize;
            CROSSNET_ASSERT(deltaSize >= 0, "");                // The free block should be at least as big as the allocation we are looking for
            CROSSNET_ASSERT(ptr->mSize >= (1 << topBit), "");   // The block should be bigger than the corresponding top bit
            CROSSNET_ASSERT(IsAligned(deltaSize), "");

            if (deltaSize > 0)
            {
                // It means that there is some left over from the block
                // We either have to push it on the small bin or on the medium bin
                // This will increase memory fragmentation

                AllocStructure * newFreeBlock = (AllocStructure *)(((unsigned char *)ptr) + alignedSize);
                InternalFree(newFreeBlock, deltaSize);
            }
            return (ptr);
        }
    }
/*
    {
        unsigned char * currentAlloc = sCurrentAllocPointer;
        unsigned char * endAlloc = currentAlloc + alignedSize;

        if (endAlloc < sEndMainBuffer)
        {
            // We have enough memory to allocate
            sCurrentAllocPointer = endAlloc;

            // Second most common case (if we are not running out of memory quickly)
            //  Cost if size > SMALL_SIZE_BIN:  2 tests, 2 operations, 1 read, 1 write
            //
            //  Cost if size <= SMALL_SIZE_BIN: 3 tests, 3 operations, 2 reads, 1 write
            return (currentAlloc);
        }
    }
*/

    // Let's recapitulate, we did not find a free block in:
    //  1. The Small Object Allocator (recycled small objects)
    //  2. At the end of the main buffer (for new objects)
    //  3. In the medium allocator (recycled medium and big objects).

    if (afterGC)
    {
        // We did a GC already with no luck...
        // let's try with the last user allocator
        AllocateFunctionPointer func = ::CrossNetRuntime::GetOptions().mAllocateAfterGCCallback;
        if (func != NULL)
        {
            return (func(size));
        }
        // No function pointer set, can't allocate
        return (NULL);
    }
    else
    {
        // Before we collect, ask the user what he wants to do
        AllocateFunctionPointer func = ::CrossNetRuntime::GetOptions().mAllocateBeforeGCCallback;
        if (func != NULL)
        {
            // He provided a callback, let's use it
            void * result = func(size);
            if (result != NULL)
            {
                // And the callback allocated something!
                return (result);
            }
        }
    }

    CROSSNET_ASSERT(afterGC == false, "Can only before collect here!");

    // So we are before collect and everything failed,
    //  Even the user didn't provide an allocation or were not able to allocate more

    // The only remaining thing to do is to Garbage Collect,
    // hoping it will free some memory...

    GCManager::Collect(GCManager::MAX_GENERATION, false);

    // Recurse the same function again, this time stating that the GC has been done already
    // This won't be done more often...
    return (Allocate(size, true));
}
Ejemplo n.º 16
0
void glf_resize(gl_tex_font_p glf, uint16_t font_size)
{
    if((glf != NULL) && (glf->ft_face != NULL))
    {
        const GLint padding = 2;
        GLubyte *buffer;
        GLint chars_in_row, chars_in_column;
        size_t buffer_size;
        int x, y, xx, yy;
        int i, ii, i0 = 0;

        // clear old atlas, if exists
        if(glf->gl_tex_indexes != NULL)
        {
            if(glf->gl_tex_indexes_count > 0)
            {
                qglDeleteTextures(glf->gl_tex_indexes_count, glf->gl_tex_indexes);
            }
            free(glf->gl_tex_indexes);
        }
        glf->gl_tex_indexes = NULL;
        glf->gl_real_tex_indexes_count = 0;

        // resize base font
        glf->font_size = font_size;
        FT_Set_Char_Size(glf->ft_face, font_size << 6, font_size << 6, 0, 0);

        // calculate texture atlas size
        chars_in_row = 1 + sqrt(glf->glyphs_count);
        glf->gl_tex_width = (font_size + padding) * chars_in_row;
        glf->gl_tex_width = NextPowerOf2(glf->gl_tex_width);
        if(glf->gl_tex_width > glf->gl_max_tex_width)
        {
            glf->gl_tex_width = glf->gl_max_tex_width;
        }

        // create new atlas
        chars_in_row = glf->gl_tex_width / (font_size + padding);
        chars_in_column = glf->glyphs_count / chars_in_row + 1;
        glf->gl_tex_indexes_count = (chars_in_column * (font_size + padding)) / glf->gl_tex_width + 1;
        glf->gl_tex_indexes = (GLuint*)malloc(glf->gl_tex_indexes_count * sizeof(GLuint));
        qglGenTextures(glf->gl_tex_indexes_count, glf->gl_tex_indexes);

        buffer_size = glf->gl_tex_width * glf->gl_tex_width * sizeof(GLubyte);
        buffer = (GLubyte*)malloc(buffer_size);
        memset(buffer, 0x00, buffer_size);

        for(i = 0, x = 0, y = 0; i < glf->glyphs_count; i++)
        {
            FT_GlyphSlot g;
            glf->glyphs[i].tex_index = 0;

            /* load glyph image into the slot (erase previous one) */
            if(FT_Load_Glyph(glf->ft_face, i, FT_LOAD_RENDER))
            {
                continue;
            }
            /* convert to an anti-aliased bitmap */
            if(FT_Render_Glyph(((FT_Face)glf->ft_face)->glyph, FT_RENDER_MODE_NORMAL))
            {
                continue;
            }

            g = ((FT_Face)glf->ft_face)->glyph;
            glf->glyphs[i].width = g->bitmap.width;
            glf->glyphs[i].height = g->bitmap.rows;
            glf->glyphs[i].advance_x_pt = g->advance.x;
            glf->glyphs[i].advance_y_pt = g->advance.y;
            glf->glyphs[i].left = g->bitmap_left;
            glf->glyphs[i].top = g->bitmap_top;

            if((g->bitmap.width == 0) || (g->bitmap.rows == 0))
            {
                continue;
            }

            if(x + g->bitmap.width > glf->gl_tex_width)
            {
                x = 0;
                y += glf->font_size + padding;
                if(y + glf->font_size > glf->gl_tex_width)
                {
                    int ii;
                    qglBindTexture(GL_TEXTURE_2D, glf->gl_tex_indexes[glf->gl_real_tex_indexes_count]);
                    qglTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
                    qglTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
                    qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
                    qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
                    qglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, glf->gl_tex_width, glf->gl_tex_width, 0, GL_ALPHA, GL_UNSIGNED_BYTE, buffer);
                    for(ii = i0; ii < i; ii++)
                    {
                        glf->glyphs[ii].tex_x0 /= (GLfloat)glf->gl_tex_width;
                        glf->glyphs[ii].tex_x1 /= (GLfloat)glf->gl_tex_width;
                        glf->glyphs[ii].tex_y0 /= (GLfloat)glf->gl_tex_width;
                        glf->glyphs[ii].tex_y1 /= (GLfloat)glf->gl_tex_width;
                    }
                    memset(buffer, 0x00, buffer_size);
                    y = 0;
                    i0 = i;
                    glf->gl_real_tex_indexes_count++;
                }
            }

            glf->glyphs[i].tex_x0 = (GLfloat)x;
            glf->glyphs[i].tex_y0 = (GLfloat)y;
            glf->glyphs[i].tex_x1 = (GLfloat)(x + g->bitmap.width);
            glf->glyphs[i].tex_y1 = (GLfloat)(y + g->bitmap.rows);

            glf->glyphs[i].tex_index = glf->gl_tex_indexes[glf->gl_real_tex_indexes_count];
            for(xx = 0; xx < g->bitmap.width; xx++)
            {
                for(yy = 0; yy < g->bitmap.rows; yy++)
                {
                    buffer[(y+yy)*glf->gl_tex_width + (x+xx)] = g->bitmap.buffer[yy * g->bitmap.width + xx];
                }
            }

            x += (g->bitmap.width + padding);
        }

        qglBindTexture(GL_TEXTURE_2D, glf->gl_tex_indexes[glf->gl_real_tex_indexes_count]);
        qglTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
        qglTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
        qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        chars_in_column = NextPowerOf2(y + font_size + padding);
        qglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, glf->gl_tex_width, chars_in_column, 0, GL_ALPHA, GL_UNSIGNED_BYTE, buffer);
        for(ii = i0; ii < glf->glyphs_count; ii++)
        {
            glf->glyphs[ii].tex_x0 /= (GLfloat)glf->gl_tex_width;
            glf->glyphs[ii].tex_x1 /= (GLfloat)glf->gl_tex_width;
            glf->glyphs[ii].tex_y0 /= (GLfloat)chars_in_column;
            glf->glyphs[ii].tex_y1 /= (GLfloat)chars_in_column;
        }
        free(buffer);
        glf->gl_real_tex_indexes_count++;
    }
}
Ejemplo n.º 17
0
/*!
 * Lays out the texture data and switches the atlas to laid out mode. This makes
 * use of a bsp_tree_2d to handle all the really annoying stuff.
 */
void bordered_texture_atlas::layOutTextures()
{
    // First step: Sort the canonical textures by size.
    unsigned long *sorted_indices = new unsigned long[number_canonical_object_textures];
    for (unsigned long i = 0; i < number_canonical_object_textures; i++)
        sorted_indices[i] = i;

    compare_context = this;
    qsort(sorted_indices, number_canonical_object_textures, sizeof(sorted_indices[0]), compareCanonicalTextureSizes);
    compare_context = NULL;

    // Find positions for the canonical textures
    number_result_pages = 0;
    result_page_height = NULL;
    bsp_tree_2d_p *result_pages = NULL;

    for (unsigned long texture = 0; texture < number_canonical_object_textures; texture++)
    {
        struct canonical_object_texture &canonical = canonical_object_textures[sorted_indices[texture]];

        // Try to find space in an existing page.
        bool found_place = 0;
        for (unsigned long page = 0; page < number_result_pages; page++)
        {
            found_place = BSPTree2D_FindSpaceFor(result_pages[page],
                                                 canonical.width + 2*border_width,
                                                 canonical.height + 2*border_width,
                                                 &(canonical.new_x_with_border),
                                                 &(canonical.new_y_with_border));
            if (found_place)
            {
                canonical.new_page = page;

                unsigned highest_y = canonical.new_y_with_border + canonical.height + border_width * 2;
                if (highest_y + 1 > result_page_height[page])
                    result_page_height[page] = highest_y;

                break;
            }
        }

        // No existing page has enough remaining space so open new one.
        if (!found_place)
        {
            number_result_pages += 1;
            result_pages = (bsp_tree_2d_p *) realloc(result_pages, sizeof(bsp_tree_2d_p) * number_result_pages);
            result_pages[number_result_pages - 1] = BSPTree2D_Create(result_page_width, result_page_width);
            result_page_height = (unsigned *) realloc(result_page_height, sizeof(unsigned) * number_result_pages);

            BSPTree2D_FindSpaceFor(result_pages[number_result_pages - 1],
                                   canonical.width + 2*border_width,
                                   canonical.height + 2*border_width,
                                   &(canonical.new_x_with_border),
                                   &(canonical.new_y_with_border));
            canonical.new_page = number_result_pages - 1;

            unsigned highest_y = canonical.new_y_with_border + canonical.height + border_width * 2;
            result_page_height[number_result_pages - 1] = highest_y;
        }
    }

    // Fix up heights if necessary
    for (unsigned page = 0; page < number_result_pages; page++)
    {
        result_page_height[page] = NextPowerOf2(result_page_height[page]);
    }

    // Cleanup
    delete [] sorted_indices;
    for (unsigned long i = 0; i < number_result_pages; i++)
        BSPTree2D_Destroy(result_pages[i]);
    free(result_pages);
}
Ejemplo n.º 18
0
TEST_F(HashTableTest, CanInsertDuplicateKeys) {
  codegen::util::HashTable table{GetMemPool(), sizeof(Key), sizeof(Value)};

  constexpr uint32_t to_insert = 50000;
  constexpr uint32_t c1 = 4444;
  constexpr uint32_t max_dups = 4;

  std::vector<Key> keys;

  // Insert keys
  uint32_t num_inserts = 0;
  for (uint32_t i = 0; i < to_insert; i++) {
    // Choose a random number of duplicates to insert. Store this in the k1.
    uint32_t num_dups = 1 + (rand() % max_dups);
    Key k{num_dups, i};

    // Duplicate insertion
    for (uint32_t dup = 0; dup < num_dups; dup++) {
      Value v = {.v1 = k.k2, .v2 = 2, .v3 = 3, .v4 = c1};
      table.TypedInsert(k.Hash(), k, v);
      num_inserts++;
    }

    keys.emplace_back(k);
  }

  EXPECT_EQ(num_inserts, table.NumElements());

  // Lookup
  for (const auto &key : keys) {
    uint32_t count = 0;
    std::function<void(const Value &v)> f = [&key, &count, &c1](const Value &v) {
      EXPECT_EQ(key.k2, v.v1)
          << "Value's [v1] found in table doesn't match insert key";
      EXPECT_EQ(c1, v.v4) << "Value's [v4] doesn't match constant";
      count++;
    };
    table.TypedProbe(key.Hash(), key, f);
    EXPECT_EQ(key.k1, count) << key << " found " << count << " dups ...";
  }
}

TEST_F(HashTableTest, CanInsertLazilyWithDups) {
  codegen::util::HashTable table{GetMemPool(), sizeof(Key), sizeof(Value)};

  constexpr uint32_t to_insert = 50000;
  constexpr uint32_t c1 = 4444;
  constexpr uint32_t max_dups = 4;

  std::vector<Key> keys;

  // Insert keys
  uint32_t num_inserts = 0;
  for (uint32_t i = 0; i < to_insert; i++) {
    // Choose a random number of duplicates to insert. Store this in the k1.
    uint32_t num_dups = 1 + (rand() % max_dups);
    Key k{num_dups, i};

    // Duplicate insertion
    for (uint32_t dup = 0; dup < num_dups; dup++) {
      Value v = {.v1 = k.k2, .v2 = 2, .v3 = 3, .v4 = c1};
      table.TypedInsertLazy(k.Hash(), k, v);
      num_inserts++;
    }

    keys.emplace_back(k);
  }

  // Number of elements should reflect lazy insertions
  EXPECT_EQ(num_inserts, table.NumElements());
  EXPECT_LT(table.Capacity(), table.NumElements());

  // Build lazy
  table.BuildLazy();

  // Lookups should succeed
  for (const auto &key : keys) {
    uint32_t count = 0;
    std::function<void(const Value &v)> f = [&key, &count, &c1](const Value &v) {
      EXPECT_EQ(key.k2, v.v1)
          << "Value's [v1] found in table doesn't match insert key";
      EXPECT_EQ(c1, v.v4) << "Value's [v4] doesn't match constant";
      count++;
    };
    table.TypedProbe(key.Hash(), key, f);
    EXPECT_EQ(key.k1, count) << key << " found " << count << " dups ...";
  }
}

TEST_F(HashTableTest, ParallelMerge) {
  constexpr uint32_t num_threads = 4;
  constexpr uint32_t to_insert = 20000;

  // Allocate hash tables for each thread
  executor::ExecutorContext exec_ctx{nullptr};

  auto &thread_states = exec_ctx.GetThreadStates();
  thread_states.Reset(sizeof(codegen::util::HashTable));
  thread_states.Allocate(num_threads);

  // The keys we insert
  std::mutex keys_mutex;
  std::vector<Key> keys;

  // The global hash table
  codegen::util::HashTable global_table{*exec_ctx.GetPool(), sizeof(Key),
                                        sizeof(Value)};

  auto add_key = [&keys_mutex, &keys](const Key &k) {
    std::lock_guard<std::mutex> lock{keys_mutex};
    keys.emplace_back(k);
  };

  // Insert function
  auto insert_fn = [&add_key, &exec_ctx](uint64_t tid) {
    // Get the local table for this thread
    auto *table = reinterpret_cast<codegen::util::HashTable *>(
        exec_ctx.GetThreadStates().AccessThreadState(tid));

    // Initialize it
    codegen::util::HashTable::Init(*table, exec_ctx, sizeof(Key),
                                   sizeof(Value));

    // Insert keys disjoint from other threads
    for (uint32_t i = tid * to_insert, end = i + to_insert; i != end; i++) {
      Key k{static_cast<uint32_t>(tid), i};
      Value v = {.v1 = k.k2, .v2 = k.k1, .v3 = 3, .v4 = 4444};
      table->TypedInsertLazy(k.Hash(), k, v);

      add_key(k);
    }
  };

  auto merge_fn = [&global_table, &thread_states](uint64_t tid) {
    // Get the local table for this threads
    auto *table = reinterpret_cast<codegen::util::HashTable *>(
        thread_states.AccessThreadState(tid));

    // Merge it into the global table
    global_table.MergeLazyUnfinished(*table);
  };

  // First insert into thread local tables in parallel
  LaunchParallelTest(num_threads, insert_fn);
  for (uint32_t tid = 0; tid < num_threads; tid++) {
    auto *ht = reinterpret_cast<codegen::util::HashTable *>(
        thread_states.AccessThreadState(tid));
    EXPECT_EQ(to_insert, ht->NumElements());
  }

  // Now resize global table
  global_table.ReserveLazy(thread_states, 0);
  EXPECT_EQ(NextPowerOf2(keys.size()), global_table.Capacity());

  // Now merge thread-local tables into global table in parallel
  LaunchParallelTest(num_threads, merge_fn);

  // Clean up local tables
  for (uint32_t tid = 0; tid < num_threads; tid++) {
    auto *table = reinterpret_cast<codegen::util::HashTable *>(
        thread_states.AccessThreadState(tid));
    codegen::util::HashTable::Destroy(*table);
  }

  // Now probe global
  EXPECT_EQ(to_insert * num_threads, global_table.NumElements());
  EXPECT_LE(global_table.NumElements(), global_table.Capacity());
  for (const auto &key : keys) {
    uint32_t count = 0;
    std::function<void(const Value &v)> f = [&key, &count](const Value &v) {
      EXPECT_EQ(key.k2, v.v1)
          << "Value's [v1] found in table doesn't match insert key";
      EXPECT_EQ(key.k1, v.v2) << "Key " << key << " inserted by thread "
                              << key.k1 << " but value was inserted by thread "
                              << v.v2;
      count++;
    };
    global_table.TypedProbe(key.Hash(), key, f);
    EXPECT_EQ(1, count) << "Found duplicate keys in unique key test";
  }
}

}  // namespace test
Ejemplo n.º 19
0
inline FTPoint FTBufferFontImpl::RenderI(const T* string, const int len,
                                         FTPoint position, FTPoint spacing,
                                         int renderMode)
{
    const float padding = 3.0f;
    int width, height, texWidth, texHeight;
    int cacheIndex = -1;
    bool inCache = false;

    // Protect blending functions, GL_BLEND and GL_TEXTURE_2D
    glPushAttrib(GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT);

    // Protect glPixelStorei() calls
    glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);

    glEnable(GL_TEXTURE_2D);
    if ((renderMode & FTGL::RENDER_NOBLEND) == 0) {
      glEnable(GL_BLEND);
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE
    }

    // Search whether the string is already in a texture we uploaded
    for(int n = 0; n < BUFFER_CACHE_SIZE; n++)
    {
        int i = (lastString + n + BUFFER_CACHE_SIZE) % BUFFER_CACHE_SIZE;

        if(stringCache[i] && !StringCompare(stringCache[i], string, len))
        {
            cacheIndex = i;
            inCache = true;
            break;
        }
    }

    // If the string was not found, we need to put it in the cache and compute
    // its new bounding box.
    if(!inCache)
    {
        // FIXME: this cache is not very efficient. We should first expire
        // strings that are not used very often.
        cacheIndex = lastString;
        lastString = (lastString + 1) % BUFFER_CACHE_SIZE;

        if(stringCache[cacheIndex])
        {
            free(stringCache[cacheIndex]);
        }
        // FIXME: only the first N bytes are copied; we want the first N chars.
        stringCache[cacheIndex] = StringCopy(string, len);
        bboxCache[cacheIndex] = BBox(string, len, FTPoint(), spacing);
    }

    FTBBox bbox = bboxCache[cacheIndex];

    width = static_cast<int>(bbox.Upper().X() - bbox.Lower().X()
                              + padding + padding + 0.5);
    height = static_cast<int>(bbox.Upper().Y() - bbox.Lower().Y()
                               + padding + padding + 0.5);

    texWidth = NextPowerOf2(width);
    texHeight = NextPowerOf2(height);

    glBindTexture(GL_TEXTURE_2D, idCache[cacheIndex]);

    // If the string was not found, we need to render the text in a new
    // texture buffer, then upload it to the OpenGL layer.
    if(!inCache)
    {
        buffer->Size(texWidth, texHeight);
        buffer->Pos(FTPoint(padding, padding) - bbox.Lower());

        advanceCache[cacheIndex] =
              FTFontImpl::Render(string, len, FTPoint(), spacing, renderMode);

        glBindTexture(GL_TEXTURE_2D, idCache[cacheIndex]);

        glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
        glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

        /* TODO: use glTexSubImage2D later? */
        glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texWidth, texHeight, 0,
                     GL_ALPHA, GL_UNSIGNED_BYTE, (GLvoid *)buffer->Pixels());

        buffer->Size(0, 0);
    }

    FTPoint low = position + bbox.Lower();
    FTPoint up = position + bbox.Upper();

    glBegin(GL_QUADS);
        glNormal3f(0.0f, 0.0f, 1.0f);
        glTexCoord2f(padding / texWidth,
                     (texHeight - height + padding) / texHeight);
        glVertex2f(low.Xf(), up.Yf());
        glTexCoord2f(padding / texWidth,
                     (texHeight - padding) / texHeight);
        glVertex2f(low.Xf(), low.Yf());
        glTexCoord2f((width - padding) / texWidth,
                     (texHeight - padding) / texHeight);
        glVertex2f(up.Xf(), low.Yf());
        glTexCoord2f((width - padding) / texWidth,
                     (texHeight - height + padding) / texHeight);
        glVertex2f(up.Xf(), up.Yf());
    glEnd();

    glPopClientAttrib();
    glPopAttrib();

    return position + advanceCache[cacheIndex];
}