tavli

annotate src/image.cc @ 4:b41ceead1708

procedural playing field texture mask
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 25 Jun 2015 05:58:35 +0300
parents
children c2a2069a49ec
rev   line source
nuclear@4 1 #include <string.h>
nuclear@4 2 #include "opengl.h"
nuclear@4 3 #include "image.h"
nuclear@4 4 #include "imago2.h"
nuclear@4 5
nuclear@4 6
nuclear@4 7 static unsigned int next_pow2(unsigned int x);
nuclear@4 8
nuclear@4 9 Image::Image()
nuclear@4 10 {
nuclear@4 11 width = height = tex_width = tex_height = 0;
nuclear@4 12 pixels = 0;
nuclear@4 13 tex = 0;
nuclear@4 14 tex_valid = false;
nuclear@4 15 }
nuclear@4 16
nuclear@4 17 Image::~Image()
nuclear@4 18 {
nuclear@4 19 destroy();
nuclear@4 20 }
nuclear@4 21
nuclear@4 22 Image::Image(const Image &img)
nuclear@4 23 {
nuclear@4 24 pixels = 0;
nuclear@4 25 create(img.width, img.height, img.pixels);
nuclear@4 26 }
nuclear@4 27
nuclear@4 28 Image &Image::operator =(const Image &img)
nuclear@4 29 {
nuclear@4 30 if(&img != this) {
nuclear@4 31 create(img.width, img.height, img.pixels);
nuclear@4 32 }
nuclear@4 33 return *this;
nuclear@4 34 }
nuclear@4 35
nuclear@4 36 bool Image::create(int width, int height, unsigned char *pixels)
nuclear@4 37 {
nuclear@4 38 destroy();
nuclear@4 39
nuclear@4 40 try {
nuclear@4 41 unsigned char *tmp = new unsigned char[width * height * 3];
nuclear@4 42 this->pixels = tmp;
nuclear@4 43 this->width = width;
nuclear@4 44 this->height = height;
nuclear@4 45 }
nuclear@4 46 catch(...) {
nuclear@4 47 return false;
nuclear@4 48 }
nuclear@4 49
nuclear@4 50 if(pixels) {
nuclear@4 51 memcpy(this->pixels, pixels, width * height * 3);
nuclear@4 52 }
nuclear@4 53 return true;
nuclear@4 54 }
nuclear@4 55
nuclear@4 56 void Image::destroy()
nuclear@4 57 {
nuclear@4 58 delete [] pixels;
nuclear@4 59 pixels = 0;
nuclear@4 60 width = height = 0;
nuclear@4 61
nuclear@4 62 if(tex) {
nuclear@4 63 glDeleteTextures(1, &tex);
nuclear@4 64 tex = 0;
nuclear@4 65 tex_valid = false;
nuclear@4 66 }
nuclear@4 67 }
nuclear@4 68
nuclear@4 69 bool Image::load(const char *fname)
nuclear@4 70 {
nuclear@4 71 int xsz, ysz;
nuclear@4 72 unsigned char *pix = (unsigned char*)img_load_pixels(fname, &xsz, &ysz, IMG_FMT_RGB24);
nuclear@4 73 if(!pix) {
nuclear@4 74 return false;
nuclear@4 75 }
nuclear@4 76 return create(xsz, ysz, pix);
nuclear@4 77 }
nuclear@4 78
nuclear@4 79 unsigned int Image::texture() const
nuclear@4 80 {
nuclear@4 81 if(!pixels) {
nuclear@4 82 return 0;
nuclear@4 83 }
nuclear@4 84 if(!tex) {
nuclear@4 85 glGenTextures(1, &tex);
nuclear@4 86 }
nuclear@4 87
nuclear@4 88 if(!tex_valid) {
nuclear@4 89 tex_width = next_pow2(width);
nuclear@4 90 tex_height = next_pow2(height);
nuclear@4 91
nuclear@4 92 glBindTexture(GL_TEXTURE_2D, tex);
nuclear@4 93 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
nuclear@4 94 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
nuclear@4 95
nuclear@4 96 if(GLEW_SGIS_generate_mipmap) {
nuclear@4 97 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 1);
nuclear@4 98
nuclear@4 99 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_width, tex_height, 0, GL_RGB, GL_UNSIGNED_BYTE,
nuclear@4 100 width == tex_width && height == tex_height ? pixels : 0);
nuclear@4 101 if(width != tex_width || height != tex_height) {
nuclear@4 102 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels);
nuclear@4 103 }
nuclear@4 104 } else {
nuclear@4 105 gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, tex_width, tex_height, GL_RGB, GL_UNSIGNED_BYTE, pixels);
nuclear@4 106 }
nuclear@4 107
nuclear@4 108 if(GLEW_EXT_texture_filter_anisotropic) {
nuclear@4 109 static float max_aniso = -1.0;
nuclear@4 110
nuclear@4 111 if(max_aniso < 0.0) {
nuclear@4 112 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_aniso);
nuclear@4 113 printf("using anisotropic filtering: x%g\n", max_aniso);
nuclear@4 114 }
nuclear@4 115
nuclear@4 116 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_aniso);
nuclear@4 117 }
nuclear@4 118 tex_valid = true;
nuclear@4 119 }
nuclear@4 120 return tex;
nuclear@4 121 }
nuclear@4 122
nuclear@4 123 int Image::texture_width() const
nuclear@4 124 {
nuclear@4 125 return tex_width;
nuclear@4 126 }
nuclear@4 127
nuclear@4 128 int Image::texture_height() const
nuclear@4 129 {
nuclear@4 130 return tex_height;
nuclear@4 131 }
nuclear@4 132
nuclear@4 133 void Image::invalidate_texture()
nuclear@4 134 {
nuclear@4 135 tex_valid = false;
nuclear@4 136 }
nuclear@4 137
nuclear@4 138
nuclear@4 139 void clear_image(Image *img)
nuclear@4 140 {
nuclear@4 141 clear_image(img, 0, 0, 0);
nuclear@4 142 }
nuclear@4 143
nuclear@4 144 void clear_image(Image *img, float r, float g, float b)
nuclear@4 145 {
nuclear@4 146 if(!img->pixels) {
nuclear@4 147 return;
nuclear@4 148 }
nuclear@4 149
nuclear@4 150 unsigned char col[3];
nuclear@4 151 unsigned char *ptr = img->pixels;
nuclear@4 152 int npix = img->width * img->height;
nuclear@4 153
nuclear@4 154 col[0] = (int)(r * 255.0);
nuclear@4 155 col[1] = (int)(g * 255.0);
nuclear@4 156 col[2] = (int)(b * 255.0);
nuclear@4 157
nuclear@4 158 for(int i=0; i<npix; i++) {
nuclear@4 159 for(int j=0; j<3; j++) {
nuclear@4 160 ptr[j] = col[j];
nuclear@4 161 }
nuclear@4 162 ptr += 3;
nuclear@4 163 }
nuclear@4 164 }
nuclear@4 165
nuclear@4 166 bool combine_image(Image *dest, const Image *aimg, const Image *bimg, ImgCombine op, float t)
nuclear@4 167 {
nuclear@4 168 int xsz = dest->width;
nuclear@4 169 int ysz = dest->height;
nuclear@4 170 int npixels = xsz * ysz;
nuclear@4 171 int nbytes = npixels * 3;
nuclear@4 172 int tint = (int)(t * 255);
nuclear@4 173
nuclear@4 174 if(aimg->width != xsz || bimg->width != xsz || aimg->height != ysz || bimg->height != ysz) {
nuclear@4 175 return false;
nuclear@4 176 }
nuclear@4 177
nuclear@4 178 unsigned char *dptr = dest->pixels;
nuclear@4 179 const unsigned char *aptr = aimg->pixels;
nuclear@4 180 const unsigned char *bptr = bimg->pixels;
nuclear@4 181
nuclear@4 182 switch(op) {
nuclear@4 183 case IMG_OP_ADD:
nuclear@4 184 for(int i=0; i<nbytes; i++) {
nuclear@4 185 unsigned int x = *aptr++ + *bptr++;
nuclear@4 186 *dptr++ = x > 255 ? 255 : x;
nuclear@4 187 }
nuclear@4 188 break;
nuclear@4 189
nuclear@4 190 case IMG_OP_SUB:
nuclear@4 191 for(int i=0; i<nbytes; i++) {
nuclear@4 192 int x = (int)*aptr++ - (int)*bptr++;
nuclear@4 193 *dptr++ = x < 0 ? 0 : x;
nuclear@4 194 }
nuclear@4 195 break;
nuclear@4 196
nuclear@4 197 case IMG_OP_MUL:
nuclear@4 198 for(int i=0; i<nbytes; i++) {
nuclear@4 199 unsigned int x = ((unsigned int)*aptr++ * (unsigned int)*bptr++) >> 8;
nuclear@4 200 *dptr++ = x > 255 ? 255 : x;
nuclear@4 201 }
nuclear@4 202 break;
nuclear@4 203
nuclear@4 204 case IMG_OP_LERP:
nuclear@4 205 for(int i=0; i<nbytes; i++) {
nuclear@4 206 int x = (int)*aptr + ((((int)*bptr - (int)*aptr) * tint) >> 8);
nuclear@4 207 *dptr++ = x > 255 ? 255 : (x < 0 ? 0 : x);
nuclear@4 208 }
nuclear@4 209 break;
nuclear@4 210
nuclear@4 211 default:
nuclear@4 212 break;
nuclear@4 213 }
nuclear@4 214
nuclear@4 215 dest->invalidate_texture();
nuclear@4 216 return true;
nuclear@4 217 }
nuclear@4 218
nuclear@4 219 static unsigned int next_pow2(unsigned int x)
nuclear@4 220 {
nuclear@4 221 x--;
nuclear@4 222 x = (x >> 1) | x;
nuclear@4 223 x = (x >> 2) | x;
nuclear@4 224 x = (x >> 4) | x;
nuclear@4 225 x = (x >> 8) | x;
nuclear@4 226 x = (x >> 16) | x;
nuclear@4 227 return x + 1;
nuclear@4 228 }