⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 texture.cpp

📁 The goal of this project is to explore the idea of point-based radiosity, which is a shooting radio
💻 CPP
字号:
/*+-------------------------------------------------------------------
  Ben Landon
  CSCI E-235
  
  Final Project

  Texture.cpp

*/

#include "gl_common.h"
#include "Texture.hpp"

Texture::Texture (unsigned int width, unsigned int height)
    : m_width(width), m_height(height)
{
    glGenTextures(1, &m_texture_id);
}

Texture::~Texture()
{
    glDeleteTextures(1, &m_texture_id);
}

void Texture::make_current (void) const
{
    glBindTexture(GL_TEXTURE_2D, m_texture_id);
    GLenum err = glGetError();
}

GrayscaleTexture::GrayscaleTexture (Map_of<float>& gray_map)
    : Texture(gray_map.width(), gray_map.height())
{    
    // FIXME - Ensure the width and height 
    // these are powers of two.
    unsigned int width = gray_map.width();
    unsigned int height = gray_map.height();
    
    m_grayscale_texels = new float[width * height];
    unsigned int counter = 0;    
	
    for (int j = 0; j < (int)height; j++)
    {
        for (int i = 0; i < (int)width; i++)
        {            
            m_grayscale_texels[counter++] = gray_map.get(i, j);       
        }
    }

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glBindTexture(GL_TEXTURE_2D, m_texture_id);


    GLenum err = glGetError();

    if (err != GL_NO_ERROR)
	throw TextureException();

    int rc = gluBuild2DMipmaps(GL_TEXTURE_2D, 1, width, height, 
			       GL_LUMINANCE, GL_FLOAT, m_grayscale_texels);

    if (rc != 0)
	throw TextureException();

}
    
GrayscaleTexture::~GrayscaleTexture ()
{
    if (m_grayscale_texels)
    {
	delete [] m_grayscale_texels;
	m_grayscale_texels = NULL;
    }
}


/*+-------------------------------------------------------------------
  GrayscaleTexture::mipmap_texels

  Get the mipmap texels cooresponding to the specified texture level.

*/
void GrayscaleTexture::mipmap_texels (int mipmap_level, float* texels) const
{
    glBindTexture(GL_TEXTURE_2D, m_texture_id);


    int rc = gluBuild2DMipmaps(GL_TEXTURE_2D, 1, m_width, m_height, 
			       GL_LUMINANCE, GL_FLOAT, m_grayscale_texels);

    if (rc != 0)
	throw TextureException();

    glGetTexImage(GL_TEXTURE_2D, 
		  mipmap_level, 
		  GL_LUMINANCE, 
		  GL_FLOAT, 
		  texels);
    
    GLenum err = glGetError();

    if (err != GL_NO_ERROR)
        throw TextureException();
}


/*+-------------------------------------------------------------------
  GrayscaleTexture::get_mipmap_dimensions 

*/
void GrayscaleTexture::get_mipmap_dimensions (int level, int& width, int& height) const
{
    width = m_width >> level;
    height = m_height >> level;
}


/*+-------------------------------------------------------------------
  GrayscaleTexture::mipmap_level 

  Compute the mipmap level that corresponds to the given width and height
  A return value of -1 means that no mipmap level corresponds to this width
  and height.

*/
int GrayscaleTexture::mipmap_level (unsigned int width, unsigned int height) const
{
    if (width > m_width || height > m_height)
	return -1;
    
    if (width == m_width && height == m_height)
	return 0;

    unsigned int count = 1;
    unsigned int computed_width = m_width;
    unsigned int computed_height = m_height;

    while (computed_height > 0 && computed_height > 0)
    {
	computed_height >>= 1;
	computed_width >>= 1;

	if ((width == computed_width) && (height == computed_height))
	    return count;
	
	else
	    count++;
    }
    return -1;
}


/*+-------------------------------------------------------------------
  SceneTexture::components_per_pixel 

  This is the number of components in a given pixel 
  for a SceneTexture.  4 means that there are four float 
  values per pixel in the SceneTexture pixel array, in 
  RGBA order.
  
*/
int SceneTexture::components_per_pixel = 4; // RGBA

/*+-------------------------------------------------------------------
  SceneTexture constructor 

*/
SceneTexture::SceneTexture (int width, int height)
    : Texture(width, height)
{
    m_pixels = new float[components_per_pixel * width * height];
    
    if (!m_pixels)
	throw TextureException();

    this->clear();
}

