nuclear@0: #include nuclear@0: #include nuclear@3: #ifdef _MSC_VER nuclear@3: #include nuclear@3: #else nuclear@0: #include nuclear@3: #endif nuclear@0: #include "opengl.h" nuclear@0: #include "image.h" nuclear@0: #include "imago2.h" nuclear@0: nuclear@0: nuclear@0: static unsigned int next_pow2(unsigned int x); nuclear@0: nuclear@0: Image::Image() nuclear@0: { nuclear@0: width = height = tex_width = tex_height = 0; nuclear@0: pixels = 0; nuclear@0: tex = 0; nuclear@0: tex_valid = false; nuclear@0: } nuclear@0: nuclear@0: Image::~Image() nuclear@0: { nuclear@0: destroy(); nuclear@0: } nuclear@0: nuclear@0: Image::Image(const Image &img) nuclear@0: { nuclear@0: pixels = 0; nuclear@0: create(img.width, img.height, img.pixels); nuclear@0: } nuclear@0: nuclear@0: Image &Image::operator =(const Image &img) nuclear@0: { nuclear@0: if(&img != this) { nuclear@0: create(img.width, img.height, img.pixels); nuclear@0: } nuclear@0: return *this; nuclear@0: } nuclear@0: nuclear@0: bool Image::create(int width, int height, unsigned char *pixels) nuclear@0: { nuclear@0: destroy(); nuclear@0: nuclear@0: try { nuclear@0: unsigned char *tmp = new unsigned char[width * height * 4]; nuclear@0: this->pixels = tmp; nuclear@0: this->width = width; nuclear@0: this->height = height; nuclear@0: } nuclear@0: catch(...) { nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: if(pixels) { nuclear@0: memcpy(this->pixels, pixels, width * height * 4); nuclear@0: } nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: void Image::destroy() nuclear@0: { nuclear@0: delete [] pixels; nuclear@0: pixels = 0; nuclear@0: width = height = 0; nuclear@0: nuclear@0: if(tex) { nuclear@0: glDeleteTextures(1, &tex); nuclear@0: tex = 0; nuclear@0: tex_valid = false; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: bool Image::load(const char *fname) nuclear@0: { nuclear@0: int xsz, ysz; nuclear@0: unsigned char *pix = (unsigned char*)img_load_pixels(fname, &xsz, &ysz, IMG_FMT_RGBA32); nuclear@0: if(!pix) { nuclear@0: return false; nuclear@0: } nuclear@0: return create(xsz, ysz, pix); nuclear@0: } nuclear@0: nuclear@0: bool Image::save(const char *fname) const nuclear@0: { nuclear@0: return img_save_pixels(fname, pixels, width, height, IMG_FMT_RGBA32) != -1; nuclear@0: } nuclear@0: nuclear@0: unsigned int Image::texture() const nuclear@0: { nuclear@0: if(!pixels) { nuclear@0: return 0; nuclear@0: } nuclear@0: if(!tex) { nuclear@0: glGenTextures(1, &tex); nuclear@0: } nuclear@0: nuclear@0: if(!tex_valid) { nuclear@0: tex_width = next_pow2(width); nuclear@0: tex_height = next_pow2(height); nuclear@0: nuclear@0: glBindTexture(GL_TEXTURE_2D, tex); nuclear@0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); nuclear@0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); nuclear@0: nuclear@0: if(GLEW_SGIS_generate_mipmap) { nuclear@0: glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 1); nuclear@0: nuclear@0: void *data = (width == tex_width && height == tex_height) ? pixels : 0; nuclear@0: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_width, tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); nuclear@0: if(!data) { nuclear@0: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); nuclear@0: } nuclear@0: } else { nuclear@0: gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, tex_width, tex_height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); nuclear@0: } nuclear@0: nuclear@0: if(GLEW_EXT_texture_filter_anisotropic) { nuclear@0: static float max_aniso = -1.0; nuclear@0: nuclear@0: if(max_aniso < 0.0) { nuclear@0: glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_aniso); nuclear@0: printf("using anisotropic filtering: x%g\n", max_aniso); nuclear@0: } nuclear@0: nuclear@0: glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_aniso); nuclear@0: } nuclear@0: tex_valid = true; nuclear@0: } nuclear@0: return tex; nuclear@0: } nuclear@0: nuclear@0: int Image::texture_width() const nuclear@0: { nuclear@0: return tex_width; nuclear@0: } nuclear@0: nuclear@0: int Image::texture_height() const nuclear@0: { nuclear@0: return tex_height; nuclear@0: } nuclear@0: nuclear@0: void Image::invalidate_texture() nuclear@0: { nuclear@0: tex_valid = false; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: void clear_image(Image *img) nuclear@0: { nuclear@0: clear_image(img, 0, 0, 0, 255); nuclear@0: } nuclear@0: nuclear@0: void clear_image(Image *img, float r, float g, float b, float a) nuclear@0: { nuclear@0: if(!img->pixels) { nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: unsigned char col[4]; nuclear@0: unsigned char *ptr = img->pixels; nuclear@0: int npix = img->width * img->height; nuclear@0: nuclear@0: col[0] = (int)(r * 255.0); nuclear@0: col[1] = (int)(g * 255.0); nuclear@0: col[2] = (int)(b * 255.0); nuclear@0: col[3] = (int)(a * 255.0); nuclear@0: nuclear@0: for(int i=0; ipixels) { nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: unsigned char alpha = (int)(a * 255.0); nuclear@0: unsigned char *ptr = img->pixels; nuclear@0: int npix = img->width * img->height; nuclear@0: nuclear@0: for(int i=0; iwidth; nuclear@0: int ysz = dest->height; nuclear@0: int npixels = xsz * ysz; nuclear@0: int nbytes = npixels * 4; nuclear@0: int tint = (int)(t * 255); nuclear@0: nuclear@0: if(aimg->width != xsz || bimg->width != xsz || aimg->height != ysz || bimg->height != ysz) { nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: unsigned char *dptr = dest->pixels; nuclear@0: const unsigned char *aptr = aimg->pixels; nuclear@0: const unsigned char *bptr = bimg->pixels; nuclear@0: nuclear@0: switch(op) { nuclear@0: case IMG_OP_ADD: nuclear@0: for(int i=0; i 255 ? 255 : x; nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: case IMG_OP_SUB: nuclear@0: for(int i=0; i> 8; nuclear@0: *dptr++ = x > 255 ? 255 : x; nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: case IMG_OP_LERP: nuclear@0: for(int i=0; i> 8); nuclear@0: *dptr++ = x > 255 ? 255 : (x < 0 ? 0 : x); nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: default: nuclear@0: break; nuclear@0: } nuclear@0: nuclear@0: dest->invalidate_texture(); nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: void convolve_horiz_image(Image *dest, float *kern, int ksz, float scale) nuclear@0: { nuclear@0: if((ksz & 1) == 0) { nuclear@0: fprintf(stderr, "%s: kernel size (%d) must be odd, skipping last value\n", __FUNCTION__, ksz); nuclear@0: --ksz; nuclear@0: } nuclear@0: if(scale == 0.0) { nuclear@0: // calculate scale factor nuclear@0: float sum = 0.0; nuclear@0: for(int i=0; iwidth * 4 * sizeof *buf); nuclear@0: unsigned char *sptr = dest->pixels; nuclear@0: nuclear@0: for(int i=0; iheight; i++) { nuclear@0: float *bptr = buf; nuclear@0: for(int j=0; jwidth * 4; j++) { nuclear@0: *bptr++ = (float)(sptr[j] / 255.0); nuclear@0: } nuclear@0: nuclear@0: for(int j=0; jwidth; j++) { nuclear@0: float col[] = {0, 0, 0, 0}; nuclear@0: nuclear@0: for(int k=0; k= dest->width) idx = dest->width - 1; nuclear@0: nuclear@0: col[0] += buf[idx * 4] * kern[k]; nuclear@0: col[1] += buf[idx * 4 + 1] * kern[k]; nuclear@0: col[2] += buf[idx * 4 + 2] * kern[k]; nuclear@0: col[3] += buf[idx * 4 + 3] * kern[k]; nuclear@0: } nuclear@0: nuclear@0: int ri = (int)(col[0] * scale * 255.0); nuclear@0: int gi = (int)(col[1] * scale * 255.0); nuclear@0: int bi = (int)(col[2] * scale * 255.0); nuclear@0: int ai = (int)(col[3] * scale * 255.0); nuclear@0: nuclear@0: sptr[0] = ri < 0 ? 0 : (ri > 255 ? 255 : ri); nuclear@0: sptr[1] = gi < 0 ? 0 : (gi > 255 ? 255 : gi); nuclear@0: sptr[2] = bi < 0 ? 0 : (bi > 255 ? 255 : bi); nuclear@0: sptr[3] = ai < 0 ? 0 : (ai > 255 ? 255 : ai); nuclear@0: sptr += 4; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: dest->invalidate_texture(); nuclear@0: } nuclear@0: nuclear@0: void convolve_vert_image(Image *dest, float *kern, int ksz, float scale) nuclear@0: { nuclear@0: if((ksz & 1) == 0) { nuclear@0: fprintf(stderr, "%s: kernel size (%d) must be odd, skipping last value\n", __FUNCTION__, ksz); nuclear@0: --ksz; nuclear@0: } nuclear@0: if(scale == 0.0) { nuclear@0: // calculate scale factor nuclear@0: float sum = 0.0; nuclear@0: for(int i=0; iheight * 4 * sizeof *buf); nuclear@0: unsigned char *sptr = dest->pixels; nuclear@0: nuclear@0: for(int i=0; iwidth; i++) { nuclear@0: float *bptr = buf; nuclear@0: sptr = dest->pixels + i * 4; nuclear@0: nuclear@0: for(int j=0; jheight; j++) { nuclear@0: for(int k=0; k<4; k++) { nuclear@0: *bptr++ = (float)(sptr[k] / 255.0); nuclear@0: } nuclear@0: sptr += dest->width * 4; nuclear@0: } nuclear@0: nuclear@0: sptr = dest->pixels + i * 4; nuclear@0: nuclear@0: for(int j=0; jheight; j++) { nuclear@0: float col[] = {0, 0, 0, 0}; nuclear@0: nuclear@0: for(int k=0; k= dest->height) idx = dest->height - 1; nuclear@0: nuclear@0: col[0] += buf[idx * 4] * kern[k]; nuclear@0: col[1] += buf[idx * 4 + 1] * kern[k]; nuclear@0: col[2] += buf[idx * 4 + 2] * kern[k]; nuclear@0: col[3] += buf[idx * 4 + 3] * kern[k]; nuclear@0: } nuclear@0: nuclear@0: int ri = (int)(col[0] * scale * 255.0); nuclear@0: int gi = (int)(col[1] * scale * 255.0); nuclear@0: int bi = (int)(col[2] * scale * 255.0); nuclear@0: int ai = (int)(col[3] * scale * 255.0); nuclear@0: nuclear@0: sptr[0] = ri < 0 ? 0 : (ri > 255 ? 255 : ri); nuclear@0: sptr[1] = gi < 0 ? 0 : (gi > 255 ? 255 : gi); nuclear@0: sptr[2] = bi < 0 ? 0 : (bi > 255 ? 255 : bi); nuclear@0: sptr[3] = ai < 0 ? 0 : (ai > 255 ? 255 : ai); nuclear@0: sptr += dest->width * 4; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: static unsigned int next_pow2(unsigned int x) nuclear@0: { nuclear@0: x--; nuclear@0: x = (x >> 1) | x; nuclear@0: x = (x >> 2) | x; nuclear@0: x = (x >> 4) | x; nuclear@0: x = (x >> 8) | x; nuclear@0: x = (x >> 16) | x; nuclear@0: return x + 1; nuclear@0: }