tavli
changeset 4:b41ceead1708
procedural playing field texture mask
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 25 Jun 2015 05:58:35 +0300 |
parents | 94aff2ff1934 |
children | e48b40a3c82a |
files | src/board.cc src/board.h src/image.cc src/image.h src/object.cc src/object.h |
diffstat | 6 files changed, 419 insertions(+), 40 deletions(-) [+] |
line diff
1.1 --- a/src/board.cc Mon Jun 22 21:46:57 2015 +0300 1.2 +++ b/src/board.cc Thu Jun 25 05:58:35 2015 +0300 1.3 @@ -16,6 +16,9 @@ 1.4 1.5 bool Board::init() 1.6 { 1.7 + if(!generate_textures()) { 1.8 + return false; 1.9 + } 1.10 if(!generate()) { 1.11 return false; 1.12 } 1.13 @@ -57,65 +60,75 @@ 1.14 1.15 bool Board::generate() 1.16 { 1.17 + Mesh tmp; 1.18 Matrix4x4 xform; 1.19 1.20 obj.clear(); 1.21 1.22 - // generate bottom 1.23 - Mesh *bottom = new Mesh; 1.24 - gen_box(bottom, HSIZE, BOT_THICKNESS, HSIZE * 2.0); 1.25 - xform.set_translation(Vector3(0, -BOT_THICKNESS / 2.0, 0)); 1.26 - bottom->apply_xform(xform); 1.27 + for(int i=0; i<2; i++) { 1.28 + int sign = i * 2 - 1; 1.29 1.30 - Object *obottom = new Object; 1.31 - obottom->set_mesh(bottom); 1.32 - obj.push_back(obottom); 1.33 + // generate bottom 1.34 + Mesh *bottom = new Mesh; 1.35 + gen_box(bottom, HSIZE, BOT_THICKNESS, HSIZE * 2.0); 1.36 + xform.set_translation(Vector3(0, -BOT_THICKNESS / 2.0, 0)); 1.37 + bottom->apply_xform(xform); 1.38 1.39 + Object *obottom = new Object; 1.40 + obottom->set_mesh(bottom); 1.41 + obottom->xform().set_translation(Vector3(sign * (HSIZE / 2.0 + WALL_THICKNESS + HINGE_RAD * 0.25), 0, 0)); 1.42 + obottom->set_texture(img_field.texture()); 1.43 + obj.push_back(obottom); 1.44 1.45 - // generate the 4 sides 1.46 - Mesh *sides = new Mesh; 1.47 - gen_box(sides, WALL_THICKNESS, WALL_HEIGHT, VSIZE + WALL_THICKNESS * 2); 1.48 - xform.set_translation(Vector3(-(HSIZE + WALL_THICKNESS) / 2.0, 1.49 - WALL_HEIGHT / 2.0 - BOT_THICKNESS, 0)); 1.50 - sides->apply_xform(xform); 1.51 1.52 - Mesh tmp; 1.53 - gen_box(&tmp, WALL_THICKNESS, WALL_HEIGHT, VSIZE + WALL_THICKNESS * 2); 1.54 - xform.set_translation(Vector3((HSIZE + WALL_THICKNESS) / 2.0, 1.55 - WALL_HEIGHT / 2.0 - BOT_THICKNESS, 0)); 1.56 - tmp.apply_xform(xform); 1.57 - sides->append(tmp); 1.58 - tmp.clear(); 1.59 + // generate the 4 sides 1.60 + Mesh *sides = new Mesh; 1.61 + gen_box(sides, WALL_THICKNESS, WALL_HEIGHT, VSIZE + WALL_THICKNESS * 2); 1.62 + xform.set_translation(Vector3(-(HSIZE + WALL_THICKNESS) / 2.0, 1.63 + WALL_HEIGHT / 2.0 - BOT_THICKNESS, 0)); 1.64 + sides->apply_xform(xform); 1.65 1.66 - gen_box(&tmp, HSIZE, WALL_HEIGHT, WALL_THICKNESS); 1.67 - xform.set_translation(Vector3(0, WALL_HEIGHT / 2.0 - BOT_THICKNESS, 1.68 - (VSIZE + WALL_THICKNESS) / 2.0)); 1.69 - tmp.apply_xform(xform); 1.70 - sides->append(tmp); 1.71 - tmp.clear(); 1.72 + gen_box(&tmp, WALL_THICKNESS, WALL_HEIGHT, VSIZE + WALL_THICKNESS * 2); 1.73 + xform.set_translation(Vector3((HSIZE + WALL_THICKNESS) / 2.0, 1.74 + WALL_HEIGHT / 2.0 - BOT_THICKNESS, 0)); 1.75 + tmp.apply_xform(xform); 1.76 + sides->append(tmp); 1.77 + tmp.clear(); 1.78 1.79 - gen_box(&tmp, HSIZE, WALL_HEIGHT, WALL_THICKNESS); 1.80 - xform.set_translation(Vector3(0, WALL_HEIGHT / 2.0 - BOT_THICKNESS, 1.81 - -(VSIZE + WALL_THICKNESS) / 2.0)); 1.82 - tmp.apply_xform(xform); 1.83 - sides->append(tmp); 1.84 - tmp.clear(); 1.85 + gen_box(&tmp, HSIZE, WALL_HEIGHT, WALL_THICKNESS); 1.86 + xform.set_translation(Vector3(0, WALL_HEIGHT / 2.0 - BOT_THICKNESS, 1.87 + (VSIZE + WALL_THICKNESS) / 2.0)); 1.88 + tmp.apply_xform(xform); 1.89 + sides->append(tmp); 1.90 + tmp.clear(); 1.91 1.92 - Object *osides = new Object; 1.93 - osides->set_mesh(sides); 1.94 - obj.push_back(osides); 1.95 + gen_box(&tmp, HSIZE, WALL_HEIGHT, WALL_THICKNESS); 1.96 + xform.set_translation(Vector3(0, WALL_HEIGHT / 2.0 - BOT_THICKNESS, 1.97 + -(VSIZE + WALL_THICKNESS) / 2.0)); 1.98 + tmp.apply_xform(xform); 1.99 + sides->append(tmp); 1.100 + tmp.clear(); 1.101 + 1.102 + Object *osides = new Object; 1.103 + osides->set_mesh(sides); 1.104 + osides->xform() = obottom->xform(); 1.105 + obj.push_back(osides); 1.106 + 1.107 + } 1.108 1.109 1.110 // generate the hinges 1.111 Mesh *hinges = new Mesh; 1.112 gen_cylinder(hinges, HINGE_RAD, HINGE_HEIGHT, 10, 1, 1); 1.113 - xform.set_rotation(Vector3(M_PI / 2.0, 0, 0)); 1.114 - xform.translate(Vector3(0, VSIZE / 4.0, 0)); 1.115 + xform.reset_identity(); 1.116 + xform.translate(Vector3(0, WALL_HEIGHT - HINGE_RAD * 0.5, VSIZE / 4.0)); 1.117 + xform.rotate(Vector3(M_PI / 2.0, 0, 0)); 1.118 hinges->apply_xform(xform); 1.119 1.120 gen_cylinder(&tmp, HINGE_RAD, HINGE_HEIGHT, 10, 1, 1); 1.121 - xform.set_rotation(Vector3(M_PI / 2.0, 0, 0)); 1.122 - xform.translate(Vector3(0, -VSIZE / 4.0, 0)); 1.123 + xform.reset_identity(); 1.124 + xform.translate(Vector3(0, WALL_HEIGHT - HINGE_RAD * 0.5, -VSIZE / 4.0)); 1.125 + xform.rotate(Vector3(M_PI / 2.0, 0, 0)); 1.126 tmp.apply_xform(xform); 1.127 1.128 hinges->append(tmp); 1.129 @@ -127,3 +140,73 @@ 1.130 1.131 return true; 1.132 } 1.133 + 1.134 +static bool spike(float x, float y) 1.135 +{ 1.136 + x = fmod(x * 5.0, 1.0); 1.137 + return y < (x < 0.5 ? 2.0 * x : 2.0 - 2.0 * x); 1.138 +} 1.139 + 1.140 +static bool circle(float x, float y, float rad) 1.141 +{ 1.142 + x = fmod(x * 5.0, 1.0) - 0.5; 1.143 + y = (y - 0.65) * 5.0; 1.144 + float len = sqrt(x * x + y * y); 1.145 + return len < rad; 1.146 +} 1.147 + 1.148 +static bool diamond(float x, float y) 1.149 +{ 1.150 + return y >= (1.0 - (x < 0.5 ? 2.0 * x : 2.0 - 2.0 * x)) * 0.3333333 + 0.88; 1.151 +} 1.152 + 1.153 +static bool center_circle(float x, float y, float rad) 1.154 +{ 1.155 + x = x - 0.5; 1.156 + y = 1.0 - y; 1.157 + return sqrt(x * x + y * y) < rad; 1.158 +} 1.159 + 1.160 +bool Board::generate_textures() 1.161 +{ 1.162 + const int xsz = 512; 1.163 + const int ysz = 1024; 1.164 + 1.165 + img_field.create(xsz, ysz); 1.166 + clear_image(&img_field, 0, 0, 0); 1.167 + 1.168 + unsigned char *pptr = img_field.pixels; 1.169 + 1.170 + for(int i=0; i<ysz; i++) { 1.171 + float v = (float)i / (float)ysz; 1.172 + 1.173 + for(int j=0; j<xsz; j++) { 1.174 + float u = (float)j / (float)xsz; 1.175 + 1.176 + int r = 0, g = 0, b = 0; 1.177 + 1.178 + float x = u; 1.179 + float y = v < 0.5 ? v * 2.0 : 2.0 - v * 2.0; 1.180 + bool inside = false; 1.181 + 1.182 + inside |= (spike(x, y + 0.33333) && !spike(x, y + 0.4)) || 1.183 + (spike(x, y + 0.5) && !spike(x, y + 0.68)); 1.184 + inside |= (circle(x, y, 0.12) && !circle(x, y, 0.1)) || circle(x, y, 0.06); 1.185 + inside |= (diamond(x, y) && !diamond(x, y - 0.015)) || 1.186 + (diamond(x, y - 0.023) && !diamond(x, y - 0.028)); 1.187 + inside |= center_circle(x, y, 0.03); 1.188 + 1.189 + if(inside) { 1.190 + r = g = b = 255; 1.191 + } 1.192 + 1.193 + pptr[0] = r; 1.194 + pptr[1] = g; 1.195 + pptr[2] = b; 1.196 + pptr += 3; 1.197 + } 1.198 + } 1.199 + 1.200 + img_field.texture(); 1.201 + return true; 1.202 +}
2.1 --- a/src/board.h Mon Jun 22 21:46:57 2015 +0300 2.2 +++ b/src/board.h Thu Jun 25 05:58:35 2015 +0300 2.3 @@ -3,6 +3,7 @@ 2.4 2.5 #include <vector> 2.6 #include "object.h" 2.7 +#include "image.h" 2.8 2.9 #define NUM_SLOTS 24 2.10 #define MAX_PUCKS 30 2.11 @@ -15,7 +16,10 @@ 2.12 std::vector<Object*> obj; 2.13 Object *puck_obj; 2.14 2.15 + Image img_wood, img_field; 2.16 + 2.17 bool generate(); 2.18 + bool generate_textures(); 2.19 2.20 public: 2.21 Board();
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/src/image.cc Thu Jun 25 05:58:35 2015 +0300 3.3 @@ -0,0 +1,228 @@ 3.4 +#include <string.h> 3.5 +#include "opengl.h" 3.6 +#include "image.h" 3.7 +#include "imago2.h" 3.8 + 3.9 + 3.10 +static unsigned int next_pow2(unsigned int x); 3.11 + 3.12 +Image::Image() 3.13 +{ 3.14 + width = height = tex_width = tex_height = 0; 3.15 + pixels = 0; 3.16 + tex = 0; 3.17 + tex_valid = false; 3.18 +} 3.19 + 3.20 +Image::~Image() 3.21 +{ 3.22 + destroy(); 3.23 +} 3.24 + 3.25 +Image::Image(const Image &img) 3.26 +{ 3.27 + pixels = 0; 3.28 + create(img.width, img.height, img.pixels); 3.29 +} 3.30 + 3.31 +Image &Image::operator =(const Image &img) 3.32 +{ 3.33 + if(&img != this) { 3.34 + create(img.width, img.height, img.pixels); 3.35 + } 3.36 + return *this; 3.37 +} 3.38 + 3.39 +bool Image::create(int width, int height, unsigned char *pixels) 3.40 +{ 3.41 + destroy(); 3.42 + 3.43 + try { 3.44 + unsigned char *tmp = new unsigned char[width * height * 3]; 3.45 + this->pixels = tmp; 3.46 + this->width = width; 3.47 + this->height = height; 3.48 + } 3.49 + catch(...) { 3.50 + return false; 3.51 + } 3.52 + 3.53 + if(pixels) { 3.54 + memcpy(this->pixels, pixels, width * height * 3); 3.55 + } 3.56 + return true; 3.57 +} 3.58 + 3.59 +void Image::destroy() 3.60 +{ 3.61 + delete [] pixels; 3.62 + pixels = 0; 3.63 + width = height = 0; 3.64 + 3.65 + if(tex) { 3.66 + glDeleteTextures(1, &tex); 3.67 + tex = 0; 3.68 + tex_valid = false; 3.69 + } 3.70 +} 3.71 + 3.72 +bool Image::load(const char *fname) 3.73 +{ 3.74 + int xsz, ysz; 3.75 + unsigned char *pix = (unsigned char*)img_load_pixels(fname, &xsz, &ysz, IMG_FMT_RGB24); 3.76 + if(!pix) { 3.77 + return false; 3.78 + } 3.79 + return create(xsz, ysz, pix); 3.80 +} 3.81 + 3.82 +unsigned int Image::texture() const 3.83 +{ 3.84 + if(!pixels) { 3.85 + return 0; 3.86 + } 3.87 + if(!tex) { 3.88 + glGenTextures(1, &tex); 3.89 + } 3.90 + 3.91 + if(!tex_valid) { 3.92 + tex_width = next_pow2(width); 3.93 + tex_height = next_pow2(height); 3.94 + 3.95 + glBindTexture(GL_TEXTURE_2D, tex); 3.96 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 3.97 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 3.98 + 3.99 + if(GLEW_SGIS_generate_mipmap) { 3.100 + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 1); 3.101 + 3.102 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_width, tex_height, 0, GL_RGB, GL_UNSIGNED_BYTE, 3.103 + width == tex_width && height == tex_height ? pixels : 0); 3.104 + if(width != tex_width || height != tex_height) { 3.105 + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels); 3.106 + } 3.107 + } else { 3.108 + gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, tex_width, tex_height, GL_RGB, GL_UNSIGNED_BYTE, pixels); 3.109 + } 3.110 + 3.111 + if(GLEW_EXT_texture_filter_anisotropic) { 3.112 + static float max_aniso = -1.0; 3.113 + 3.114 + if(max_aniso < 0.0) { 3.115 + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_aniso); 3.116 + printf("using anisotropic filtering: x%g\n", max_aniso); 3.117 + } 3.118 + 3.119 + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_aniso); 3.120 + } 3.121 + tex_valid = true; 3.122 + } 3.123 + return tex; 3.124 +} 3.125 + 3.126 +int Image::texture_width() const 3.127 +{ 3.128 + return tex_width; 3.129 +} 3.130 + 3.131 +int Image::texture_height() const 3.132 +{ 3.133 + return tex_height; 3.134 +} 3.135 + 3.136 +void Image::invalidate_texture() 3.137 +{ 3.138 + tex_valid = false; 3.139 +} 3.140 + 3.141 + 3.142 +void clear_image(Image *img) 3.143 +{ 3.144 + clear_image(img, 0, 0, 0); 3.145 +} 3.146 + 3.147 +void clear_image(Image *img, float r, float g, float b) 3.148 +{ 3.149 + if(!img->pixels) { 3.150 + return; 3.151 + } 3.152 + 3.153 + unsigned char col[3]; 3.154 + unsigned char *ptr = img->pixels; 3.155 + int npix = img->width * img->height; 3.156 + 3.157 + col[0] = (int)(r * 255.0); 3.158 + col[1] = (int)(g * 255.0); 3.159 + col[2] = (int)(b * 255.0); 3.160 + 3.161 + for(int i=0; i<npix; i++) { 3.162 + for(int j=0; j<3; j++) { 3.163 + ptr[j] = col[j]; 3.164 + } 3.165 + ptr += 3; 3.166 + } 3.167 +} 3.168 + 3.169 +bool combine_image(Image *dest, const Image *aimg, const Image *bimg, ImgCombine op, float t) 3.170 +{ 3.171 + int xsz = dest->width; 3.172 + int ysz = dest->height; 3.173 + int npixels = xsz * ysz; 3.174 + int nbytes = npixels * 3; 3.175 + int tint = (int)(t * 255); 3.176 + 3.177 + if(aimg->width != xsz || bimg->width != xsz || aimg->height != ysz || bimg->height != ysz) { 3.178 + return false; 3.179 + } 3.180 + 3.181 + unsigned char *dptr = dest->pixels; 3.182 + const unsigned char *aptr = aimg->pixels; 3.183 + const unsigned char *bptr = bimg->pixels; 3.184 + 3.185 + switch(op) { 3.186 + case IMG_OP_ADD: 3.187 + for(int i=0; i<nbytes; i++) { 3.188 + unsigned int x = *aptr++ + *bptr++; 3.189 + *dptr++ = x > 255 ? 255 : x; 3.190 + } 3.191 + break; 3.192 + 3.193 + case IMG_OP_SUB: 3.194 + for(int i=0; i<nbytes; i++) { 3.195 + int x = (int)*aptr++ - (int)*bptr++; 3.196 + *dptr++ = x < 0 ? 0 : x; 3.197 + } 3.198 + break; 3.199 + 3.200 + case IMG_OP_MUL: 3.201 + for(int i=0; i<nbytes; i++) { 3.202 + unsigned int x = ((unsigned int)*aptr++ * (unsigned int)*bptr++) >> 8; 3.203 + *dptr++ = x > 255 ? 255 : x; 3.204 + } 3.205 + break; 3.206 + 3.207 + case IMG_OP_LERP: 3.208 + for(int i=0; i<nbytes; i++) { 3.209 + int x = (int)*aptr + ((((int)*bptr - (int)*aptr) * tint) >> 8); 3.210 + *dptr++ = x > 255 ? 255 : (x < 0 ? 0 : x); 3.211 + } 3.212 + break; 3.213 + 3.214 + default: 3.215 + break; 3.216 + } 3.217 + 3.218 + dest->invalidate_texture(); 3.219 + return true; 3.220 +} 3.221 + 3.222 +static unsigned int next_pow2(unsigned int x) 3.223 +{ 3.224 + x--; 3.225 + x = (x >> 1) | x; 3.226 + x = (x >> 2) | x; 3.227 + x = (x >> 4) | x; 3.228 + x = (x >> 8) | x; 3.229 + x = (x >> 16) | x; 3.230 + return x + 1; 3.231 +}
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/src/image.h Thu Jun 25 05:58:35 2015 +0300 4.3 @@ -0,0 +1,44 @@ 4.4 +#ifndef IMAGE_H_ 4.5 +#define IMAGE_H_ 4.6 + 4.7 +class Image { 4.8 +private: 4.9 + mutable int tex_width, tex_height; 4.10 + mutable unsigned int tex; 4.11 + mutable bool tex_valid; 4.12 + 4.13 +public: 4.14 + int width, height; 4.15 + unsigned char *pixels; 4.16 + 4.17 + Image(); 4.18 + ~Image(); 4.19 + 4.20 + Image(const Image &img); 4.21 + Image &operator =(const Image &img); 4.22 + 4.23 + bool create(int width, int height, unsigned char *pixels = 0); 4.24 + void destroy(); 4.25 + 4.26 + bool load(const char *fname); 4.27 + 4.28 + unsigned int texture() const; 4.29 + int texture_width() const; 4.30 + int texture_height() const; 4.31 + 4.32 + void invalidate_texture(); 4.33 +}; 4.34 + 4.35 +void clear_image(Image *img); 4.36 +void clear_image(Image *img, float r, float g, float b); 4.37 + 4.38 +enum ImgCombine { 4.39 + IMG_OP_ADD, 4.40 + IMG_OP_SUB, 4.41 + IMG_OP_MUL, 4.42 + IMG_OP_LERP 4.43 +}; 4.44 + 4.45 +bool combine_image(Image *dest, const Image *aimg, const Image *bimg, ImgCombine op = IMG_OP_LERP, float t = 0.5); 4.46 + 4.47 +#endif // IMAGE_H_
5.1 --- a/src/object.cc Mon Jun 22 21:46:57 2015 +0300 5.2 +++ b/src/object.cc Thu Jun 25 05:58:35 2015 +0300 5.3 @@ -4,6 +4,7 @@ 5.4 Object::Object() 5.5 { 5.6 mesh = 0; 5.7 + tex = 0; 5.8 } 5.9 5.10 Object::~Object() 5.11 @@ -31,10 +32,22 @@ 5.12 return mesh; 5.13 } 5.14 5.15 +void Object::set_texture(unsigned int tex) 5.16 +{ 5.17 + this->tex = tex; 5.18 +} 5.19 + 5.20 void Object::draw() const 5.21 { 5.22 if(!mesh) return; 5.23 5.24 + if(tex) { 5.25 + glBindTexture(GL_TEXTURE_2D, tex); 5.26 + glEnable(GL_TEXTURE_2D); 5.27 + } else { 5.28 + glDisable(GL_TEXTURE_2D); 5.29 + } 5.30 + 5.31 glMatrixMode(GL_MODELVIEW); 5.32 glPushMatrix(); 5.33 glMultTransposeMatrixf(matrix[0]); 5.34 @@ -42,6 +55,10 @@ 5.35 mesh->draw(); 5.36 5.37 glPopMatrix(); 5.38 + 5.39 + if(tex) { 5.40 + glDisable(GL_TEXTURE_2D); 5.41 + } 5.42 } 5.43 5.44 bool Object::intersect(const Ray &ray, HitPoint *hit) const
6.1 --- a/src/object.h Mon Jun 22 21:46:57 2015 +0300 6.2 +++ b/src/object.h Thu Jun 25 05:58:35 2015 +0300 6.3 @@ -8,6 +8,7 @@ 6.4 private: 6.5 Mesh *mesh; 6.6 Matrix4x4 matrix; 6.7 + unsigned int tex; 6.8 6.9 public: 6.10 Object(); 6.11 @@ -19,6 +20,8 @@ 6.12 void set_mesh(Mesh *m); 6.13 Mesh *get_mesh() const; 6.14 6.15 + void set_texture(unsigned int tex); 6.16 + 6.17 void draw() const; 6.18 6.19 bool intersect(const Ray &ray, HitPoint *hit) const;