OsdGLPtexMipmapTexture *
OsdGLPtexMipmapTexture::Create(PtexTexture * reader, int maxLevels)
{
    OsdGLPtexMipmapTexture * result = NULL;

    GLint maxNumPages = 0;
    glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &maxNumPages);

    // Read the ptexture data and pack the texels
    OsdPtexMipmapTextureLoader loader(reader, maxNumPages, maxLevels);

    // Setup GPU memory
    int numFaces = loader.GetNumFaces();

    GLuint layout = genTextureBuffer(GL_R16I,
                                     numFaces * 6 * sizeof(GLshort),
                                     loader.GetLayoutBuffer());

    GLenum format, type;
    switch (reader->dataType()) {
        case Ptex::dt_uint16 : type = GL_UNSIGNED_SHORT; break;
        case Ptex::dt_float  : type = GL_FLOAT; break;
        case Ptex::dt_half   : type = GL_HALF_FLOAT; break;
        default              : type = GL_UNSIGNED_BYTE; break;
    }

    switch (reader->numChannels()) {
        case 1 : format = GL_RED; break;
        case 2 : format = GL_RG; break;
        case 3 : format = GL_RGB; break;
        case 4 : format = GL_RGBA; break;
        default: format = GL_RED; break;
    }

    // actual texels texture array
    GLuint texels;
    glGenTextures(1, &texels);
    glBindTexture(GL_TEXTURE_2D_ARRAY, texels);

    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glTexImage3D(GL_TEXTURE_2D_ARRAY, 0,
                 (type == GL_FLOAT) ? GL_RGBA32F : GL_RGBA,
                 loader.GetPageWidth(),
                 loader.GetPageHeight(),
                 loader.GetNumPages(),
                 0, format, type,
                 loader.GetTexelBuffer());

//    loader.ClearBuffers();

    // Return the Osd Ptexture object
    result = new OsdGLPtexMipmapTexture;

    result->_width = loader.GetPageWidth();
    result->_height = loader.GetPageHeight();
    result->_depth = loader.GetNumPages();

    result->_format = format;

    result->_layout = layout;
    result->_texels = texels;

    return result;
}
OsdGLPtexTexture *
OsdGLPtexTexture::Create(PtexTexture * reader,
                      unsigned long int targetMemory,
                      int gutterWidth,
                      int pageMargin) {

    OsdGLPtexTexture * result = NULL;

    // Read the ptexture data and pack the texels
    OsdPtexTextureLoader ldr(reader, gutterWidth, pageMargin);

    unsigned long int nativeSize = ldr.GetNativeUncompressedSize(),
           targetSize = targetMemory;

    if (targetSize != 0 && targetSize != nativeSize)
        ldr.OptimizeResolution(targetSize);

    GLint maxnumpages = 0;
    glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &maxnumpages);

    ldr.OptimizePacking(maxnumpages);

    if (!ldr.GenerateBuffers())
        return result;

    // Setup GPU memory
    unsigned long int nfaces = ldr.GetNumBlocks();

    GLuint pages = genTextureBuffer(GL_R32I,
                                    nfaces * sizeof(GLint),
                                    ldr.GetIndexBuffer());

    GLuint layout = genTextureBuffer(GL_RGBA32F,
                                     nfaces * 4 * sizeof(GLfloat),
                                     ldr.GetLayoutBuffer());

    GLenum format, type;
    switch (reader->dataType()) {
        case Ptex::dt_uint16 : type = GL_UNSIGNED_SHORT; break;
        case Ptex::dt_float  : type = GL_FLOAT; break;
        case Ptex::dt_half   : type = GL_HALF_FLOAT; break;
        default              : type = GL_UNSIGNED_BYTE; break;
    }

    switch (reader->numChannels()) {
        case 1 : format = GL_RED; break;
        case 2 : format = GL_RG; break;
        case 3 : format = GL_RGB; break;
        case 4 : format = GL_RGBA; break;
        default: format = GL_RED; break;
    }

    // actual texels texture array
    GLuint texels;
    glGenTextures(1, &texels);
    glBindTexture(GL_TEXTURE_2D_ARRAY, texels);

    // XXXX for the time being, filtering is off - once cross-patch filtering
    // is in place, we will use glGenSamplers to dynamically access these settings.
    if (gutterWidth > 0) {
        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    } else {
        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    }
    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glTexImage3D(GL_TEXTURE_2D_ARRAY, 0,
                 (type == GL_FLOAT) ? GL_RGBA32F : GL_RGBA,
                 ldr.GetPageSize(),
                 ldr.GetPageSize(),
                 ldr.GetNumPages(),
                 0, format, type,
                 ldr.GetTexelBuffer());

    ldr.ClearBuffers();

    // Return the Osd Ptexture object
    result = new OsdGLPtexTexture;

    result->_width = ldr.GetPageSize();
    result->_height = ldr.GetPageSize();
    result->_depth = ldr.GetNumPages();

    result->_format = format;

    result->_pages = pages;
    result->_layout = layout;
    result->_texels = texels;

    return result;
}
D3D11PtexTexture *
D3D11PtexTexture::Create(ID3D11DeviceContext *deviceContext,
                         PtexTexture * reader,
                         unsigned long int targetMemory,
                         int gutterWidth,
                         int pageMargin) {

    D3D11PtexTexture * result = NULL;

    // Read the ptex data and pack the texels
    PtexTextureLoader ldr(reader, gutterWidth, pageMargin);

    unsigned long int nativeSize = ldr.GetNativeUncompressedSize(),
           targetSize = targetMemory;

    if (targetSize != 0 && targetSize != nativeSize)
        ldr.OptimizeResolution(targetSize);

    int maxnumpages = D3D10_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION;
    ldr.OptimizePacking(maxnumpages);

    if (!ldr.GenerateBuffers())
        return result;

    // Setup GPU memory
    unsigned long int nfaces = ldr.GetNumBlocks();

    ID3D11Buffer *pages = genTextureBuffer(deviceContext,
                                           nfaces * sizeof(int),
                                           ldr.GetIndexBuffer());

    ID3D11Buffer *layout = genTextureBuffer(deviceContext,
                                            nfaces * 4 * sizeof(float),
                                            ldr.GetLayoutBuffer());

    DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
    int bpp = 0;
    int numChannels = reader->numChannels();
    switch (reader->dataType()) {
    case Ptex::dt_uint16:
        switch (numChannels) {
        case 1: format = DXGI_FORMAT_R16_UINT; break;
        case 2: format = DXGI_FORMAT_R16G16_UINT; break;
        case 3: assert(false); break;
        case 4: format = DXGI_FORMAT_R16G16B16A16_UINT; break;
        }
        bpp = numChannels * 2;
        break;
    case Ptex::dt_float:
        switch (numChannels) {
        case 1: format = DXGI_FORMAT_R32_FLOAT; break;
        case 2: format = DXGI_FORMAT_R32G32_FLOAT; break;
        case 3: format = DXGI_FORMAT_R32G32B32_FLOAT; break;
        case 4: format = DXGI_FORMAT_R32G32B32A32_FLOAT; break;
        }
        bpp = numChannels * 4;
        break;
    case Ptex::dt_half:
        switch (numChannels) {
        case 1: format = DXGI_FORMAT_R16_FLOAT; break;
        case 2: format = DXGI_FORMAT_R16G16_FLOAT; break;
        case 3:assert(false); break;
        case 4: format = DXGI_FORMAT_R16G16B16A16_FLOAT; break;
        }
        bpp = numChannels * 2;
        break;
    default:
        switch (numChannels) {
        case 1: format = DXGI_FORMAT_R8_UINT; break;
        case 2: format = DXGI_FORMAT_R8G8_UINT; break;
        case 3: assert(false); break;
        case 4: format = DXGI_FORMAT_R8G8B8A8_UINT; break;
        }
        bpp = numChannels;
        break;
    }

    // actual texels texture array
    D3D11_TEXTURE2D_DESC desc;
    desc.Width = ldr.GetPageSize();
    desc.Height = ldr.GetPageSize();
    desc.MipLevels = 1;
    desc.ArraySize = ldr.GetNumPages();
    desc.Format = format;
    desc.SampleDesc.Count = 1;
    desc.SampleDesc.Quality = 0;
    desc.Usage = D3D11_USAGE_DEFAULT;
    desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
    desc.CPUAccessFlags = 0;
    desc.MiscFlags = 0;

    D3D11_SUBRESOURCE_DATA initData;
    initData.pSysMem = ldr.GetTexelBuffer();
    initData.SysMemPitch = ldr.GetPageSize() * bpp;
    initData.SysMemSlicePitch = ldr.GetPageSize() * ldr.GetPageSize() * bpp;

    ID3D11Device *device;
    ID3D11Texture2D *texels;
    deviceContext->GetDevice(&device);
    HRESULT hr = device->CreateTexture2D(&desc, &initData, &texels);

    ldr.ClearBuffers();

    // Return the Osd PtexTexture object
    result = new D3D11PtexTexture;

    result->_width = ldr.GetPageSize();
    result->_height = ldr.GetPageSize();
    result->_depth = ldr.GetNumPages();

    result->_format = format;

    result->_pages = pages;
    result->_layout = layout;
    result->_texels = texels;

    return result;
}