/*+-------------------------------------------------------------------
  SceneTexture destructor
  
*/
SceneTexture::~SceneTexture ()
{
    if (m_pixels)
    {
	delete [] m_pixels;
	m_pixels = NULL;
    }
}


/*+-------------------------------------------------------------------
  SceneTexture::copy_into

  This method copies the data from this SceneTexture object 
  into the target SceneTexture.  If there is texture data in
  the target SceneTarget it is deleted.  

  The width and height of the target SceneTexture will be 
  set to the width and height of this SceneTexture object.
  

*/
void SceneTexture::copy_into (SceneTexture& target)
{
    target.clear();

    if (m_pixels)
    {
	size_t array_size = components_per_pixel * m_width * m_height;
	target.m_pixels = new float[array_size];

	if (!target.m_pixels) 
	    throw TextureException();

	memcpy(target.m_pixels, m_pixels, array_size * sizeof(float));
    }
    
    target.m_width = m_width;
    target.m_height = m_height;
}


/*+-------------------------------------------------------------------
  subtract_texel

  Subtracts val from the texel at (u, v) and writes that value back to
  the texture.

*/
void SceneTexture::subtract (const Color& color_to_subtract, 
			     int u, int v, 
			     bool reset_gl_texture)
{
    assert(u >= 0 && u < (int)m_width);
    assert(v >= 0 && v < (int)m_height);

    Color texel;
    this->get(texel, u, v);

    float red = texel.red() - color_to_subtract.red();
    float green = texel.green() - color_to_subtract.green();
    float blue = texel.blue() - color_to_subtract.blue();

    // Clamp to zero 
    red = (red < 0.0f ? 0.0f : red);
    green = (green < 0.0f ? 0.0f : green);
    blue = (blue < 0.0f ? 0.0f : blue);
    
    texel.set(red, green, blue);
    this->set(texel, u, v);

    if (reset_gl_texture)
	this->tell_opengl();
}


/*+-------------------------------------------------------------------
  SceneTexture::add

  Add a color to a texel at a given position.  Clamp at [0, 1].
  
*/
void SceneTexture::add (const Color& color_to_add, 
			int u, int v, 
			bool reset_gl_texture)
{
    float red_to_add = color_to_add.red();
    float green_to_add = color_to_add.green();
    float blue_to_add = color_to_add.blue();
    
    Color existing_color;
    this->get(existing_color, u, v);

    float red = existing_color.r() + red_to_add;
    float green = existing_color.g() + green_to_add;
    float blue = existing_color.g() + blue_to_add;

    // Clamp to zero 
    red = (red < 0.0f ? 0.0f : red);
    green = (green < 0.0f ? 0.0f : green);
    blue = (blue < 0.0f ? 0.0f : blue);
    
    // Clamp to one 
    red = (red > 1.0f ? 1.0f : red);
    green = (green > 1.0f ? 1.0f : green);
    blue = (blue > 1.0f ? 1.0f : blue);

    Color texel(red, green, blue);
    this->set(texel, u, v);

    if (reset_gl_texture)
	this->tell_opengl();
}

/*+-------------------------------------------------------------------
  SceneTexture::clear
  
  Clears all of the texels to zero.  This is currently done by memset,
  which may not be the right thing to do.  Maybe MMX or SSE can be used
  eventually to optimize this.

*/
void SceneTexture::clear (void)
{
    if (m_pixels)
    {
        for (int i = 0; i < (int)m_width; i++)
        {
            for (int j = 0; j < (int)m_height; j++)
            {
                this->set(black, i, j);
            }
        }
    }
}


/*+-------------------------------------------------------------------
  SceneTexture::set (method)

  Sets the texel at (u, v) to the color specified.

  This method does no bounds checking so it is up to 
  the calling code to ensure that that (u, v) are valid
  texture coordinates for this SceneTexture object.

*/
void SceneTexture::set (const Color& color, int u, int v)
{
    if (!m_pixels)
	throw TextureException();

    unsigned int offset = components_per_pixel * (v * m_width + u);

    m_pixels[offset] = color.r();
    m_pixels[offset + 1] = color.g();
    m_pixels[offset + 2] = color.b();
    m_pixels[offset + 3] = color.a();
}

