gpuray_glsl
diff src/texture.cc @ 0:f234630e38ff
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 09 Nov 2014 13:03:36 +0200 |
parents | |
children | 92695e89164b |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/texture.cc Sun Nov 09 13:03:36 2014 +0200 1.3 @@ -0,0 +1,237 @@ 1.4 +#include <stdio.h> 1.5 +#include <unistd.h> 1.6 +#include <string.h> 1.7 +#include <errno.h> 1.8 +#include "texture.h" 1.9 +#include "object.h" 1.10 + 1.11 +static inline Color sample_image(const Image &img, float u, float v, Texture::WrapMode wrapping); 1.12 + 1.13 +Texture::Texture() 1.14 + : sampling(SampleMode::nearest), wrapping(WrapMode::repeat) 1.15 +{ 1.16 +} 1.17 + 1.18 +Texture::~Texture() {} 1.19 + 1.20 +void Texture::set_name(const char *name) 1.21 +{ 1.22 + this->name = name; 1.23 +} 1.24 + 1.25 +const char *Texture::get_name() const 1.26 +{ 1.27 + return name.c_str(); 1.28 +} 1.29 + 1.30 +void Texture::set_sampling_mode(SampleMode mode) 1.31 +{ 1.32 + sampling = mode; 1.33 +} 1.34 + 1.35 +Texture::SampleMode Texture::get_sampling_mode() const 1.36 +{ 1.37 + return sampling; 1.38 +} 1.39 + 1.40 +void Texture::set_wrapping_mode(WrapMode mode) 1.41 +{ 1.42 + wrapping = mode; 1.43 +} 1.44 + 1.45 +Texture::WrapMode Texture::get_wrapping_mode() const 1.46 +{ 1.47 + return wrapping; 1.48 +} 1.49 + 1.50 + 1.51 +Color Texture::sample(const HitPoint &hit) const 1.52 +{ 1.53 + return sample(hit.texcoord.x, hit.texcoord.y, 0.0f); 1.54 +} 1.55 + 1.56 +Image *Texture2D::get_image(int idx) 1.57 +{ 1.58 + return &img; 1.59 +} 1.60 + 1.61 +const Image *Texture2D::get_image(int idx) const 1.62 +{ 1.63 + return &img; 1.64 +} 1.65 + 1.66 + 1.67 +bool Texture2D::load(const char *fname) 1.68 +{ 1.69 + name = fname; 1.70 + return img.load(fname); 1.71 +} 1.72 + 1.73 +Color Texture2D::sample(float u, float v, float w) const 1.74 +{ 1.75 + return sample_image(img, u, v, wrapping); 1.76 +} 1.77 + 1.78 +TextureCube::TextureCube() 1.79 +{ 1.80 + wrapping = WrapMode::clamp; 1.81 +} 1.82 + 1.83 +Image *TextureCube::get_image(int idx) 1.84 +{ 1.85 + return &img[idx]; 1.86 +} 1.87 + 1.88 +const Image *TextureCube::get_image(int idx) const 1.89 +{ 1.90 + return &img[idx]; 1.91 +} 1.92 + 1.93 + 1.94 +bool TextureCube::load(const char *fname) 1.95 +{ 1.96 + // assume it's a cubemap descriptor file (face path per line) 1.97 + FILE *fp; 1.98 + if(!(fp = fopen(fname, "r"))) { 1.99 + fprintf(stderr, "failed to open the cubemap descriptor %s: %s\n", fname, strerror(errno)); 1.100 + return false; 1.101 + } 1.102 + 1.103 + name = fname; 1.104 + 1.105 + char *prefix = (char*)alloca(strlen(fname) + 1); 1.106 + strcpy(prefix, fname); 1.107 + char *ptr = strrchr(prefix, '/'); 1.108 + if(!ptr) { 1.109 + ptr = prefix; 1.110 + } 1.111 + *ptr = 0; 1.112 + 1.113 + int xsz = 0, ysz = 0; 1.114 + 1.115 + // load the faces 1.116 + char buf[512]; 1.117 + for(int i=0; i<6; i++) { 1.118 + if(!fgets(buf, sizeof buf, fp)) { 1.119 + fprintf(stderr, "invalid cubemap descriptor file: %s\n", fname); 1.120 + return false; 1.121 + } 1.122 + if(buf[strlen(buf) - 1] == '\n') { 1.123 + buf[strlen(buf) - 1] = 0; 1.124 + } 1.125 + 1.126 + std::string path = std::string(prefix) + "/" + std::string(buf); 1.127 + if(!img[i].load(path.c_str())) { 1.128 + fprintf(stderr, "failed to load image: %s\n", path.c_str()); 1.129 + fclose(fp); 1.130 + return false; 1.131 + } 1.132 + 1.133 + if(i == 0) { 1.134 + xsz = img[i].xsz; 1.135 + ysz = img[i].ysz; 1.136 + } else { 1.137 + if(img[i].xsz != xsz || img[i].ysz != ysz) { 1.138 + fprintf(stderr, "cubemap %s face image %s size (%dx%d) doesn't match the previous faces (%dx%d)\n", 1.139 + fname, path.c_str(), img[i].xsz, img[i].ysz, xsz, ysz); 1.140 + fclose(fp); 1.141 + return false; 1.142 + } 1.143 + } 1.144 + } 1.145 + return true; 1.146 +} 1.147 + 1.148 +Color TextureCube::sample(float u, float v, float w) const 1.149 +{ 1.150 + int face; 1.151 + Vector2 uv; 1.152 + 1.153 + float abs_u = fabs(u); 1.154 + float abs_v = fabs(v); 1.155 + float abs_w = fabs(w); 1.156 + 1.157 + if(abs_u > abs_v && abs_u > abs_w) { 1.158 + if(u >= 0.0) { 1.159 + face = 0; 1.160 + uv.x = w / abs_u; 1.161 + uv.y = v / abs_u; 1.162 + } else { 1.163 + face = 1; 1.164 + uv.x = -w / abs_u; 1.165 + uv.y = v / abs_u; 1.166 + } 1.167 + } else if(abs_v > abs_w) { 1.168 + if(v >= 0.0) { 1.169 + face = 2; 1.170 + uv.x = u / abs_v; 1.171 + uv.y = w / abs_v; 1.172 + } else { 1.173 + face = 3; 1.174 + uv.x = u / abs_v; 1.175 + uv.y = -w / abs_v; 1.176 + } 1.177 + } else { 1.178 + if(w >= 0.0) { 1.179 + face = 5; 1.180 + uv.x = -u / abs_w; 1.181 + uv.y = v / abs_w; 1.182 + } else { 1.183 + face = 4; 1.184 + uv.x = u / abs_w; 1.185 + uv.y = v / abs_w; 1.186 + } 1.187 + } 1.188 + 1.189 + return sample_image(img[face], uv.x * 0.5 + 0.5, uv.y * 0.5 + 0.5, wrapping); 1.190 +} 1.191 + 1.192 +Color TextureCube::sample(const HitPoint &hit) const 1.193 +{ 1.194 + return sample(hit.normal.x, hit.normal.y, hit.normal.z); 1.195 +} 1.196 + 1.197 +Texture *load_texture(const char *fname) 1.198 +{ 1.199 + if(access(fname, R_OK) == -1) { 1.200 + fprintf(stderr, "failed to load texture %s: %s\n", fname, strerror(errno)); 1.201 + return 0; 1.202 + } 1.203 + 1.204 + Texture2D *tex2d = new Texture2D; 1.205 + if(tex2d->load(fname)) { 1.206 + return tex2d; 1.207 + } 1.208 + delete tex2d; 1.209 + 1.210 + TextureCube *texcube = new TextureCube; 1.211 + if(texcube->load(fname)) { 1.212 + return texcube; 1.213 + } 1.214 + delete texcube; 1.215 + 1.216 + return 0; 1.217 +} 1.218 + 1.219 +#define CLAMP(x, lo, hi) ((x) < (lo) ? (lo) : ((x) > (hi) ? (hi) : (x))) 1.220 + 1.221 +static inline Color sample_image(const Image &img, float u, float v, Texture::WrapMode wrapping) 1.222 +{ 1.223 + int x = (int)round(u * img.xsz); 1.224 + int y = (int)round((1.0 - v) * img.ysz); 1.225 + 1.226 + if(wrapping == Texture::WrapMode::clamp) { 1.227 + x = CLAMP(x, 0, img.xsz - 1); 1.228 + y = CLAMP(y, 0, img.ysz - 1); 1.229 + } else { 1.230 + x %= img.xsz; 1.231 + y %= img.ysz; 1.232 + 1.233 + if(x < 0) 1.234 + x += img.xsz; 1.235 + if(y < 0) 1.236 + y += img.ysz; 1.237 + } 1.238 + 1.239 + return img.pixels[y * img.xsz + x]; 1.240 +}