# HG changeset patch # User John Tsiombikas # Date 1435201115 -10800 # Node ID b41ceead170832f3d1d0091a90c254336de3524b # Parent 94aff2ff193476e18aea608a7422059ff5fec058 procedural playing field texture mask diff -r 94aff2ff1934 -r b41ceead1708 src/board.cc --- a/src/board.cc Mon Jun 22 21:46:57 2015 +0300 +++ b/src/board.cc Thu Jun 25 05:58:35 2015 +0300 @@ -16,6 +16,9 @@ bool Board::init() { + if(!generate_textures()) { + return false; + } if(!generate()) { return false; } @@ -57,65 +60,75 @@ bool Board::generate() { + Mesh tmp; Matrix4x4 xform; obj.clear(); - // generate bottom - Mesh *bottom = new Mesh; - gen_box(bottom, HSIZE, BOT_THICKNESS, HSIZE * 2.0); - xform.set_translation(Vector3(0, -BOT_THICKNESS / 2.0, 0)); - bottom->apply_xform(xform); + for(int i=0; i<2; i++) { + int sign = i * 2 - 1; - Object *obottom = new Object; - obottom->set_mesh(bottom); - obj.push_back(obottom); + // generate bottom + Mesh *bottom = new Mesh; + gen_box(bottom, HSIZE, BOT_THICKNESS, HSIZE * 2.0); + xform.set_translation(Vector3(0, -BOT_THICKNESS / 2.0, 0)); + bottom->apply_xform(xform); + Object *obottom = new Object; + obottom->set_mesh(bottom); + obottom->xform().set_translation(Vector3(sign * (HSIZE / 2.0 + WALL_THICKNESS + HINGE_RAD * 0.25), 0, 0)); + obottom->set_texture(img_field.texture()); + obj.push_back(obottom); - // generate the 4 sides - Mesh *sides = new Mesh; - gen_box(sides, WALL_THICKNESS, WALL_HEIGHT, VSIZE + WALL_THICKNESS * 2); - xform.set_translation(Vector3(-(HSIZE + WALL_THICKNESS) / 2.0, - WALL_HEIGHT / 2.0 - BOT_THICKNESS, 0)); - sides->apply_xform(xform); - Mesh tmp; - gen_box(&tmp, WALL_THICKNESS, WALL_HEIGHT, VSIZE + WALL_THICKNESS * 2); - xform.set_translation(Vector3((HSIZE + WALL_THICKNESS) / 2.0, - WALL_HEIGHT / 2.0 - BOT_THICKNESS, 0)); - tmp.apply_xform(xform); - sides->append(tmp); - tmp.clear(); + // generate the 4 sides + Mesh *sides = new Mesh; + gen_box(sides, WALL_THICKNESS, WALL_HEIGHT, VSIZE + WALL_THICKNESS * 2); + xform.set_translation(Vector3(-(HSIZE + WALL_THICKNESS) / 2.0, + WALL_HEIGHT / 2.0 - BOT_THICKNESS, 0)); + sides->apply_xform(xform); - gen_box(&tmp, HSIZE, WALL_HEIGHT, WALL_THICKNESS); - xform.set_translation(Vector3(0, WALL_HEIGHT / 2.0 - BOT_THICKNESS, - (VSIZE + WALL_THICKNESS) / 2.0)); - tmp.apply_xform(xform); - sides->append(tmp); - tmp.clear(); + gen_box(&tmp, WALL_THICKNESS, WALL_HEIGHT, VSIZE + WALL_THICKNESS * 2); + xform.set_translation(Vector3((HSIZE + WALL_THICKNESS) / 2.0, + WALL_HEIGHT / 2.0 - BOT_THICKNESS, 0)); + tmp.apply_xform(xform); + sides->append(tmp); + tmp.clear(); - gen_box(&tmp, HSIZE, WALL_HEIGHT, WALL_THICKNESS); - xform.set_translation(Vector3(0, WALL_HEIGHT / 2.0 - BOT_THICKNESS, - -(VSIZE + WALL_THICKNESS) / 2.0)); - tmp.apply_xform(xform); - sides->append(tmp); - tmp.clear(); + gen_box(&tmp, HSIZE, WALL_HEIGHT, WALL_THICKNESS); + xform.set_translation(Vector3(0, WALL_HEIGHT / 2.0 - BOT_THICKNESS, + (VSIZE + WALL_THICKNESS) / 2.0)); + tmp.apply_xform(xform); + sides->append(tmp); + tmp.clear(); - Object *osides = new Object; - osides->set_mesh(sides); - obj.push_back(osides); + gen_box(&tmp, HSIZE, WALL_HEIGHT, WALL_THICKNESS); + xform.set_translation(Vector3(0, WALL_HEIGHT / 2.0 - BOT_THICKNESS, + -(VSIZE + WALL_THICKNESS) / 2.0)); + tmp.apply_xform(xform); + sides->append(tmp); + tmp.clear(); + + Object *osides = new Object; + osides->set_mesh(sides); + osides->xform() = obottom->xform(); + obj.push_back(osides); + + } // generate the hinges Mesh *hinges = new Mesh; gen_cylinder(hinges, HINGE_RAD, HINGE_HEIGHT, 10, 1, 1); - xform.set_rotation(Vector3(M_PI / 2.0, 0, 0)); - xform.translate(Vector3(0, VSIZE / 4.0, 0)); + xform.reset_identity(); + xform.translate(Vector3(0, WALL_HEIGHT - HINGE_RAD * 0.5, VSIZE / 4.0)); + xform.rotate(Vector3(M_PI / 2.0, 0, 0)); hinges->apply_xform(xform); gen_cylinder(&tmp, HINGE_RAD, HINGE_HEIGHT, 10, 1, 1); - xform.set_rotation(Vector3(M_PI / 2.0, 0, 0)); - xform.translate(Vector3(0, -VSIZE / 4.0, 0)); + xform.reset_identity(); + xform.translate(Vector3(0, WALL_HEIGHT - HINGE_RAD * 0.5, -VSIZE / 4.0)); + xform.rotate(Vector3(M_PI / 2.0, 0, 0)); tmp.apply_xform(xform); hinges->append(tmp); @@ -127,3 +140,73 @@ return true; } + +static bool spike(float x, float y) +{ + x = fmod(x * 5.0, 1.0); + return y < (x < 0.5 ? 2.0 * x : 2.0 - 2.0 * x); +} + +static bool circle(float x, float y, float rad) +{ + x = fmod(x * 5.0, 1.0) - 0.5; + y = (y - 0.65) * 5.0; + float len = sqrt(x * x + y * y); + return len < rad; +} + +static bool diamond(float x, float y) +{ + return y >= (1.0 - (x < 0.5 ? 2.0 * x : 2.0 - 2.0 * x)) * 0.3333333 + 0.88; +} + +static bool center_circle(float x, float y, float rad) +{ + x = x - 0.5; + y = 1.0 - y; + return sqrt(x * x + y * y) < rad; +} + +bool Board::generate_textures() +{ + const int xsz = 512; + const int ysz = 1024; + + img_field.create(xsz, ysz); + clear_image(&img_field, 0, 0, 0); + + unsigned char *pptr = img_field.pixels; + + for(int i=0; i #include "object.h" +#include "image.h" #define NUM_SLOTS 24 #define MAX_PUCKS 30 @@ -15,7 +16,10 @@ std::vector obj; Object *puck_obj; + Image img_wood, img_field; + bool generate(); + bool generate_textures(); public: Board(); diff -r 94aff2ff1934 -r b41ceead1708 src/image.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/image.cc Thu Jun 25 05:58:35 2015 +0300 @@ -0,0 +1,228 @@ +#include +#include "opengl.h" +#include "image.h" +#include "imago2.h" + + +static unsigned int next_pow2(unsigned int x); + +Image::Image() +{ + width = height = tex_width = tex_height = 0; + pixels = 0; + tex = 0; + tex_valid = false; +} + +Image::~Image() +{ + destroy(); +} + +Image::Image(const Image &img) +{ + pixels = 0; + create(img.width, img.height, img.pixels); +} + +Image &Image::operator =(const Image &img) +{ + if(&img != this) { + create(img.width, img.height, img.pixels); + } + return *this; +} + +bool Image::create(int width, int height, unsigned char *pixels) +{ + destroy(); + + try { + unsigned char *tmp = new unsigned char[width * height * 3]; + this->pixels = tmp; + this->width = width; + this->height = height; + } + catch(...) { + return false; + } + + if(pixels) { + memcpy(this->pixels, pixels, width * height * 3); + } + return true; +} + +void Image::destroy() +{ + delete [] pixels; + pixels = 0; + width = height = 0; + + if(tex) { + glDeleteTextures(1, &tex); + tex = 0; + tex_valid = false; + } +} + +bool Image::load(const char *fname) +{ + int xsz, ysz; + unsigned char *pix = (unsigned char*)img_load_pixels(fname, &xsz, &ysz, IMG_FMT_RGB24); + if(!pix) { + return false; + } + return create(xsz, ysz, pix); +} + +unsigned int Image::texture() const +{ + if(!pixels) { + return 0; + } + if(!tex) { + glGenTextures(1, &tex); + } + + if(!tex_valid) { + tex_width = next_pow2(width); + tex_height = next_pow2(height); + + glBindTexture(GL_TEXTURE_2D, tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + if(GLEW_SGIS_generate_mipmap) { + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 1); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_width, tex_height, 0, GL_RGB, GL_UNSIGNED_BYTE, + width == tex_width && height == tex_height ? pixels : 0); + if(width != tex_width || height != tex_height) { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels); + } + } else { + gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, tex_width, tex_height, GL_RGB, GL_UNSIGNED_BYTE, pixels); + } + + if(GLEW_EXT_texture_filter_anisotropic) { + static float max_aniso = -1.0; + + if(max_aniso < 0.0) { + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_aniso); + printf("using anisotropic filtering: x%g\n", max_aniso); + } + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_aniso); + } + tex_valid = true; + } + return tex; +} + +int Image::texture_width() const +{ + return tex_width; +} + +int Image::texture_height() const +{ + return tex_height; +} + +void Image::invalidate_texture() +{ + tex_valid = false; +} + + +void clear_image(Image *img) +{ + clear_image(img, 0, 0, 0); +} + +void clear_image(Image *img, float r, float g, float b) +{ + if(!img->pixels) { + return; + } + + unsigned char col[3]; + unsigned char *ptr = img->pixels; + int npix = img->width * img->height; + + col[0] = (int)(r * 255.0); + col[1] = (int)(g * 255.0); + col[2] = (int)(b * 255.0); + + for(int i=0; iwidth; + int ysz = dest->height; + int npixels = xsz * ysz; + int nbytes = npixels * 3; + int tint = (int)(t * 255); + + if(aimg->width != xsz || bimg->width != xsz || aimg->height != ysz || bimg->height != ysz) { + return false; + } + + unsigned char *dptr = dest->pixels; + const unsigned char *aptr = aimg->pixels; + const unsigned char *bptr = bimg->pixels; + + switch(op) { + case IMG_OP_ADD: + for(int i=0; i 255 ? 255 : x; + } + break; + + case IMG_OP_SUB: + for(int i=0; i> 8; + *dptr++ = x > 255 ? 255 : x; + } + break; + + case IMG_OP_LERP: + for(int i=0; i> 8); + *dptr++ = x > 255 ? 255 : (x < 0 ? 0 : x); + } + break; + + default: + break; + } + + dest->invalidate_texture(); + return true; +} + +static unsigned int next_pow2(unsigned int x) +{ + x--; + x = (x >> 1) | x; + x = (x >> 2) | x; + x = (x >> 4) | x; + x = (x >> 8) | x; + x = (x >> 16) | x; + return x + 1; +} diff -r 94aff2ff1934 -r b41ceead1708 src/image.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/image.h Thu Jun 25 05:58:35 2015 +0300 @@ -0,0 +1,44 @@ +#ifndef IMAGE_H_ +#define IMAGE_H_ + +class Image { +private: + mutable int tex_width, tex_height; + mutable unsigned int tex; + mutable bool tex_valid; + +public: + int width, height; + unsigned char *pixels; + + Image(); + ~Image(); + + Image(const Image &img); + Image &operator =(const Image &img); + + bool create(int width, int height, unsigned char *pixels = 0); + void destroy(); + + bool load(const char *fname); + + unsigned int texture() const; + int texture_width() const; + int texture_height() const; + + void invalidate_texture(); +}; + +void clear_image(Image *img); +void clear_image(Image *img, float r, float g, float b); + +enum ImgCombine { + IMG_OP_ADD, + IMG_OP_SUB, + IMG_OP_MUL, + IMG_OP_LERP +}; + +bool combine_image(Image *dest, const Image *aimg, const Image *bimg, ImgCombine op = IMG_OP_LERP, float t = 0.5); + +#endif // IMAGE_H_ diff -r 94aff2ff1934 -r b41ceead1708 src/object.cc --- a/src/object.cc Mon Jun 22 21:46:57 2015 +0300 +++ b/src/object.cc Thu Jun 25 05:58:35 2015 +0300 @@ -4,6 +4,7 @@ Object::Object() { mesh = 0; + tex = 0; } Object::~Object() @@ -31,10 +32,22 @@ return mesh; } +void Object::set_texture(unsigned int tex) +{ + this->tex = tex; +} + void Object::draw() const { if(!mesh) return; + if(tex) { + glBindTexture(GL_TEXTURE_2D, tex); + glEnable(GL_TEXTURE_2D); + } else { + glDisable(GL_TEXTURE_2D); + } + glMatrixMode(GL_MODELVIEW); glPushMatrix(); glMultTransposeMatrixf(matrix[0]); @@ -42,6 +55,10 @@ mesh->draw(); glPopMatrix(); + + if(tex) { + glDisable(GL_TEXTURE_2D); + } } bool Object::intersect(const Ray &ray, HitPoint *hit) const diff -r 94aff2ff1934 -r b41ceead1708 src/object.h --- a/src/object.h Mon Jun 22 21:46:57 2015 +0300 +++ b/src/object.h Thu Jun 25 05:58:35 2015 +0300 @@ -8,6 +8,7 @@ private: Mesh *mesh; Matrix4x4 matrix; + unsigned int tex; public: Object(); @@ -19,6 +20,8 @@ void set_mesh(Mesh *m); Mesh *get_mesh() const; + void set_texture(unsigned int tex); + void draw() const; bool intersect(const Ray &ray, HitPoint *hit) const;