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 }
|