gpuray_glsl

annotate 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
rev   line source
nuclear@0 1 #include <stdio.h>
nuclear@0 2 #include <unistd.h>
nuclear@0 3 #include <string.h>
nuclear@0 4 #include <errno.h>
nuclear@0 5 #include "texture.h"
nuclear@0 6 #include "object.h"
nuclear@0 7
nuclear@0 8 static inline Color sample_image(const Image &img, float u, float v, Texture::WrapMode wrapping);
nuclear@0 9
nuclear@0 10 Texture::Texture()
nuclear@0 11 : sampling(SampleMode::nearest), wrapping(WrapMode::repeat)
nuclear@0 12 {
nuclear@0 13 }
nuclear@0 14
nuclear@0 15 Texture::~Texture() {}
nuclear@0 16
nuclear@0 17 void Texture::set_name(const char *name)
nuclear@0 18 {
nuclear@0 19 this->name = name;
nuclear@0 20 }
nuclear@0 21
nuclear@0 22 const char *Texture::get_name() const
nuclear@0 23 {
nuclear@0 24 return name.c_str();
nuclear@0 25 }
nuclear@0 26
nuclear@0 27 void Texture::set_sampling_mode(SampleMode mode)
nuclear@0 28 {
nuclear@0 29 sampling = mode;
nuclear@0 30 }
nuclear@0 31
nuclear@0 32 Texture::SampleMode Texture::get_sampling_mode() const
nuclear@0 33 {
nuclear@0 34 return sampling;
nuclear@0 35 }
nuclear@0 36
nuclear@0 37 void Texture::set_wrapping_mode(WrapMode mode)
nuclear@0 38 {
nuclear@0 39 wrapping = mode;
nuclear@0 40 }
nuclear@0 41
nuclear@0 42 Texture::WrapMode Texture::get_wrapping_mode() const
nuclear@0 43 {
nuclear@0 44 return wrapping;
nuclear@0 45 }
nuclear@0 46
nuclear@0 47
nuclear@0 48 Color Texture::sample(const HitPoint &hit) const
nuclear@0 49 {
nuclear@0 50 return sample(hit.texcoord.x, hit.texcoord.y, 0.0f);
nuclear@0 51 }
nuclear@0 52
nuclear@0 53 Image *Texture2D::get_image(int idx)
nuclear@0 54 {
nuclear@0 55 return &img;
nuclear@0 56 }
nuclear@0 57
nuclear@0 58 const Image *Texture2D::get_image(int idx) const
nuclear@0 59 {
nuclear@0 60 return &img;
nuclear@0 61 }
nuclear@0 62
nuclear@0 63
nuclear@0 64 bool Texture2D::load(const char *fname)
nuclear@0 65 {
nuclear@0 66 name = fname;
nuclear@0 67 return img.load(fname);
nuclear@0 68 }
nuclear@0 69
nuclear@0 70 Color Texture2D::sample(float u, float v, float w) const
nuclear@0 71 {
nuclear@0 72 return sample_image(img, u, v, wrapping);
nuclear@0 73 }
nuclear@0 74
nuclear@0 75 TextureCube::TextureCube()
nuclear@0 76 {
nuclear@0 77 wrapping = WrapMode::clamp;
nuclear@0 78 }
nuclear@0 79
nuclear@0 80 Image *TextureCube::get_image(int idx)
nuclear@0 81 {
nuclear@0 82 return &img[idx];
nuclear@0 83 }
nuclear@0 84
nuclear@0 85 const Image *TextureCube::get_image(int idx) const
nuclear@0 86 {
nuclear@0 87 return &img[idx];
nuclear@0 88 }
nuclear@0 89
nuclear@0 90
nuclear@0 91 bool TextureCube::load(const char *fname)
nuclear@0 92 {
nuclear@0 93 // assume it's a cubemap descriptor file (face path per line)
nuclear@0 94 FILE *fp;
nuclear@0 95 if(!(fp = fopen(fname, "r"))) {
nuclear@0 96 fprintf(stderr, "failed to open the cubemap descriptor %s: %s\n", fname, strerror(errno));
nuclear@0 97 return false;
nuclear@0 98 }
nuclear@0 99
nuclear@0 100 name = fname;
nuclear@0 101
nuclear@0 102 char *prefix = (char*)alloca(strlen(fname) + 1);
nuclear@0 103 strcpy(prefix, fname);
nuclear@0 104 char *ptr = strrchr(prefix, '/');
nuclear@0 105 if(!ptr) {
nuclear@0 106 ptr = prefix;
nuclear@0 107 }
nuclear@0 108 *ptr = 0;
nuclear@0 109
nuclear@0 110 int xsz = 0, ysz = 0;
nuclear@0 111
nuclear@0 112 // load the faces
nuclear@0 113 char buf[512];
nuclear@0 114 for(int i=0; i<6; i++) {
nuclear@0 115 if(!fgets(buf, sizeof buf, fp)) {
nuclear@0 116 fprintf(stderr, "invalid cubemap descriptor file: %s\n", fname);
nuclear@0 117 return false;
nuclear@0 118 }
nuclear@0 119 if(buf[strlen(buf) - 1] == '\n') {
nuclear@0 120 buf[strlen(buf) - 1] = 0;
nuclear@0 121 }
nuclear@0 122
nuclear@0 123 std::string path = std::string(prefix) + "/" + std::string(buf);
nuclear@0 124 if(!img[i].load(path.c_str())) {
nuclear@0 125 fprintf(stderr, "failed to load image: %s\n", path.c_str());
nuclear@0 126 fclose(fp);
nuclear@0 127 return false;
nuclear@0 128 }
nuclear@0 129
nuclear@0 130 if(i == 0) {
nuclear@0 131 xsz = img[i].xsz;
nuclear@0 132 ysz = img[i].ysz;
nuclear@0 133 } else {
nuclear@0 134 if(img[i].xsz != xsz || img[i].ysz != ysz) {
nuclear@0 135 fprintf(stderr, "cubemap %s face image %s size (%dx%d) doesn't match the previous faces (%dx%d)\n",
nuclear@0 136 fname, path.c_str(), img[i].xsz, img[i].ysz, xsz, ysz);
nuclear@0 137 fclose(fp);
nuclear@0 138 return false;
nuclear@0 139 }
nuclear@0 140 }
nuclear@0 141 }
nuclear@0 142 return true;
nuclear@0 143 }
nuclear@0 144
nuclear@0 145 Color TextureCube::sample(float u, float v, float w) const
nuclear@0 146 {
nuclear@0 147 int face;
nuclear@0 148 Vector2 uv;
nuclear@0 149
nuclear@0 150 float abs_u = fabs(u);
nuclear@0 151 float abs_v = fabs(v);
nuclear@0 152 float abs_w = fabs(w);
nuclear@0 153
nuclear@0 154 if(abs_u > abs_v && abs_u > abs_w) {
nuclear@0 155 if(u >= 0.0) {
nuclear@0 156 face = 0;
nuclear@0 157 uv.x = w / abs_u;
nuclear@0 158 uv.y = v / abs_u;
nuclear@0 159 } else {
nuclear@0 160 face = 1;
nuclear@0 161 uv.x = -w / abs_u;
nuclear@0 162 uv.y = v / abs_u;
nuclear@0 163 }
nuclear@0 164 } else if(abs_v > abs_w) {
nuclear@0 165 if(v >= 0.0) {
nuclear@0 166 face = 2;
nuclear@0 167 uv.x = u / abs_v;
nuclear@0 168 uv.y = w / abs_v;
nuclear@0 169 } else {
nuclear@0 170 face = 3;
nuclear@0 171 uv.x = u / abs_v;
nuclear@0 172 uv.y = -w / abs_v;
nuclear@0 173 }
nuclear@0 174 } else {
nuclear@0 175 if(w >= 0.0) {
nuclear@0 176 face = 5;
nuclear@0 177 uv.x = -u / abs_w;
nuclear@0 178 uv.y = v / abs_w;
nuclear@0 179 } else {
nuclear@0 180 face = 4;
nuclear@0 181 uv.x = u / abs_w;
nuclear@0 182 uv.y = v / abs_w;
nuclear@0 183 }
nuclear@0 184 }
nuclear@0 185
nuclear@0 186 return sample_image(img[face], uv.x * 0.5 + 0.5, uv.y * 0.5 + 0.5, wrapping);
nuclear@0 187 }
nuclear@0 188
nuclear@0 189 Color TextureCube::sample(const HitPoint &hit) const
nuclear@0 190 {
nuclear@0 191 return sample(hit.normal.x, hit.normal.y, hit.normal.z);
nuclear@0 192 }
nuclear@0 193
nuclear@0 194 Texture *load_texture(const char *fname)
nuclear@0 195 {
nuclear@0 196 if(access(fname, R_OK) == -1) {
nuclear@0 197 fprintf(stderr, "failed to load texture %s: %s\n", fname, strerror(errno));
nuclear@0 198 return 0;
nuclear@0 199 }
nuclear@0 200
nuclear@0 201 Texture2D *tex2d = new Texture2D;
nuclear@0 202 if(tex2d->load(fname)) {
nuclear@0 203 return tex2d;
nuclear@0 204 }
nuclear@0 205 delete tex2d;
nuclear@0 206
nuclear@0 207 TextureCube *texcube = new TextureCube;
nuclear@0 208 if(texcube->load(fname)) {
nuclear@0 209 return texcube;
nuclear@0 210 }
nuclear@0 211 delete texcube;
nuclear@0 212
nuclear@0 213 return 0;
nuclear@0 214 }
nuclear@0 215
nuclear@0 216 #define CLAMP(x, lo, hi) ((x) < (lo) ? (lo) : ((x) > (hi) ? (hi) : (x)))
nuclear@0 217
nuclear@0 218 static inline Color sample_image(const Image &img, float u, float v, Texture::WrapMode wrapping)
nuclear@0 219 {
nuclear@0 220 int x = (int)round(u * img.xsz);
nuclear@0 221 int y = (int)round((1.0 - v) * img.ysz);
nuclear@0 222
nuclear@0 223 if(wrapping == Texture::WrapMode::clamp) {
nuclear@0 224 x = CLAMP(x, 0, img.xsz - 1);
nuclear@0 225 y = CLAMP(y, 0, img.ysz - 1);
nuclear@0 226 } else {
nuclear@0 227 x %= img.xsz;
nuclear@0 228 y %= img.ysz;
nuclear@0 229
nuclear@0 230 if(x < 0)
nuclear@0 231 x += img.xsz;
nuclear@0 232 if(y < 0)
nuclear@0 233 y += img.ysz;
nuclear@0 234 }
nuclear@0 235
nuclear@0 236 return img.pixels[y * img.xsz + x];
nuclear@0 237 }