1 /*
2 Copyright (c) 2005-2021 Intel Corporation
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17 /*
18 The original source for this example is
19 Copyright (c) 1994-2008 John E. Stone
20 All rights reserved.
21
22 Redistribution and use in source and binary forms, with or without
23 modification, are permitted provided that the following conditions
24 are met:
25 1. Redistributions of source code must retain the above copyright
26 notice, this list of conditions and the following disclaimer.
27 2. Redistributions in binary form must reproduce the above copyright
28 notice, this list of conditions and the following disclaimer in the
29 documentation and/or other materials provided with the distribution.
30 3. The name of the author may not be used to endorse or promote products
31 derived from this software without specific prior written permission.
32
33 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
34 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
35 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
37 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 SUCH DAMAGE.
44 */
45
46 /*
47 * vol.cpp - Volume rendering helper routines etc.
48 */
49
50 #include <cstdio>
51
52 #include "machine.hpp"
53 #include "types.hpp"
54 #include "macros.hpp"
55 #include "vector.hpp"
56 #include "util.hpp"
57 #include "vol.hpp"
58 #include "box.hpp"
59 #include "trace.hpp"
60 #include "ui.hpp"
61 #include "light.hpp"
62 #include "shade.hpp"
63
scalarvol_bbox(void * obj,vector * min,vector * max)64 int scalarvol_bbox(void *obj, vector *min, vector *max) {
65 box *b = (box *)obj;
66
67 *min = b->min;
68 *max = b->max;
69
70 return 1;
71 }
72
newscalarvol(void * intex,vector min,vector max,int xs,int ys,int zs,char * fname,scalarvol * invol)73 void *newscalarvol(void *intex,
74 vector min,
75 vector max,
76 int xs,
77 int ys,
78 int zs,
79 char *fname,
80 scalarvol *invol) {
81 box *bx;
82 texture *tx, *tex;
83 scalarvol *vol;
84
85 tex = (texture *)intex;
86 tex->shadowcast = 0; /* doesn't cast a shadow */
87
88 tx = (texture *)rt_getmem(sizeof(texture));
89
90 /* is the volume data already loaded? */
91 if (invol == nullptr) {
92 vol = (scalarvol *)rt_getmem(sizeof(scalarvol));
93 vol->loaded = 0;
94 vol->data = nullptr;
95 }
96 else
97 vol = invol;
98
99 vol->opacity = tex->opacity;
100 vol->xres = xs;
101 vol->yres = ys;
102 vol->zres = zs;
103 strcpy(vol->name, fname);
104
105 tx->ctr.x = 0.0;
106 tx->ctr.y = 0.0;
107 tx->ctr.z = 0.0;
108 tx->rot = tx->ctr;
109 tx->scale = tx->ctr;
110 tx->uaxs = tx->ctr;
111 tx->vaxs = tx->ctr;
112
113 tx->islight = 0;
114 tx->shadowcast = 0; /* doesn't cast a shadow */
115
116 tx->col = tex->col;
117 tx->ambient = 1.0;
118 tx->diffuse = 0.0;
119 tx->specular = 0.0;
120 tx->opacity = 1.0;
121 tx->img = vol;
122 tx->texfunc = (color(*)(void *, void *, void *))(scalar_volume_texture);
123
124 bx = newbox(tx, min, max);
125 tx->obj = (void *)bx; /* XXX hack! */
126
127 return (void *)bx;
128 }
129
VoxelColor(flt scalar)130 color VoxelColor(flt scalar) {
131 color col;
132
133 if (scalar > 1.0)
134 scalar = 1.0;
135
136 if (scalar < 0.0)
137 scalar = 0.0;
138
139 if (scalar < 0.25) {
140 col.r = scalar * 4.0;
141 col.g = 0.0;
142 col.b = 0.0;
143 }
144 else {
145 if (scalar < 0.75) {
146 col.r = 1.0;
147 col.g = (scalar - 0.25) * 2.0;
148 col.b = 0.0;
149 }
150 else {
151 col.r = 1.0;
152 col.g = 1.0;
153 col.b = (scalar - 0.75) * 4.0;
154 }
155 }
156
157 return col;
158 }
159
scalar_volume_texture(vector * hit,texture * tex,ray * ry)160 color scalar_volume_texture(vector *hit, texture *tex, ray *ry) {
161 color col, col2;
162 box *bx;
163 flt a, tx1, tx2, ty1, ty2, tz1, tz2;
164 flt tnear, tfar;
165 flt t, tdist, dt, sum, tt;
166 vector pnt, bln;
167 scalarvol *vol;
168 flt scalar, transval;
169 int x, y, z;
170 unsigned char *ptr;
171
172 bx = (box *)tex->obj;
173 vol = (scalarvol *)bx->tex->img;
174
175 col.r = 0.0;
176 col.g = 0.0;
177 col.b = 0.0;
178
179 tnear = -FHUGE;
180 tfar = FHUGE;
181
182 if (ry->d.x == 0.0) {
183 if ((ry->o.x < bx->min.x) || (ry->o.x > bx->max.x))
184 return col;
185 }
186 else {
187 tx1 = (bx->min.x - ry->o.x) / ry->d.x;
188 tx2 = (bx->max.x - ry->o.x) / ry->d.x;
189 if (tx1 > tx2) {
190 a = tx1;
191 tx1 = tx2;
192 tx2 = a;
193 }
194 if (tx1 > tnear)
195 tnear = tx1;
196 if (tx2 < tfar)
197 tfar = tx2;
198 }
199 if (tnear > tfar)
200 return col;
201 if (tfar < 0.0)
202 return col;
203
204 if (ry->d.y == 0.0) {
205 if ((ry->o.y < bx->min.y) || (ry->o.y > bx->max.y))
206 return col;
207 }
208 else {
209 ty1 = (bx->min.y - ry->o.y) / ry->d.y;
210 ty2 = (bx->max.y - ry->o.y) / ry->d.y;
211 if (ty1 > ty2) {
212 a = ty1;
213 ty1 = ty2;
214 ty2 = a;
215 }
216 if (ty1 > tnear)
217 tnear = ty1;
218 if (ty2 < tfar)
219 tfar = ty2;
220 }
221 if (tnear > tfar)
222 return col;
223 if (tfar < 0.0)
224 return col;
225
226 if (ry->d.z == 0.0) {
227 if ((ry->o.z < bx->min.z) || (ry->o.z > bx->max.z))
228 return col;
229 }
230 else {
231 tz1 = (bx->min.z - ry->o.z) / ry->d.z;
232 tz2 = (bx->max.z - ry->o.z) / ry->d.z;
233 if (tz1 > tz2) {
234 a = tz1;
235 tz1 = tz2;
236 tz2 = a;
237 }
238 if (tz1 > tnear)
239 tnear = tz1;
240 if (tz2 < tfar)
241 tfar = tz2;
242 }
243 if (tnear > tfar)
244 return col;
245 if (tfar < 0.0)
246 return col;
247
248 if (tnear < 0.0)
249 tnear = 0.0;
250
251 tdist = sqrt((flt)(vol->xres * vol->xres + vol->yres * vol->yres + vol->zres * vol->zres));
252 tt = (vol->opacity / tdist);
253
254 bln.x = fabs(bx->min.x - bx->max.x);
255 bln.y = fabs(bx->min.y - bx->max.y);
256 bln.z = fabs(bx->min.z - bx->max.z);
257
258 dt = sqrt(bln.x * bln.x + bln.y * bln.y + bln.z * bln.z) / tdist;
259 sum = 0.0;
260
261 /* move the volume residency check out of loop.. */
262 if (!vol->loaded) {
263 LoadVol(vol);
264 vol->loaded = 1;
265 }
266
267 for (t = tnear; t <= tfar; t += dt) {
268 pnt.x = ((ry->o.x + (ry->d.x * t)) - bx->min.x) / bln.x;
269 pnt.y = ((ry->o.y + (ry->d.y * t)) - bx->min.y) / bln.y;
270 pnt.z = ((ry->o.z + (ry->d.z * t)) - bx->min.z) / bln.z;
271
272 x = (int)((vol->xres - 1.5) * pnt.x + 0.5);
273 y = (int)((vol->yres - 1.5) * pnt.y + 0.5);
274 z = (int)((vol->zres - 1.5) * pnt.z + 0.5);
275
276 ptr = vol->data + ((vol->xres * vol->yres * z) + (vol->xres * y) + x);
277
278 scalar = (flt)((flt)1.0 * ((int)ptr[0])) / 255.0;
279
280 sum += tt * scalar;
281
282 transval = tt * scalar;
283
284 col2 = VoxelColor(scalar);
285
286 if (sum < 1.0) {
287 col.r += transval * col2.r;
288 col.g += transval * col2.g;
289 col.b += transval * col2.b;
290 if (sum < 0.0)
291 sum = 0.0;
292 }
293 else {
294 sum = 1.0;
295 }
296 }
297
298 if (sum < 1.0) { /* spawn transmission rays / refraction */
299 color transcol;
300
301 transcol = shade_transmission(ry, hit, 1.0 - sum);
302
303 col.r += transcol.r; /* add the transmitted ray */
304 col.g += transcol.g; /* to the diffuse and */
305 col.b += transcol.b; /* transmission total.. */
306 }
307
308 return col;
309 }
310
LoadVol(scalarvol * vol)311 void LoadVol(scalarvol *vol) {
312 FILE *dfile;
313 std::size_t status;
314 char msgtxt[2048];
315
316 dfile = fopen(vol->name, "r");
317 if (dfile == nullptr) {
318 char msgtxt[2048];
319 sprintf(msgtxt, "Vol: can't open %s for input!!! Aborting\n", vol->name);
320 rt_ui_message(MSG_ERR, msgtxt);
321 rt_ui_message(MSG_ABORT, "Rendering Aborted.");
322 std::exit(-1);
323 }
324
325 sprintf(
326 msgtxt, "loading %dx%dx%d volume set from %s", vol->xres, vol->yres, vol->zres, vol->name);
327 rt_ui_message(MSG_0, msgtxt);
328
329 vol->data = (unsigned char *)rt_getmem(vol->xres * vol->yres * vol->zres);
330
331 status = fread(vol->data, 1, (vol->xres * vol->yres * vol->zres), dfile);
332 fclose(dfile);
333 }
334