/*+-------------------------------------------------------------------
  SceneTexture::get_brightest_texel 

  This can be optimized with mipmaps eventually.

*/
void SceneTexture::get_brightest_texel (int& u, int& v, Color& c) const 
{
    int brightest_u = 0;
    int brightest_v = 0;
    Color brightest_color;

    // Use the first texel as the brightest.  
    // This corresponds to (u, v) of (0.0)

    brightest_color.set_from_array(m_pixels, 4);

    for (int i = 0; i < (int)m_width; i++)
    {
	for (int j = 0; j < (int)m_height; j++)
	{
	    Color temp_color;
	    unsigned int offset = get_pixel_offset(i, j);
	    temp_color.set_from_array(&m_pixels[offset],4);
	    
	    float lum1 = temp_color.sum();

	    float lum2 = brightest_color.sum();

	    if (lum1 > lum2)
	    {
		brightest_u = i;
		brightest_v = j;
		brightest_color = temp_color;
	    }
	}
    }

    c = brightest_color;
    u = brightest_u;
    v = brightest_v;
}

    
/*+-------------------------------------------------------------------
  SceneTexture::get_texel_sum

  Sum the texels in this texture.  This is 
  the sum over all texels or (R + G + B) * A

*/
float SceneTexture::get_texel_sum (void) const
{
    float texture_sum  = 0.0f;
    Color temp_color;

    for (int i = 0; i < (int)m_width; i++)
    {
	for (int j = 0; j < (int)m_height; j++)
	{
	    this->get(temp_color, i, j);
	    texture_sum += temp_color.sum();
	}
    }

    return texture_sum;
}


/*+-------------------------------------------------------------------
  SceneTexture::get

*/    
void SceneTexture::get (Color& color, int u, int v) const
{
    assert(u >= 0 && u < (int)m_width);
    assert(v >= 0 && v < (int)m_height);
    assert(m_pixels != NULL);

    unsigned int offset = get_pixel_offset(u, v);
    
    color.set_from_array(&m_pixels[offset], 4);
}


/*+-------------------------------------------------------------------
  SceneTexture::delete_texture_data (private method)

  This method is used to discard existing texture data.
  
*/
void SceneTexture::delete_texture_data (void)
{
    // FIXME - Should I worry about what happens if
    // the texels are currently be used by OpenGL.

    if (m_pixels)
    {
	delete [] m_pixels;
	m_pixels = NULL;
	m_width = 0;
	m_height = 0;
    }
}

// Tell OpenGL about the texels in this texture object.
void SceneTexture::tell_opengl (void)
{

    glBindTexture(GL_TEXTURE_2D, m_texture_id);

    int rc = gluBuild2DMipmaps(GL_TEXTURE_2D, 
			       components_per_pixel, 
			       m_width, 
			       m_height, 
			       GL_RGBA, GL_FLOAT, 
			       m_pixels);
    
    GLenum err = glGetError();
    if (err != GL_NO_ERROR)
    {
        const GLubyte* str = gluErrorString(err);
        throw TextureException();
    }
}


/*+-------------------------------------------------------------------
  SceneTextures::set_texels 

*/
void SceneTexture::set_texels (float* texels, unsigned int num_texels)
{
    assert(texels != NULL);
    memcpy(m_pixels, texels, num_texels * sizeof(float));
}

/*+-------------------------------------------------------------------
  SceneTextures::normalize

*/
void SceneTexture::normalize (void)
{
    // Go through the texture and renormalize such that the
    // brightest texel has one in a particular channel.

    float max_red = 0.0f;
    float max_green = 0.0f;
    float max_blue = 0.0f;

    unsigned int max_texel_index = m_width * m_height;

    assert(components_per_pixel >= 3);
    for (unsigned index = 0; 
         index < max_texel_index; 
         index += components_per_pixel)
    {
        float red = m_pixels[index];
        float green = m_pixels[index + 1];
        float blue = m_pixels[index + 2];

        if (red > max_red)
            max_red = red;
        
        if (green > max_green)
            max_green = green;

        if (blue > max_blue)
            max_blue = blue;
    }

    float max_val = max(max_red, max(max_green, max_blue));
    if (max_val > 1.0f)
    {
        for (unsigned index = 0; index < max_texel_index; index ++)
        {
            m_pixels[index] = m_pixels[index]/max_val;
        }
    }
}

void SceneTexture::clone_into (SceneTexture& clone_target)
{
    size_t pixel_array_size = components_per_pixel * m_width * m_height;

    if (clone_target.m_width != m_width || 
        clone_target.m_height != m_height)
    {
        if (clone_target.m_pixels)
            delete [] (clone_target.m_pixels);
        
        clone_target.m_width = m_width;
        clone_target.m_height = m_height;

        
        
        clone_target.m_pixels = new float [pixel_array_size];
    }

    memcpy((clone_target.m_pixels), m_pixels, pixel_array_size);
    clone_target.m_texture_id = m_texture_id;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -