Search code examples
javascriptloopstextures

How to dynamically and efficiently generate texture sizes and dimensions in powers of two


I've fleshed out a loop to dynamically generate texture sizes for each different view I have in a browser-based visualization using shaders. I know the minimum number of pixels I need in order to pass my values to the shaders; however I need to scale them up to a power of 2 size, and then make sure their x and y dimensions are also powers of two with a 1:1, 2:1, or 1:2 ratio. Right now my loop is infinite, and I suppose I will need to continue to increase the overall power of 2 pixel count until I reach a size that satisfies one of my ratios.

My question is: Is there a more efficient or direct way to achieve what I'm trying to do here?

var motifMinBufferSize = 80000;   
var bufferSize; // the total number of texels that will be in the computation buffers (must be a power of two) 
var dimensions;

function initValues() {

    bufferSize = setBufferSize();
    dimensions = setPositionsTextureSize();
}

function setBufferSize() {

    var buffer = motifMinBufferSize;

    // fill out the buffers to a power of two - necessary for the computation textures in the shaders
    var powCount = 1;
    var powOf2 = 2;
    while ( buffer > powOf2 ) {
        powOf2 *= 2;
        powCount++;
    }

    while ( buffer < powOf2 ) {
        buffer += 1;
    }
}

function setPositionsTextureSize() {

    var dimensions = {
        texWidth : null,
        texHeight : null
    };
    var foundDimensions = false;
    var powOf2 = 2;

    while (foundDimensions === false) {
        var candidateWidth = bufferSize/powOf2;
        if ( candidateWidth === powOf2 || candidateWidth/2 === powOf2 || candidateWidth*2 === powOf2 ) {
            dimensions.texWidth = candidateWidth;
            dimensions.textHeight = powOf2;
            foundDimensions = true;
        } else {
            powOf2 *= 2;
        }
    }
    return dimensions;

}

Solution

  • Your buffer must contain 2^n elements since both the width and height of the buffer are powers of two. The smallest n that satisfies the requirement of holding at least motifMinBufferSize elements is calculated using logarithms: n = Math.ceil(Math.log2(motifMinBufferSize)).

    Let's say height of the buffer is 2^h and the width of the buffer is 2^w. We know that w and h can differ by at most one (due to the restrictions on the ratio of the buffer dimensions). We also know that 2^n = 2^w * 2^h which means n = w + h. Since w and h differ by at most 1, they are both basically half of n. Therefore we can get:

    function getBufferDimensions(minBufferSize) {
      var n = Math.ceil(Math.log2(minBufferSize));
      var w = Math.ceil(n / 2);
      var h = n - w;
    
      return {
        width: Math.pow(2, w),
        height: Math.pow(2, h),
      };
    }