From 84320a4b92c1922cd40bd7ce3d942d19cc704bd2 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Mon, 25 Jul 2016 07:01:13 +0300 Subject: [PATCH] using a texture for the grid is better --- Makefile | 4 +- sdr/grid.p.glsl | 17 +- sdr/grid.v.glsl | 4 +- src/app.cc | 10 ++ src/assman.c | 31 ++++ src/assman.h | 29 ++++ src/assman_desktop.c | 38 +++++ src/image.cc | 251 +++++++++++++++++++++++++++++ src/image.h | 44 ++++++ src/opengl.h | 22 +++ src/texture.cc | 429 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/texture.h | 88 +++++++++++ 12 files changed, 950 insertions(+), 17 deletions(-) create mode 100644 src/assman.c create mode 100644 src/assman.h create mode 100644 src/assman_desktop.c create mode 100644 src/image.cc create mode 100644 src/image.h create mode 100644 src/texture.cc create mode 100644 src/texture.h diff --git a/Makefile b/Makefile index dcb3c86..998cd34 100644 --- a/Makefile +++ b/Makefile @@ -13,8 +13,8 @@ bin = vrfileman warn = -pedantic -Wall CFLAGS = $(warn) $(opt) $(dbg) $(inc) `pkg-config --cflags sdl2` -CXXFLAGS = $(warn) $(opt) $(dbg) $(inc) `pkg-config --cflags sdl2` -LDFLAGS = $(libgl) -lgmath `pkg-config --libs sdl2` +CXXFLAGS = -std=c++11 $(warn) $(opt) $(dbg) $(inc) `pkg-config --cflags sdl2` +LDFLAGS = $(libgl) -lgmath -limago `pkg-config --libs sdl2` ifeq ($(shell uname -s), Darwin) diff --git a/sdr/grid.p.glsl b/sdr/grid.p.glsl index 86a30a5..825cdc6 100644 --- a/sdr/grid.p.glsl +++ b/sdr/grid.p.glsl @@ -1,23 +1,14 @@ -varying vec3 pos, vpos; +uniform sampler2D tex; -float grid(vec2 p, float duty) -{ - float w = duty * 0.5; - p = fract(p); - return smoothstep(1.0 - w, 1.0, p.x) + (1.0 - smoothstep(0.0, w, p.x)) + - smoothstep(1.0 - w, 1.0, p.y) + (1.0 - smoothstep(0.0, w, p.y)); -} +varying vec3 vpos; void main() { - vec3 p = pos * 500.0; - - const vec3 grid_color = vec3(1.0, 0.2, 0.8); const vec3 bg_color = vec3(0.5, 0.1, 1.0); - vec3 color = grid_color * grid(p.xz, 0.2); + vec3 grid_color = texture2D(tex, gl_TexCoord[0].st).xyz; float fog = min(abs(vpos.z) * 0.05, 1.0); - gl_FragColor.xyz = mix(color, bg_color, fog); + gl_FragColor.xyz = mix(grid_color, bg_color, fog); gl_FragColor.a = 1.0; } diff --git a/sdr/grid.v.glsl b/sdr/grid.v.glsl index 9f102eb..d6bda6e 100644 --- a/sdr/grid.v.glsl +++ b/sdr/grid.v.glsl @@ -1,8 +1,8 @@ -varying vec3 pos, vpos; +varying vec3 vpos; void main() { gl_Position = ftransform(); - pos = gl_Vertex.xyz; vpos = (gl_ModelViewMatrix * gl_Vertex).xyz; + gl_TexCoord[0].xy = gl_Vertex.xz * 500.0; } diff --git a/src/app.cc b/src/app.cc index 1de3f89..f99e034 100644 --- a/src/app.cc +++ b/src/app.cc @@ -6,6 +6,7 @@ #include "mesh.h" #include "meshgen.h" #include "sdr.h" +#include "texture.h" int win_width, win_height; float win_aspect; @@ -13,6 +14,7 @@ long time_msec; static float cam_theta, cam_phi; static Mesh *mesh_torus; +static Texture *tex_grid; static bool bnstate[16]; static int prev_x, prev_y; @@ -44,6 +46,10 @@ bool app_init(int argc, char **argv) if(!(sdr_grid = create_program_load("sdr/grid.v.glsl", "sdr/grid.p.glsl"))) { return false; } + if(!(tex_grid = load_texture("data/purple_grid.png"))) { + delete tex_grid; + return false; + } return true; } @@ -71,6 +77,8 @@ void app_draw() glMultMatrixf(xform[0]); bind_program(sdr_grid); + bind_texture(tex_grid); + glBegin(GL_QUADS); glNormal3f(0, 1, 0); glVertex3f(-1, 0, 1); @@ -78,6 +86,8 @@ void app_draw() glVertex3f(1, 0, -1); glVertex3f(-1, 0, -1); glEnd(); + + bind_texture(0); bind_program(0); glPopMatrix(); diff --git a/src/assman.c b/src/assman.c new file mode 100644 index 0000000..423c8de --- /dev/null +++ b/src/assman.c @@ -0,0 +1,31 @@ +#include +#include "assman.h" + +int ass_fgetc(ass_file *fp) +{ + unsigned char c; + + if(ass_fread(&c, 1, 1, fp) < 1) { + return -1; + } + return (int)c; +} + +char *ass_fgets(char *s, int size, ass_file *fp) +{ + int i, c; + char *ptr = s; + + if(!size) return 0; + + for(i=0; i + +typedef void ass_file; + +#ifdef __cplusplus +extern "C" { +#endif + +ass_file *ass_fopen(const char *fname, const char *mode); +void ass_fclose(ass_file *fp); +long ass_fseek(ass_file *fp, long offs, int whence); +long ass_ftell(ass_file *fp); +int ass_feof(ass_file *fp); + +size_t ass_fread(void *buf, size_t size, size_t count, ass_file *fp); +int ass_ungetc(int c, ass_file *fp); + +/* convenience functions, derived from the above */ +int ass_fgetc(ass_file *fp); +char *ass_fgets(char *s, int size, ass_file *fp); + +#ifdef __cplusplus +} +#endif + +#endif /* ASSMAN_H_ */ diff --git a/src/assman_desktop.c b/src/assman_desktop.c new file mode 100644 index 0000000..33e1eba --- /dev/null +++ b/src/assman_desktop.c @@ -0,0 +1,38 @@ +#include +#include "assman.h" + +ass_file *ass_fopen(const char *fname, const char *mode) +{ + return (ass_file*)fopen(fname, mode); +} + +void ass_fclose(ass_file *fp) +{ + fclose((FILE*)fp); +} + +long ass_fseek(ass_file *fp, long offs, int whence) +{ + fseek((FILE*)fp, offs, whence); + return ftell((FILE*)fp); +} + +long ass_ftell(ass_file *fp) +{ + return ftell((FILE*)fp); +} + +int ass_feof(ass_file *fp) +{ + return feof((FILE*)fp); +} + +size_t ass_fread(void *buf, size_t size, size_t count, ass_file *fp) +{ + return fread(buf, size, count, (FILE*)fp); +} + +int ass_ungetc(int c, ass_file *fp) +{ + return ungetc(c, (FILE*)fp); +} diff --git a/src/image.cc b/src/image.cc new file mode 100644 index 0000000..6d6e4b2 --- /dev/null +++ b/src/image.cc @@ -0,0 +1,251 @@ +#include +#include "assman.h" +#include "imago2.h" +#include "image.h" + + +static int pixel_elements(Image::Format fmt); +static int elem_size(Image::Format fmt); +static int pixel_size(Image::Format fmt); + +Image::Image() +{ + fmt = FMT_RGBA; + width = height = 0; + pixels = 0; +} + +Image::~Image() +{ + delete [] (char*)pixels; +} + +Image::Image(const Image &img) +{ + pixels = 0; + set_pixels(img.width, img.height, img.pixels, img.fmt); +} + +Image &Image::operator =(const Image &img) +{ + if(&img != this) { + delete [] (char*)pixels; + pixels = 0; + set_pixels(img.width, img.height, img.pixels, img.fmt); + } + return *this; +} + +Image::Image(Image &&img) +{ + width = img.width; + height = img.height; + pixels = img.pixels; + fmt = img.fmt; + + img.pixels = 0; +} + +Image &Image::operator =(Image &&img) +{ + if(&img != this) { + width = img.width; + height = img.height; + pixels = img.pixels; + fmt = img.fmt; + + img.pixels = 0; + } + return *this; +} + +int Image::get_width() const +{ + return width; +} + +int Image::get_height() const +{ + return height; +} + +Image::Format Image::get_format() const +{ + return fmt; +} + +bool Image::create(int x, int y, Format fmt) +{ + width = x; + height = y; + this->fmt = fmt; + + try { + pixels = new char[x * y * pixel_size(fmt)]; + } + catch(...) { + return false; + } + return true; +} + +bool Image::set_pixels(int x, int y, void *pixels, Format fmt) +{ + if(!create(x, y, fmt)) { + return false; + } + memcpy(this->pixels, pixels, x * y * pixel_size(fmt)); + return true; +} + +void *Image::get_pixels() const +{ + return pixels; +} + +static size_t io_read(void *buf, size_t bytes, void *uptr) +{ + return ass_fread(buf, 1, bytes, uptr); +} + +static long io_seek(long offs, int whence, void *uptr) +{ + return ass_fseek(uptr, offs, whence); +} + +bool Image::load(const char *fname) +{ + struct img_pixmap pixmap; + struct img_io io; + + if(!(io.uptr = ass_fopen(fname, "rb"))) { + fprintf(stderr, "failed to open image: %s\n", fname); + return false; + } + io.read = io_read; + io.write = 0; + io.seek = io_seek; + + img_init(&pixmap); + if(img_read(&pixmap, &io) == -1) { + return false; + } + ass_fclose(io.uptr); + + Format fmt; + switch(pixmap.fmt) { + case IMG_FMT_GREY8: + fmt = FMT_GREY; + break; + case IMG_FMT_RGB24: + fmt = FMT_RGB; + break; + case IMG_FMT_RGBA32: + fmt = FMT_RGBA; + break; + case IMG_FMT_GREYF: + fmt = FMT_GREY_FLOAT; + break; + case IMG_FMT_RGBF: + fmt = FMT_RGB_FLOAT; + break; + case IMG_FMT_RGBAF: + fmt = FMT_RGBA_FLOAT; + break; + default: + img_destroy(&pixmap); + return false; + } + + if(!set_pixels(pixmap.width, pixmap.height, pixmap.pixels, fmt)) { + img_destroy(&pixmap); + return false; + } + img_destroy(&pixmap); + return true; +} + +bool Image::save(const char *fname) const +{ + struct img_pixmap pixmap; + + img_init(&pixmap); + + switch(fmt) { + case FMT_GREY: + pixmap.fmt = IMG_FMT_GREY8; + break; + case FMT_GREY_FLOAT: + pixmap.fmt = IMG_FMT_GREYF; + break; + case FMT_RGB: + pixmap.fmt = IMG_FMT_RGB24; + break; + case FMT_RGB_FLOAT: + pixmap.fmt = IMG_FMT_RGBF; + break; + case FMT_RGBA: + pixmap.fmt = IMG_FMT_RGBA32; + break; + case FMT_RGBA_FLOAT: + pixmap.fmt = IMG_FMT_RGBAF; + break; + default: + return false; + } + + pixmap.width = width; + pixmap.height = height; + pixmap.pixels = pixels; + pixmap.pixelsz = pixel_size(fmt); + + if(img_save(&pixmap, fname) == -1) { + return false; + } + return true; +} + +static int pixel_elements(Image::Format fmt) +{ + switch(fmt) { + case Image::FMT_GREY: + case Image::FMT_GREY_FLOAT: + return 1; + + case Image::FMT_RGB: + case Image::FMT_RGB_FLOAT: + return 3; + + case Image::FMT_RGBA: + case Image::FMT_RGBA_FLOAT: + return 4; + + default: + break; + } + return 0; +} + +static int elem_size(Image::Format fmt) +{ + switch(fmt) { + case Image::FMT_GREY: + case Image::FMT_RGB: + case Image::FMT_RGBA: + return 1; + + case Image::FMT_GREY_FLOAT: + case Image::FMT_RGB_FLOAT: + case Image::FMT_RGBA_FLOAT: + return sizeof(float); + + default: + break; + } + return 0; +} + +static int pixel_size(Image::Format fmt) +{ + return elem_size(fmt) * pixel_elements(fmt); +} diff --git a/src/image.h b/src/image.h new file mode 100644 index 0000000..0ddbd12 --- /dev/null +++ b/src/image.h @@ -0,0 +1,44 @@ +#ifndef IMAGE_H_ +#define IMAGE_H_ + + +class Image { +public: + enum Format { + FMT_GREY, + FMT_RGB, + FMT_RGBA, + FMT_GREY_FLOAT, + FMT_RGB_FLOAT, + FMT_RGBA_FLOAT + }; + +private: + Format fmt; + int width, height; + void *pixels; + +public: + Image(); + ~Image(); + + Image(const Image &img); + Image &operator =(const Image &img); + + Image(Image &&img); + Image &operator =(Image &&img); + + int get_width() const; + int get_height() const; + + Format get_format() const; + + bool create(int x, int y, Format fmt = FMT_RGBA); + bool set_pixels(int x, int y, void *pixels, Format fmt = FMT_RGBA); + void *get_pixels() const; + + bool load(const char *fname); + bool save(const char *fname) const; +}; + +#endif // IMAGE_H_ diff --git a/src/opengl.h b/src/opengl.h index 6d5387e..9acd561 100644 --- a/src/opengl.h +++ b/src/opengl.h @@ -30,6 +30,28 @@ #endif /* IPHONE */ +#ifndef GL_RGB16F +#define GL_RGB16F 0x881b +#endif +#ifndef GL_RGBA16F +#define GL_RGBA16F 0x881a +#endif +#ifndef GL_RGB32F +#define GL_RGB32F 0x8815 +#endif +#ifndef GL_RGBA32F +#define GL_RGBA32F 0x8814 +#endif +#ifndef GL_LUMINANCE16F +#define GL_LUMINANCE16F 0x881e +#endif +#ifndef GL_LUMINANCE32F +#define GL_LUMINANCE32F 0x8818 +#endif +#ifndef GL_DEPTH24_STENCIL8 +#define GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_OES +#endif + #ifdef __cplusplus extern "C" { #endif diff --git a/src/texture.cc b/src/texture.cc new file mode 100644 index 0000000..95d34e3 --- /dev/null +++ b/src/texture.cc @@ -0,0 +1,429 @@ +#include +#include "texture.h" +#include "image.h" +#include "opengl.h" +#include "imago2.h" + +#if defined(GL_ES_VERSION_2_0) || defined(GL_VERSION_3_0) +#define USE_GL_GENERATE_MIPMAP +#elif defined(__GLEW_H__) +#define USE_SGIS_GENERATE_MIPMAP +#endif + +static int glifmt_from_ifmt(unsigned int ifmt); +static int glfmt_from_ifmt(unsigned int ifmt); +static int gltype_from_ifmt(unsigned int ifmt); + +static int glifmt_from_imgfmt(Image::Format fmt); +static Image::Format imgfmt_from_glifmt(unsigned int ifmt); + +static unsigned int cur_target[8] = { + GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D, + GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D +}; + +void bind_texture(Texture *tex, int tunit) +{ + if(tex) { + tex->bind(tunit); + } else { + glActiveTexture(GL_TEXTURE0 + tunit); + glBindTexture(cur_target[tunit], 0); + glActiveTexture(GL_TEXTURE0); + } +} + +Texture *load_texture(const char *fname) +{ + TextureCube *texcube = new TextureCube; + if(texcube->load(fname)) { + return texcube; + } + delete texcube; + + Texture2D *tex = new Texture2D; + if(tex->load(fname)) { + return tex; + } + delete tex; + return 0; +} + + +Texture::Texture() +{ + target = 0; + sz[0] = sz[1] = sz[2] = 0; + texfmt = 0; + + glGenTextures(1, &id); +} + +Texture::~Texture() +{ + if(id) { + glDeleteTextures(1, &id); + } +} + +void Texture::set_wrapping(unsigned int wrap) +{ + if(!target) { + return; + } + + glBindTexture(target, id); + glTexParameteri(target, GL_TEXTURE_WRAP_S, wrap); + glTexParameteri(target, GL_TEXTURE_WRAP_T, wrap); +} + +void Texture::set_filtering(unsigned int filt) +{ + unsigned int mag_filter; + + if(!target) { + return; + } + + switch(filt) { + case GL_LINEAR_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_LINEAR: + mag_filter = GL_LINEAR; + break; + + case GL_NEAREST_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + mag_filter = GL_NEAREST; + break; + + default: + mag_filter = filt; + } + + set_filtering(filt, mag_filter); +} + +void Texture::set_filtering(unsigned int min_filt, unsigned int mag_filt) +{ + glBindTexture(target, id); + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, min_filt); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, mag_filt); +} + +unsigned int Texture::get_format() const +{ + return texfmt; +} + +int Texture::get_size(int dim) const +{ + if(dim < 0 || dim >= 3) { + return 0; + } + return sz[dim]; +} + +unsigned int Texture::get_id() const +{ + return id; +} + +void Texture::bind(int tex_unit) const +{ + glActiveTexture(GL_TEXTURE0 + tex_unit); + glBindTexture(target, id); + glActiveTexture(GL_TEXTURE0); + + cur_target[tex_unit] = target; +} + + +// ---- Texture2D ---- + +Texture2D::Texture2D() +{ + target = GL_TEXTURE_2D; +} + +TextureType Texture2D::get_type() const +{ + return TEXTURE_2D; +} + +void Texture2D::create(int xsz, int ysz, unsigned int ifmt) +{ + int fmt = glfmt_from_ifmt(ifmt); + int type = gltype_from_ifmt(ifmt); + + glBindTexture(GL_TEXTURE_2D, id); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, glifmt_from_ifmt(ifmt), xsz, ysz, 0, fmt, type, 0); + sz[0] = xsz; + sz[1] = ysz; + texfmt = ifmt; +} + +void Texture2D::set_image(const Image &img, int idx) +{ + texfmt = glifmt_from_imgfmt(img.get_format()); + unsigned int fmt = glfmt_from_ifmt(texfmt); + unsigned int type = gltype_from_ifmt(texfmt); + + sz[0] = img.get_width(); + sz[1] = img.get_height(); + + glBindTexture(GL_TEXTURE_2D, id); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + +#ifdef USE_SGIS_GENERATE_MIPMAP + if(GLEW_SGIS_generate_mipmap) { + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); +#endif + glTexImage2D(GL_TEXTURE_2D, 0, texfmt, sz[0], sz[1], 0, fmt, type, img.get_pixels()); +#ifdef USE_SGIS_GENERATE_MIPMAP + } else { + gluBuild2DMipmaps(GL_TEXTURE_2D, texfmt, sz[0], sz[1], fmt, type, img.get_pixels()); + } +#endif + +#ifdef USE_GL_GENERATE_MIPMAP + glGenerateMipmap(GL_TEXTURE_2D); +#endif +} + +void Texture2D::get_image(Image *img, int idx) const +{ +#ifndef GL_ES_VERSION_2_0 + glBindTexture(GL_TEXTURE_2D, id); + + Image::Format img_fmt = imgfmt_from_glifmt(texfmt); + img->create(sz[0], sz[1], img_fmt); + + unsigned int fmt = glfmt_from_ifmt(texfmt); + unsigned int type = gltype_from_ifmt(texfmt); + glGetTexImage(GL_TEXTURE_2D, 0, fmt, type, img->get_pixels()); +#endif // GL_ES_VERSION_2_0 +} + +void Texture2D::set_subimage(const Image &img, int xoffs, int yoffs) +{ + unsigned int ifmt = glifmt_from_imgfmt(img.get_format()); + + glBindTexture(GL_TEXTURE_2D, id); + glTexSubImage2D(GL_TEXTURE_2D, 0, xoffs, yoffs, img.get_width(), img.get_height(), + glfmt_from_ifmt(ifmt), gltype_from_ifmt(ifmt), img.get_pixels()); +} + +bool Texture2D::load(const char *fname) +{ + Image img; + if(!img.load(fname)) { + fprintf(stderr, "failed to load 2D texture: %s\n", fname); + return false; + } + set_image(img); + + printf("loaded 2D texture: %s\n", fname); + return true; +} + +bool Texture2D::save(const char *fname) const +{ +#ifndef GL_ES_VERSION_2_0 + unsigned char *pixels = new unsigned char[sz[0] * sz[1] * 4]; + + glBindTexture(GL_TEXTURE_2D, id); + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + + if(img_save_pixels(fname, pixels, sz[0], sz[1]) == -1) { + fprintf(stderr, "failed to save 2D texture: %s\n", fname); + delete [] pixels; + return false; + } + + printf("saved 2D texture: %s\n", fname); + delete [] pixels; + return true; +#else + return false; // TODO +#endif +} + +// ---- TextureCube ---- +static unsigned int cube_faces[] = { + GL_TEXTURE_CUBE_MAP_POSITIVE_X, + GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z +}; + +TextureCube::TextureCube() +{ + target = GL_TEXTURE_CUBE_MAP; +} + +TextureType TextureCube::get_type() const +{ + return TEXTURE_CUBE; +} + + +void TextureCube::create(int xsz, int ysz, unsigned int ifmt) +{ + if(xsz != ysz) { + fprintf(stderr, "trying to create cubemap with different width and height (%dx%d)\n", xsz, ysz); + return; + } + + texfmt = ifmt; + + glBindTexture(GL_TEXTURE_CUBE_MAP, id); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + for(int i=0; i<6; i++) { + glTexImage2D(cube_faces[i], 0, ifmt, xsz, ysz, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + } +} + +void TextureCube::set_image(const Image &img, int idx) +{ + // TODO +} + +void TextureCube::get_image(Image *img, int idx) const +{ + // TODO +} + +bool TextureCube::load(const char *fname) +{ + return false; // TODO +} + +bool TextureCube::save(const char *fname) const +{ + return false; // TODO +} + +static int glifmt_from_ifmt(unsigned int ifmt) +{ +#ifdef GL_ES_VERSION_2_0 + switch(ifmt) { + case GL_LUMINANCE16F: + case GL_LUMINANCE32F: + ifmt = GL_LUMINANCE; + break; + + case GL_RGB16F: + case GL_RGB32F: + ifmt = GL_RGB; + break; + + case GL_RGBA16F: + case GL_RGBA32F: + ifmt = GL_RGBA; + break; + + default: + break; + } +#endif + return ifmt; // by default just pass it through... +} + +static int glfmt_from_ifmt(unsigned int ifmt) +{ + switch(ifmt) { + case GL_LUMINANCE16F: + case GL_LUMINANCE32F: + return GL_LUMINANCE; + + case GL_RGB16F: + case GL_RGB32F: + return GL_RGB; + + case GL_RGBA16F: + case GL_RGBA32F: + return GL_RGBA; + + default: + break; + } + return ifmt; +} + +static int gltype_from_ifmt(unsigned int ifmt) +{ + switch(ifmt) { + case GL_RGB16F: + case GL_RGBA16F: + case GL_LUMINANCE16F: +#ifdef GL_ES_VERSION_2_0 + return GL_HALF_FLOAT_OES; +#endif + case GL_RGB32F: + case GL_RGBA32F: + case GL_LUMINANCE32F: + return GL_FLOAT; + + default: + break; + } + return GL_UNSIGNED_BYTE; +} + +static int glifmt_from_imgfmt(Image::Format fmt) +{ + switch(fmt) { + case Image::FMT_GREY: + return GL_LUMINANCE; + case Image::FMT_GREY_FLOAT: + return GL_LUMINANCE16F; + case Image::FMT_RGB: + return GL_RGB; + case Image::FMT_RGB_FLOAT: + return GL_RGB16F; + case Image::FMT_RGBA: + return GL_RGBA; + case Image::FMT_RGBA_FLOAT: + return GL_RGBA16F; + default: + break; + } + return 0; +} + +static Image::Format imgfmt_from_glifmt(unsigned int ifmt) +{ + switch(ifmt) { + case GL_LUMINANCE: + return Image::FMT_GREY; + case GL_LUMINANCE16F: + return Image::FMT_GREY_FLOAT; + case GL_RGB: + return Image::FMT_RGB; + case GL_RGB16F: + return Image::FMT_RGB_FLOAT; + case GL_RGBA: + return Image::FMT_RGBA; + case GL_RGBA16F: + return Image::FMT_RGBA_FLOAT; + default: + break; + } + + fprintf(stderr, "imgfmt_from_glifmt: unknown internal format: %x\n", ifmt); +#ifndef NDEBUG + abort(); +#endif + return Image::FMT_RGBA; // ... whatever +} diff --git a/src/texture.h b/src/texture.h new file mode 100644 index 0000000..e39efe0 --- /dev/null +++ b/src/texture.h @@ -0,0 +1,88 @@ +#ifndef TEXTURE_H_ +#define TEXTURE_H_ + +#include "opengl.h" + +class Image; + +enum TextureType { + TEXTURE_2D, + TEXTURE_CUBE +}; + +class Texture { +protected: + unsigned int id; + unsigned int target; + unsigned int texfmt; + int sz[3]; + + Texture(const Texture &tex) {} + Texture &operator =(const Texture &tex) { + return *this; + } + +public: + Texture(); + virtual ~Texture(); + + virtual TextureType get_type() const = 0; + + void set_wrapping(unsigned int wrap); + void set_filtering(unsigned int filt); + void set_filtering(unsigned int min_filt, unsigned int mag_filt); + + unsigned int get_format() const; + + virtual int get_size(int dim) const; + + virtual void create(int xsz, int ysz, unsigned int ifmt = GL_RGBA) = 0; + virtual void set_image(const Image &img, int idx = 0) = 0; + virtual void get_image(Image *img, int idx = 0) const = 0; + + virtual bool load(const char *fname) = 0; + virtual bool save(const char *fname) const = 0; + + virtual unsigned int get_id() const; + + virtual void bind(int tex_unit = 0) const; +}; + +class Texture2D : public Texture { +public: + Texture2D(); + + virtual TextureType get_type() const; + + virtual void create(int xsz, int ysz, unsigned int ifmt = GL_RGBA); + virtual void set_image(const Image &img, int idx = 0); + virtual void get_image(Image *img, int idx = 0) const; + + virtual void set_subimage(const Image &img, int xoffs, int yoffs); + + virtual bool load(const char *fname); + virtual bool save(const char *fname) const; +}; + +class TextureCube : public Texture { +public: + TextureCube(); + + virtual TextureType get_type() const; + + virtual void create(int xsz, int ysz, unsigned int ifmt = GL_RGBA); + virtual void set_image(const Image &img, int idx = 0); + virtual void get_image(Image *img, int idx = 0) const; + + virtual bool load(const char *fname); + virtual bool save(const char *fname) const; +}; + +void bind_texture(Texture *tex, int tunit = 0); + +/** loads a texture autodetecting whether it's a 2D texture or + * cubemap and creating the correct Texture subclass instance. + */ +Texture *load_texture(const char *fname); + +#endif // TEXTURE_H_ -- 1.7.10.4