一个简单的能处理MIPMAP的类

//-------------------------------------------------------------------------
eiTexture::eiTexture(eiBool instance_type, eiBool mip_map_filter)
{
    format        
= NONE;
    type        
= SRC;
    m_width        
= 0;
    m_height    
= 0;
    instance    
= instance_type;
    use_mip_map    
= mip_map_filter;
    bits        
= NULL;
}

//-------------------------------------------------------------------------
eiTexture::~eiTexture()
{
}

//-------------------------------------------------------------------------
eiBool eiTexture::load(eiChar *file_name)
{
    CFile file;

    
if!file.Open( file_name, CFile::modeRead | CFile::shareDenyWrite ) )
    
{
        msger.print(
"Load texture failed.");    
        
return false;
    }


    BITMAPFILEHEADER bfhHeader;

    file.Read( 
&bfhHeader, sizeof(BITMAPFILEHEADER) );

    
if( bfhHeader.bfType != 0x4d42 )
    
{
        msger.print(
"Load texture failed.");
        
return false;
    }

    
    eiUInt uBmpInfoLen 
= (eiUInt) bfhHeader.bfOffBits - sizeof(BITMAPFILEHEADER);

    LPBITMAPINFOHEADER m_lpBMPHdr 
= (LPBITMAPINFOHEADER) new eiByte [ uBmpInfoLen ];

    eiUInt counts 
= file.Read(m_lpBMPHdr, uBmpInfoLen);

    
if(m_lpBMPHdr->biSize != sizeof(BITMAPINFOHEADER))
    
{
        msger.print(
"Texture format error.");
        
return false;
    }


    DWORD m_dwImageSize 
= m_lpBMPHdr->biSizeImage;

    
if(m_dwImageSize == 0)
    
{
        DWORD dwBytes 
= ((DWORD) m_lpBMPHdr->biWidth * m_lpBMPHdr->biBitCount) / 32;
        
        
if(((DWORD) m_lpBMPHdr->biWidth * m_lpBMPHdr->biBitCount) % 32)
        
{
            dwBytes
++;
        }


        dwBytes 
*= 4;

        m_dwImageSize 
= dwBytes * m_lpBMPHdr->biHeight; 
    }


    bits 
= (eiByte*new eiByte [ m_dwImageSize ];

    counts 
= file.Read(bits, m_dwImageSize);

    file.Close();

    m_width  
= m_lpBMPHdr->biWidth;
    m_height 
= m_lpBMPHdr->biHeight;

    delete []m_lpBMPHdr;

    format 
= BMP;

    normalize();

    inv_width    
= 1.0 / m_width;
    inv_height    
= 1.0 / m_height;

    
if(use_mip_map)
    
{
        make_mip_map();
    }


    
return true;
}

