Cycles: svn merge -r41225:41232 ^/trunk/blender
[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_hash.h"
26 #include "util_image.h"
27 #include "util_math.h"
28 #include "util_opengl.h"
29 #include "util_time.h"
30 #include "util_types.h"
31
32 CCL_NAMESPACE_BEGIN
33
34 /* Render Buffers */
35
36 RenderBuffers::RenderBuffers(Device *device_)
37 {
38         device = device_;
39         width = 0;
40         height = 0;
41 }
42
43 RenderBuffers::~RenderBuffers()
44 {
45         device_free();
46 }
47
48 void RenderBuffers::device_free()
49 {
50         if(buffer.device_pointer) {
51                 device->mem_free(buffer);
52                 buffer.clear();
53         }
54
55         if(rng_state.device_pointer) {
56                 device->mem_free(rng_state);
57                 rng_state.clear();
58         }
59 }
60
61 void RenderBuffers::reset(Device *device, int width_, int height_)
62 {
63         width = width_;
64         height = height_;
65
66         /* free existing buffers */
67         device_free();
68         
69         /* allocate buffer */
70         buffer.resize(width, height);
71         device->mem_alloc(buffer, MEM_READ_WRITE);
72         device->mem_zero(buffer);
73
74         /* allocate rng state */
75         rng_state.resize(width, height);
76
77         uint *init_state = rng_state.resize(width, height);
78         int x, y;
79         
80         for(x=0; x<width; x++)
81                 for(y=0; y<height; y++)
82                         init_state[x + y*width] = hash_int_2d(x, y);
83
84         device->mem_alloc(rng_state, MEM_READ_WRITE);
85         device->mem_copy_to(rng_state);
86 }
87
88 float4 *RenderBuffers::copy_from_device(float exposure, int sample)
89 {
90         if(!buffer.device_pointer)
91                 return NULL;
92
93         device->mem_copy_from(buffer, 0, buffer.memory_size());
94
95         float4 *out = new float4[width*height];
96         float4 *in = (float4*)buffer.data_pointer;
97         float scale = 1.0f/(float)sample;
98         
99         for(int i = width*height - 1; i >= 0; i--) {
100                 float4 rgba = in[i]*scale;
101
102                 rgba.x = rgba.x*exposure;
103                 rgba.y = rgba.y*exposure;
104                 rgba.z = rgba.z*exposure;
105
106                 /* clamp since alpha might be > 1.0 due to russian roulette */
107                 rgba.w = clamp(rgba.w, 0.0f, 1.0f);
108
109                 out[i] = rgba;
110         }
111
112         return out;
113 }
114
115 /* Display Buffer */
116
117 DisplayBuffer::DisplayBuffer(Device *device_)
118 {
119         device = device_;
120         width = 0;
121         height = 0;
122         draw_width = 0;
123         draw_height = 0;
124         transparent = true; /* todo: determine from background */
125 }
126
127 DisplayBuffer::~DisplayBuffer()
128 {
129         device_free();
130 }
131
132 void DisplayBuffer::device_free()
133 {
134         if(rgba.device_pointer) {
135                 device->pixels_free(rgba);
136                 rgba.clear();
137         }
138 }
139
140 void DisplayBuffer::reset(Device *device, int width_, int height_)
141 {
142         draw_width = 0;
143         draw_height = 0;
144
145         width = width_;
146         height = height_;
147
148         /* free existing buffers */
149         device_free();
150
151         /* allocate display pixels */
152         rgba.resize(width, height);
153         device->pixels_alloc(rgba);
154 }
155
156 void DisplayBuffer::draw_set(int width_, int height_)
157 {
158         assert(width_ <= width && height_ <= height);
159
160         draw_width = width_;
161         draw_height = height_;
162 }
163
164 void DisplayBuffer::draw_transparency_grid()
165 {
166         GLubyte checker_stipple_sml[32*32/8] = {
167                 255,0,255,0,255,0,255,0,255,0,255,0,255,0,255,0, \
168                 255,0,255,0,255,0,255,0,255,0,255,0,255,0,255,0, \
169                 0,255,0,255,0,255,0,255,0,255,0,255,0,255,0,255, \
170                 0,255,0,255,0,255,0,255,0,255,0,255,0,255,0,255, \
171                 255,0,255,0,255,0,255,0,255,0,255,0,255,0,255,0, \
172                 255,0,255,0,255,0,255,0,255,0,255,0,255,0,255,0, \
173                 0,255,0,255,0,255,0,255,0,255,0,255,0,255,0,255, \
174                 0,255,0,255,0,255,0,255,0,255,0,255,0,255,0,255, \
175         };
176
177         glColor4ub(50, 50, 50, 255);
178         glRectf(0, 0, width, height);
179         glEnable(GL_POLYGON_STIPPLE);
180         glColor4ub(55, 55, 55, 255);
181         glPolygonStipple(checker_stipple_sml);
182         glRectf(0, 0, width, height);
183         glDisable(GL_POLYGON_STIPPLE);
184 }
185
186 void DisplayBuffer::draw(Device *device)
187 {
188         if(draw_width != 0 && draw_height != 0) {
189                 if(transparent)
190                         draw_transparency_grid();
191
192                 device->draw_pixels(rgba, 0, draw_width, draw_height, width, height, transparent);
193         }
194 }
195
196 bool DisplayBuffer::draw_ready()
197 {
198         return (draw_width != 0 && draw_height != 0);
199 }
200
201 void DisplayBuffer::write(Device *device, const string& filename)
202 {
203         int w = draw_width;
204         int h = draw_height;
205
206         if(w == 0 || h == 0)
207                 return;
208
209         /* read buffer from device */
210         device->pixels_copy_from(rgba, 0, w, h);
211
212         /* write image */
213         ImageOutput *out = ImageOutput::create(filename);
214         ImageSpec spec(w, h, 4, TypeDesc::UINT8);
215         int scanlinesize = w*4*sizeof(uchar);
216
217         out->open(filename, spec);
218
219         /* conversion for different top/bottom convention */
220         out->write_image(TypeDesc::UINT8,
221                 (uchar*)rgba.data_pointer + (h-1)*scanlinesize,
222                 AutoStride,
223                 -scanlinesize,
224                 AutoStride);
225
226         out->close();
227
228         delete out;
229 }
230
231 CCL_NAMESPACE_END
232