add BLI_strcpy_rlen, replace strcat, which was used in misleading way.
[blender.git] / intern / cycles / render / buffers.cpp
1 /*
2  * Copyright 2011, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18
19 #include <stdlib.h>
20
21 #include "buffers.h"
22 #include "device.h"
23
24 #include "util_debug.h"
25 #include "util_foreach.h"
26 #include "util_hash.h"
27 #include "util_image.h"
28 #include "util_math.h"
29 #include "util_opengl.h"
30 #include "util_time.h"
31 #include "util_types.h"
32
33 CCL_NAMESPACE_BEGIN
34
35 /* Buffer Params */
36
37 BufferParams::BufferParams()
38 {
39         width = 0;
40         height = 0;
41
42         full_x = 0;
43         full_y = 0;
44         full_width = 0;
45         full_height = 0;
46
47         Pass::add(PASS_COMBINED, passes);
48 }
49
50 void BufferParams::get_offset_stride(int& offset, int& stride)
51 {
52         offset = -(full_x + full_y*width);
53         stride = width;
54 }
55
56 bool BufferParams::modified(const BufferParams& params)
57 {
58         return !(full_x == params.full_x
59                 && full_y == params.full_y
60                 && width == params.width
61                 && height == params.height
62                 && full_width == params.full_width
63                 && full_height == params.full_height
64                 && Pass::equals(passes, params.passes));
65 }
66
67 int BufferParams::get_passes_size()
68 {
69         int size = 0;
70
71         foreach(Pass& pass, passes)
72                 size += pass.components;
73         
74         return align_up(size, 4);
75 }
76
77 /* Render Buffer Task */
78
79 RenderTile::RenderTile()
80 {
81         x = 0;
82         y = 0;
83         w = 0;
84         h = 0;
85
86         sample = 0;
87         start_sample = 0;
88         num_samples = 0;
89         resolution = 0;
90
91         offset = 0;
92         stride = 0;
93
94         buffer = 0;
95         rng_state = 0;
96         rgba = 0;
97
98         buffers = NULL;
99 }
100
101 /* Render Buffers */
102
103 RenderBuffers::RenderBuffers(Device *device_)
104 {
105   device = device_;
106 }
107
108 RenderBuffers::~RenderBuffers()
109 {
110         device_free();
111 }
112
113 void RenderBuffers::device_free()
114 {
115         if(buffer.device_pointer) {
116                 device->mem_free(buffer);
117                 buffer.clear();
118         }
119
120         if(rng_state.device_pointer) {
121                 device->mem_free(rng_state);
122                 rng_state.clear();
123         }
124 }
125
126 void RenderBuffers::reset(Device *device, BufferParams& params_)
127 {
128         params = params_;
129
130         /* free existing buffers */
131         device_free();
132         
133         /* allocate buffer */
134         buffer.resize(params.width*params.height*params.get_passes_size());
135         device->mem_alloc(buffer, MEM_READ_WRITE);
136         device->mem_zero(buffer);
137
138         /* allocate rng state */
139         rng_state.resize(params.width, params.height);
140
141         uint *init_state = rng_state.resize(params.width, params.height);
142         int x, y, width = params.width, height = params.height;
143         
144         for(x = 0; x < width; x++)
145                 for(y = 0; y < height; y++)
146                         init_state[x + y*width] = hash_int_2d(params.full_x+x, params.full_y+y);
147
148         device->mem_alloc(rng_state, MEM_READ_WRITE);
149         device->mem_copy_to(rng_state);
150 }
151
152 bool RenderBuffers::copy_from_device()
153 {
154         if(!buffer.device_pointer)
155                 return false;
156
157         device->mem_copy_from(buffer, 0, params.width, params.height, params.get_passes_size()*sizeof(float));
158
159         return true;
160 }
161
162 bool RenderBuffers::get_pass_rect(PassType type, float exposure, int sample, int components, float *pixels)
163 {
164         int pass_offset = 0;
165
166         foreach(Pass& pass, params.passes) {
167                 if(pass.type != type) {
168                         pass_offset += pass.components;
169                         continue;
170                 }
171
172                 float *in = (float*)buffer.data_pointer + pass_offset;
173                 int pass_stride = params.get_passes_size();
174
175                 float scale = (pass.filter)? 1.0f/(float)sample: 1.0f;
176                 float scale_exposure = (pass.exposure)? scale*exposure: scale;
177
178                 int size = params.width*params.height;
179
180                 if(components == 1) {
181                         assert(pass.components == components);
182
183                         /* scalar */
184                         if(type == PASS_DEPTH) {
185                                 for(int i = 0; i < size; i++, in += pass_stride, pixels++) {
186                                         float f = *in;
187                                         pixels[0] = (f == 0.0f)? 1e10f: f*scale_exposure;
188                                 }
189                         }
190                         else {
191                                 for(int i = 0; i < size; i++, in += pass_stride, pixels++) {
192                                         float f = *in;
193                                         pixels[0] = f*scale_exposure;
194                                 }
195                         }
196                 }
197                 else if(components == 3) {
198                         assert(pass.components == 4);
199
200                         /* RGBA */
201                         if(type == PASS_SHADOW) {
202                                 for(int i = 0; i < size; i++, in += pass_stride, pixels += 3) {
203                                         float4 f = make_float4(in[0], in[1], in[2], in[3]);
204                                         float invw = (f.w > 0.0f)? 1.0f/f.w: 1.0f;
205
206                                         pixels[0] = f.x*invw;
207                                         pixels[1] = f.y*invw;
208                                         pixels[2] = f.z*invw;
209                                 }
210                         }
211                         else if(pass.divide_type != PASS_NONE) {
212                                 /* RGB lighting passes that need to divide out color */
213                                 pass_offset = 0;
214                                 foreach(Pass& color_pass, params.passes) {
215                                         if(color_pass.type == pass.divide_type)
216                                                 break;
217                                         pass_offset += color_pass.components;
218                                 }
219
220                                 float *in_divide = (float*)buffer.data_pointer + pass_offset;
221
222                                 for(int i = 0; i < size; i++, in += pass_stride, in_divide += pass_stride, pixels += 3) {
223                                         float3 f = make_float3(in[0], in[1], in[2]);
224                                         float3 f_divide = make_float3(in_divide[0], in_divide[1], in_divide[2]);
225
226                                         f = safe_divide_color(f*exposure, f_divide);
227
228                                         pixels[0] = f.x;
229                                         pixels[1] = f.y;
230                                         pixels[2] = f.z;
231                                 }
232                         }
233                         else {
234                                 /* RGB/vector */
235                                 for(int i = 0; i < size; i++, in += pass_stride, pixels += 3) {
236                                         float3 f = make_float3(in[0], in[1], in[2]);
237
238                                         pixels[0] = f.x*scale_exposure;
239                                         pixels[1] = f.y*scale_exposure;
240                                         pixels[2] = f.z*scale_exposure;
241                                 }
242                         }
243                 }
244                 else if(components == 4) {
245                         assert(pass.components == components);
246
247                         /* RGBA */
248                         if(type == PASS_SHADOW) {
249                                 for(int i = 0; i < size; i++, in += pass_stride, pixels += 4) {
250                                         float4 f = make_float4(in[0], in[1], in[2], in[3]);
251                                         float invw = (f.w > 0.0f)? 1.0f/f.w: 1.0f;
252
253                                         pixels[0] = f.x*invw;
254                                         pixels[1] = f.y*invw;
255                                         pixels[2] = f.z*invw;
256                                         pixels[3] = 1.0f;
257                                 }
258                         }
259                         else if(type == PASS_MOTION) {
260                                 /* need to normalize by number of samples accumulated for motion */
261                                 pass_offset = 0;
262                                 foreach(Pass& color_pass, params.passes) {
263                                         if(color_pass.type == PASS_MOTION_WEIGHT)
264                                                 break;
265                                         pass_offset += color_pass.components;
266                                 }
267
268                                 float *in_weight = (float*)buffer.data_pointer + pass_offset;
269
270                                 for(int i = 0; i < size; i++, in += pass_stride, in_weight += pass_stride, pixels += 4) {
271                                         float4 f = make_float4(in[0], in[1], in[2], in[3]);
272                                         float w = in_weight[0];
273                                         float invw = (w > 0.0f)? 1.0f/w: 0.0f;
274
275                                         pixels[0] = f.x*invw;
276                                         pixels[1] = f.y*invw;
277                                         pixels[2] = f.z*invw;
278                                         pixels[3] = f.w*invw;
279                                 }
280                         }
281                         else {
282                                 for(int i = 0; i < size; i++, in += pass_stride, pixels += 4) {
283                                         float4 f = make_float4(in[0], in[1], in[2], in[3]);
284
285                                         pixels[0] = f.x*scale_exposure;
286                                         pixels[1] = f.y*scale_exposure;
287                                         pixels[2] = f.z*scale_exposure;
288
289                                         /* clamp since alpha might be > 1.0 due to russian roulette */
290                                         pixels[3] = clamp(f.w*scale, 0.0f, 1.0f);
291                                 }
292                         }
293                 }
294
295                 return true;
296         }
297
298         return false;
299 }
300
301 /* Display Buffer */
302
303 DisplayBuffer::DisplayBuffer(Device *device_)
304 {
305         device = device_;
306         draw_width = 0;
307         draw_height = 0;
308         transparent = true; /* todo: determine from background */
309 }
310
311 DisplayBuffer::~DisplayBuffer()
312 {
313         device_free();
314 }
315
316 void DisplayBuffer::device_free()
317 {
318         if(rgba.device_pointer) {
319                 device->pixels_free(rgba);
320                 rgba.clear();
321         }
322 }
323
324 void DisplayBuffer::reset(Device *device, BufferParams& params_)
325 {
326         draw_width = 0;
327         draw_height = 0;
328
329         params = params_;
330
331         /* free existing buffers */
332         device_free();
333
334         /* allocate display pixels */
335         rgba.resize(params.width, params.height);
336         device->pixels_alloc(rgba);
337 }
338
339 void DisplayBuffer::draw_set(int width, int height)
340 {
341         assert(width <= params.width && height <= params.height);
342
343         draw_width = width;
344         draw_height = height;
345 }
346
347 void DisplayBuffer::draw(Device *device)
348 {
349         if(draw_width != 0 && draw_height != 0) {
350                 glPushMatrix();
351                 glTranslatef(params.full_x, params.full_y, 0.0f);
352
353                 device->draw_pixels(rgba, 0, draw_width, draw_height, 0, params.width, params.height, transparent);
354
355                 glPopMatrix();
356         }
357 }
358
359 bool DisplayBuffer::draw_ready()
360 {
361         return (draw_width != 0 && draw_height != 0);
362 }
363
364 void DisplayBuffer::write(Device *device, const string& filename)
365 {
366         int w = draw_width;
367         int h = draw_height;
368
369         if(w == 0 || h == 0)
370                 return;
371
372         /* read buffer from device */
373         device->pixels_copy_from(rgba, 0, w, h);
374
375         /* write image */
376         ImageOutput *out = ImageOutput::create(filename);
377         ImageSpec spec(w, h, 4, TypeDesc::UINT8);
378         int scanlinesize = w*4*sizeof(uchar);
379
380         out->open(filename, spec);
381
382         /* conversion for different top/bottom convention */
383         out->write_image(TypeDesc::UINT8,
384                 (uchar*)rgba.data_pointer + (h-1)*scanlinesize,
385                 AutoStride,
386                 -scanlinesize,
387                 AutoStride);
388
389         out->close();
390
391         delete out;
392 }
393
394 CCL_NAMESPACE_END
395