//-------------------------------------------------------------------------
eiVoid eiTexture::normalize()
{
    eiByte    
*pbits;
    eiInt    n_width,n_height;
    eiFloat dx,dy;
    eiColor color;

    pbits 
= bits;
    n_width 
= (eiInt) powf( 2, (eiInt) log2f( m_width ) + 1 );
    n_height 
= (eiInt) powf( 2, (eiInt) log2f( m_height ) + 1 );

    dx 
= (eiFloat) m_width / (eiFloat) n_width;
    dy 
= (eiFloat) m_height / (eiFloat) n_height;

    src.resize( n_width 
* n_height * 3 );

    std::vector
<eiByte>::iterator pbyPtr = src.begin();

    
for(eiInt j = 0 ; j < n_height ; j++)
    
{
        
for(eiInt i = 0 ; i < n_width ; i++)
        
{
            color 
= get_bilinear_color( pbits, i * dx, j * dy );

            pbyPtr[
0= (eiByte) ( color.b * 255 );
            pbyPtr[
1= (eiByte) ( color.g * 255 );
            pbyPtr[
2= (eiByte) ( color.r * 255 );

            pbyPtr 
+= 3;
        }

    }

    
    delete []pbits;
    bits 
= NULL;

    m_width 
= n_width;
    m_height 
= n_height;
}

//-------------------------------------------------------------------------
eiInt eiTexture::get_width()
{
    
return m_width;
}

//-------------------------------------------------------------------------
eiInt eiTexture::get_height()
{
    
return m_height;
}

//-------------------------------------------------------------------------
eiColorB eiTexture::get_color(eiByte *dibbits, eiInt x, eiInt y)
{
    eiColorB color;

    color.r 
= color.g = color.b = 0;

    
if(dibbits == NULL)
        
return color;

    
if(x < 0)
        x 
= 0;
    
if(x >= m_width)
        x 
= m_width - 1;
    
if(y < 0)
        y 
= 0;
    
if(y >= m_height)
        y 
= m_height - 1;

    eiByte 
*pbyPtr;

    pbyPtr 
= dibbits + (y * m_width + x) * 3;

    color.b 
= pbyPtr[0];
    color.g 
= pbyPtr[1];
    color.r 
= pbyPtr[2];

    
return color;
}

//-------------------------------------------------------------------------
eiColor eiTexture::get_bilinear_color(eiByte *dibbits, eiFloat x, eiFloat y)
{
    eiInt        u,v;

    u 
= (eiInt) x;
    v 
= (eiInt) y;

    
if( (eiFloat) u == x && (eiFloat) v == y )
    
{
        eiColorB clr 
= get_color(dibbits,u,v);
        
        
return newclr(    clr.r * EI_BYTE_2_FLOAT,
                        clr.g 
* EI_BYTE_2_FLOAT,
                        clr.b 
* EI_BYTE_2_FLOAT    );
    }


    eiFloat        du,dv,r1,g1,b1,r2,g2,b2;
    eiColorB    c1,c2,c3,c4;

    du 
= curve( x - u );
    dv 
= curve( y - v );

    c1 
= get_color(dibbits,u,v);
    c2 
= get_color(dibbits,u+1,v);
    c3 
= get_color(dibbits,u+1,v+1);
    c4 
= get_color(dibbits,u,v+1);

    r1 
= c1.r + (c2.r - c1.r) * du;
    g1 
= c1.g + (c2.g - c1.g) * du;
    b1 
= c1.b + (c2.b - c1.b) * du;

    r2 
= c4.r + (c3.r - c4.r) * du;
    g2 
= c4.g + (c3.g - c4.g) * du;
    b2 
= c4.b + (c3.b - c4.b) * du;

    r1 
= r1 + (r2 - r1) * dv;
    g1 
= g1 + (g2 - g1) * dv;
    b1 
= b1 + (b2 - b1) * dv;

    r1 
*= EI_BYTE_2_FLOAT;
    g1 
*= EI_BYTE_2_FLOAT;
    b1 
*= EI_BYTE_2_FLOAT;

    
return newclr(r1,g1,b1);
}

//-------------------------------------------------------------------------
eiColorB eiTexture::get_src_color(eiInt x, eiInt y)
{
    eiColorB color;

    color.r 
= color.g = color.b = 0;

    
if(src.empty())
        
return color;

    
if(x < 0)
        x 
= 0;
    
if(x >= m_width)
        x 
= m_width - 1;
    
if(y < 0)
        y 
= 0;
    
if(y >= m_height)
        y 
= m_height - 1;

    std::vector
<eiByte>::iterator pbyPtr;

    pbyPtr 
= src.begin() + (y * m_width + x) * 3;

    color.b 
= pbyPtr[0];
    color.g 
= pbyPtr[1];
    color.r 
= pbyPtr[2];

    
return color;
}

//-------------------------------------------------------------------------
eiColor eiTexture::get_src_bilinear_color(eiFloat x, eiFloat y)
{
    eiInt        u,v;

    u 
= (eiInt) x;
    v 
= (eiInt) y;

    
if( (eiFloat) u == x && (eiFloat) v == y )
    
{
        eiColorB clr 
= get_src_color(u,v);
        
        
return newclr(    clr.r * EI_BYTE_2_FLOAT,
                        clr.g 
* EI_BYTE_2_FLOAT,
                        clr.b 
* EI_BYTE_2_FLOAT    );
    }


    eiFloat        du,dv,r1,g1,b1,r2,g2,b2;
    eiColorB    c1,c2,c3,c4;

    du 
= curve( x - u );
    dv 
= curve( y - v );

    c1 
= get_src_color(u,v);
    c2 
= get_src_color(u+1,v);
    c3 
= get_src_color(u+1,v+1);
    c4 
= get_src_color(u,v+1);

    r1 
= c1.r + (c2.r - c1.r) * du;
    g1 
= c1.g + (c2.g - c1.g) * du;
    b1 
= c1.b + (c2.b - c1.b) * du;

    r2 
= c4.r + (c3.r - c4.r) * du;
    g2 
= c4.g + (c3.g - c4.g) * du;
    b2 
= c4.b + (c3.b - c4.b) * du;

    r1 
= r1 + (r2 - r1) * dv;
    g1 
= g1 + (g2 - g1) * dv;
    b1 
= b1 + (b2 - b1) * dv;

    r1 
*= EI_BYTE_2_FLOAT;
    g1 
*= EI_BYTE_2_FLOAT;
    b1 
*= EI_BYTE_2_FLOAT;

    
return newclr(r1,g1,b1);
}

//-------------------------------------------------------------------------
eiVoid eiTexture::blt(eiInt x1,eiInt y1,eiInt x2,eiInt y2,
                        eiInt width,eiInt height)
{
    eiInt    c1,c2,c3,c4;
    std::vector
<eiByte>::iterator    pbyPtr;

    
for( eiInt j = y1, mj = y2 ; j < (y1 + height) ; j += 2, mj++ )
    
{
        
for( eiInt i = x1, mi = x2 ; i < (x1 + width) ; i += 2, mi++ )
        
{
            pbyPtr 
= mip_map.begin() + j * m_width + i;
            c1 
= pbyPtr[0];
            c2 
= pbyPtr[1];

            pbyPtr 
+= m_width;
            c3 
= pbyPtr[0];
            c4 
= pbyPtr[1];

            pbyPtr 
= mip_map.begin() + mj * m_width + mi;
            pbyPtr[
0= (eiByte) ( (eiFloat) ( c1 + c2 + c3 + c4 ) * 0.25 );
        }

    }

}

//-------------------------------------------------------------------------
eiVoid eiTexture::bltB(eiInt x1,eiInt y1,eiInt x2,eiInt y2,
                        eiInt width,eiInt height)
{
    
if(width == 0 || height == 0)
        
return;

    eiInt width2,height2;

    width2 
= width / 2;
    height2 
= height / 2;

    blt( x1, y1, x2, y2, width, height);

    bltB( x2, y2, x2 
/ 2, y2 / 2, width2, height2 );
}

//-------------------------------------------------------------------------
eiVoid eiTexture::bltG(eiInt x1,eiInt y1,eiInt x2,eiInt y2,
                        eiInt width,eiInt height)
{
    
if(width == 0 || height == 0)
        
return;

    eiInt width2,height2;

    width2 
= width / 2;
    height2 
= height / 2;

    blt( x1, y1, x2, y2, width, height);

    bltG( x2, y2, x2 
/ 2, y2, width2, height2 );
}

//-------------------------------------------------------------------------
eiVoid eiTexture::bltR(eiInt x1,eiInt y1,eiInt x2,eiInt y2,
                        eiInt width,eiInt height)
{
    
if(width == 0 || height == 0)
        
return;

    eiInt width2,height2;

    width2 
= width / 2;
    height2 
= height / 2;

    blt( x1, y1, x2, y2, width, height);

    bltR( x2, y2, x2, y2 
/ 2, width2, height2 );
}

//-------------------------------------------------------------------------
eiBool eiTexture::make_mip_map()
{
    
if(format == NONE || type == MIP_MAP)
        
return false;

    mip_map.resize( m_width 
* m_height );

    eiColorB                        c1,c2,c3,c4;
    eiFloat                            r,g,b;
    std::vector
<eiByte>::iterator    pbyPtr;
    eiInt                            width2,height2;

    width2 
= m_width / 2;
    height2 
= m_height / 2;

    
for( eiInt j = 0, mj = 0 ; j < m_height ; j += 2, mj++ )
    
{
        
for( eiInt i = 0, mi = 0 ; i < m_width ; i += 2, mi++ )
        
{
            c1 
= get_src_color( i , j );
            c2 
= get_src_color( i + 1 , j );
            c3 
= get_src_color( i + 1 , j + 1 );
            c4 
= get_src_color( i , j + 1 );

            b 
= (eiFloat) ( (eiInt) c1.b + (eiInt) c2.b + (eiInt) c3.b + (eiInt) c4.b ) * 0.25;
            g 
= (eiFloat) ( (eiInt) c1.g + (eiInt) c2.g + (eiInt) c3.g + (eiInt) c4.g ) * 0.25;
            r 
= (eiFloat) ( (eiInt) c1.r + (eiInt) c2.r + (eiInt) c3.r + (eiInt) c4.r ) * 0.25;

            
// i have not considered efficiency problem in precomputing progress

            
/* mip-map is built as follow :

            NEXT GREEN
            RED  BLUE    
*/


            pbyPtr 
= mip_map.begin() + ( mj + height2 ) * m_width + mi + width2;
            pbyPtr[
0= (eiByte) b;

            pbyPtr 
= mip_map.begin() + mj * m_width + mi + width2;
            pbyPtr[
0= (eiByte) g;

            pbyPtr 
= mip_map.begin() + ( mj + height2 ) * m_width + mi;
            pbyPtr[
0= (eiByte) r;
        }

    }


    bltB( width2, height2, m_width 
/ 4, m_height / 4, width2, height2 );
    bltG( width2, 
0, m_width / 40, width2, height2 );
    bltR( 
0, height2, 0, m_height / 4, width2, height2 );

    type 
= MIP_MAP;

    
return true;
}

//-------------------------------------------------------------------------
eiFloat eiTexture::get_bilinear(eiFloat x, eiFloat y)
{
    eiInt                            u,v;
    std::vector
<eiByte>::iterator    pbyPtr;

    u 
= (eiInt) x;
    v 
= (eiInt) y;

    
if( (eiFloat) u == x && (eiFloat) v == y )
    
{
        pbyPtr 
= mip_map.begin() + m_width * v + u;

        
return pbyPtr[0* EI_BYTE_2_FLOAT;
    }


    eiFloat        du,dv,r1,r2;
    eiByte        f1,f2,f3,f4;

    du 
= curve( x - u );
    dv 
= curve( y - v );

    pbyPtr 
= mip_map.begin() + m_width * v + u;
    f1 
= pbyPtr[0];
    f2 
= pbyPtr[1];

    pbyPtr 
+= m_width;
    f3 
= pbyPtr[1];
    f4 
= pbyPtr[0];

    r1 
= f1 + (f2 - f1) * du;

    r2 
= f4 + (f3 - f4) * du;

    r1 
= r1 + (r2 - r1) * dv;

    
return r1 * EI_BYTE_2_FLOAT;
}

//-------------------------------------------------------------------------
eiColor eiTexture::get_pixel(eiFloat x, eiFloat y, eiInt d)
{
    
if(src.empty() || ( type == MIP_MAP && mip_map.empty() ) )
        
return newclr();

    
if(d == 0)
    
{
        
return get_src_bilinear_color( x, y );
    }


    eiFloat b,g,r,scale;

    scale 
= 1 / powf( 2 , d );

    eiFloat mx,my,width2,height2;

    width2 
= m_width * scale;
    height2 
= m_height * scale;
    mx 
= x * scale;
    my 
= y * scale;

    b 
= get_bilinear( width2 + mx , height2 + my );

    g 
= get_bilinear( width2 + mx , my );

    r 
= get_bilinear( mx , height2 + my );

    
return newclr(r,g,b);
}

//-------------------------------------------------------------------------
eiColor eiTexture::lookup(const eiPlane& uv)
{
    
return get_pixel(uv.x, uv.y, uv.z, uv.w);
}

//-------------------------------------------------------------------------
eiColor eiTexture::get_pixel(eiFloat x, eiFloat y, eiFloat dx, eiFloat dy)
{
    x 
*= m_width;
    y 
*= m_height;

    
if( type == SRC || ( dx == 0.0 && dy == 0.0 ) )
    
{
        
//maybe shading for raytracing, do not use mip-map

        
return get_src_bilinear_color( x, y );
    }


    dx 
*= m_width;
    dy 
*= m_height;

    eiFloat d;
    eiInt    di;
    eiColor    c1,c2;

    d 
= max(dx,dy);

    d 
= log2f(d);
    di 
= (eiInt) d;
    d 
= d - (eiFloat) di;

    c1 
= get_pixel( x, y, di );
    c2 
= get_pixel( x, y, di + 1 );

    
return mixclr( c1, c2, d );
}

//-------------------------------------------------------------------------
原文地址:https://www.cnblogs.com/len3d/p/188838.html