~ubuntu-branches/ubuntu/maverick/blender/maverick

« back to all changes in this revision

Viewing changes to extern/qdune/framebuffer/FrameBuffer.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Khashayar Naderehvandi, Khashayar Naderehvandi, Alessio Treglia
  • Date: 2009-01-22 16:53:59 UTC
  • mfrom: (14.1.1 experimental)
  • Revision ID: james.westby@ubuntu.com-20090122165359-v0996tn7fbit64ni
Tags: 2.48a+dfsg-1ubuntu1
[ Khashayar Naderehvandi ]
* Merge from debian experimental (LP: #320045), Ubuntu remaining changes:
  - Add patch correcting header file locations.
  - Add libvorbis-dev and libgsm1-dev to Build-Depends.
  - Use avcodec_decode_audio2() in source/blender/src/hddaudio.c

[ Alessio Treglia ]
* Add missing previous changelog entries.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
//---------------------------------------------------------------------------------
2
 
// Simple framebuffer for display, uses CImg library by David Tschumperle
3
 
// Currently the whole image exists at once, but it should be modified to
4
 
// write just a single bucket, using some appropriate image format like exr.
5
 
// Similarly, drawing to the display should be one bucket at a time,
6
 
// currently redraws the whole image for every bucket, which is quite 'expensive'.
7
 
// But while there are functions to draw a subimage in another image in CImg,
8
 
// I just can't seem to find (or figure out) something similar for a subrect
9
 
// *display* update. So for now this is taken care of by the hider,
10
 
// which passes a flag to only draw every column/row.
11
 
//---------------------------------------------------------------------------------
12
 
 
13
 
#include "FrameBuffer.h"
14
 
#include "Color.h"
15
 
#include "Mathutil.h"
16
 
#include "Transform.h"
17
 
#include "State.h"
18
 
#include <iostream>
19
 
#include <cstdio>
20
 
 
21
 
// VC8 warn flags
22
 
#ifdef _MSC_VER
23
 
#pragma warning(disable : 4996)
24
 
#pragma warning(disable : 4312)
25
 
#pragma warning(disable : 4311)
26
 
#endif
27
 
 
28
 
// bcb flags removed
29
 
 
30
 
#ifdef WITH_CIMG
31
 
// though here only used for its multiplatform display features,
32
 
// the CImg library by David Tschumperle is an extremely nice
33
 
// general image processing library, all in one include file
34
 
#if defined (__GNUC__) && !defined(__SVR4)
35
 
// somewhat faster display update
36
 
#define cimg_use_xshm
37
 
#endif
38
 
#include "CImg.h"
39
 
#endif
40
 
 
41
 
#include "exr_io.h"
42
 
 
43
 
#include "QDRender.h"
44
 
__BEGIN_QDRENDER
45
 
 
46
 
#ifdef WITH_CIMG
47
 
// framebuffer display
48
 
static cimg_library::CImgDisplay* fbdisplay = NULL;
49
 
static cimg_library::CImg<unsigned char>* fbdisplay_img = NULL;
50
 
#endif
51
 
 
52
 
// ctor
53
 
FrameBuffer::FrameBuffer(const Options& options)
54
 
{
55
 
        fbdata = NULL;
56
 
        ortho = (options.projection == Options::PROJ_ORTHOGRAPHIC);
57
 
 
58
 
        // start coords with respect to cropwindow
59
 
        xstart = CLAMP(CEILI(options.xRes*options.xMin), 0, options.xRes-1);
60
 
        ystart = CLAMP(CEILI(options.yRes*options.yMin), 0, options.yRes-1);
61
 
        const int xend = CLAMP(CEILI(options.xRes*options.xMax-1), 0, options.xRes-1);
62
 
        const int yend = CLAMP(CEILI(options.yRes*options.yMax-1), 0, options.yRes-1);
63
 
        // width & height with respect to cropwindow, one pixel minimum
64
 
        width = xend - xstart + 1;
65
 
        height = yend - ystart + 1;
66
 
 
67
 
        // mode, as above, default is RI_RGB, error check during parse
68
 
        mode = MD_RGB;
69
 
        dataPerPix = 3;
70
 
        if (options.displayMode == Options::DM_Z)
71
 
                { mode=MD_Z;  dataPerPix=1; }
72
 
        else if (options.displayMode == Options::DM_A)
73
 
                { mode=MD_A;  dataPerPix=1; }
74
 
        else if (options.displayMode == Options::DM_AZ)
75
 
                { mode=MD_AZ;  dataPerPix=2; }
76
 
        else if (options.displayMode == Options::DM_RGBA)
77
 
                { mode=MD_RGBA;  dataPerPix=4; }
78
 
        else if (options.displayMode == Options::DM_RGBZ)
79
 
                { mode=MD_RGBZ;  dataPerPix=4; }
80
 
        else if (options.displayMode ==  Options::DM_RGBAZ)
81
 
                { mode=MD_RGBAZ;  dataPerPix=5; }
82
 
 
83
 
        //type
84
 
        if (options.displayType == Options::DT_FILE)
85
 
                type = TP_FILE;
86
 
        else if (options.displayType == Options::DT_ZFILE)
87
 
                type = TP_ZFILE;
88
 
        else if  (options.displayType == Options::DT_FRAMEBUFFER)
89
 
                type = TP_FRAMEBUFFER;
90
 
 
91
 
        // display name, 80 max chars
92
 
        strncpy(dispname, options.displayName, 80);
93
 
 
94
 
        // RiExposure
95
 
        gain = options.gain;
96
 
        gamma = options.gamma;
97
 
 
98
 
        // color quantizer
99
 
        colQ.one = options.cqOne;
100
 
        colQ.minimum = options.cqMin;
101
 
        colQ.maximum = options.cqMax;
102
 
        colQ.dither_amplitude = options.cqDitherAmplitude;
103
 
 
104
 
        // depth quantizer, actually not used at all, might as well remove...
105
 
        depthQ.one = options.zqOne;
106
 
        depthQ.minimum = options.zqMin;
107
 
        depthQ.maximum = options.zqMax;
108
 
        depthQ.dither_amplitude = options.zqDitherAmplitude;
109
 
 
110
 
        // buffer init, float per data element
111
 
        unsigned int sz =  width * height * dataPerPix;
112
 
        fbdata = new float[sz];
113
 
        // clear
114
 
        memset(fbdata, 0, sz*sizeof(float));
115
 
 
116
 
        // the quantized color buffer, only used for file mode
117
 
        qdata = NULL;
118
 
 
119
 
#ifdef WITH_CIMG
120
 
        // init. display if 'framebuffer'
121
 
        if (type == TP_FRAMEBUFFER) {
122
 
                // always just rgb, conversion is handled in toImage() below
123
 
                fbdisplay_img = new cimg_library::CImg<unsigned char>(width, height, 1, 3, 0);
124
 
                fbdisplay = new cimg_library::CImgDisplay(*fbdisplay_img, dispname, 0);
125
 
                // the ubiquitous checkerboard background pattern, white & grey bucketsize rectangles
126
 
                const int bucketsize = options.bucketsize;
127
 
                for (unsigned int y=0; y<=(height/bucketsize); ++y) {
128
 
                        for (unsigned int x=0; x<=(width/bucketsize); ++x) {
129
 
                                unsigned char col  = (unsigned char)(((x & 1) ^ (y & 1)) ? 128 : 255);
130
 
                                for (unsigned int sy=y*bucketsize; sy<(y+1)*bucketsize; ++sy) {
131
 
                                        if (sy >= height) continue;
132
 
                                        for (unsigned int sx=x*bucketsize; sx<(x+1)*bucketsize; ++sx) {
133
 
                                                if (sx >= width) continue;
134
 
                                                (*fbdisplay_img)(sx, sy, 0) = (*fbdisplay_img)(sx, sy, 1) = (*fbdisplay_img)(sx, sy, 2) = col;
135
 
                                        }
136
 
                                }
137
 
                        }
138
 
                }
139
 
                fbdisplay->display(*fbdisplay_img);
140
 
        }
141
 
#else
142
 
        if (type == TP_FRAMEBUFFER)
143
 
                std::cout << "Cannot display, CImg not enabled, writing to file instead." << std::endl;
144
 
#endif
145
 
 
146
 
}
147
 
 
148
 
// dtor
149
 
FrameBuffer::~FrameBuffer()
150
 
{
151
 
        // free alloc'ed data
152
 
#ifdef WITH_CIMG
153
 
        if (fbdisplay_img) delete fbdisplay_img;
154
 
        if (fbdisplay) {
155
 
                fbdisplay->close();
156
 
                delete fbdisplay;
157
 
        }
158
 
#endif
159
 
        if (qdata) delete[] qdata;
160
 
        if (fbdata) delete[] fbdata;
161
 
}
162
 
 
163
 
void FrameBuffer::operator()(int x, int y, float rgbaz[5])
164
 
{
165
 
        x -= xstart, y -= ystart;
166
 
        if ((x < 0) or (y < 0) or (x >= (int)width) or (y >= (int)height)) return;
167
 
        unsigned int ofs = (x + y*width) * dataPerPix;
168
 
        switch (mode) {
169
 
                case MD_A:
170
 
                        fbdata[ofs] = rgbaz[3];
171
 
                        break;
172
 
                case MD_Z:
173
 
                        fbdata[ofs] = rgbaz[4];
174
 
                        break;
175
 
                case MD_AZ:
176
 
                        fbdata[ofs++] = rgbaz[3];
177
 
                        fbdata[ofs] = rgbaz[4];
178
 
                        break;
179
 
                case MD_RGBA:
180
 
                        fbdata[ofs++] = rgbaz[0];
181
 
                        fbdata[ofs++] = rgbaz[1];
182
 
                        fbdata[ofs++] = rgbaz[2];
183
 
                        fbdata[ofs] = rgbaz[3];
184
 
                        break;
185
 
                case MD_RGBZ:
186
 
                        fbdata[ofs++] = rgbaz[0];
187
 
                        fbdata[ofs++] = rgbaz[1];
188
 
                        fbdata[ofs++] = rgbaz[2];
189
 
                        fbdata[ofs] = rgbaz[4];
190
 
                        break;
191
 
                case MD_RGBAZ:
192
 
                        fbdata[ofs++] = rgbaz[0];
193
 
                        fbdata[ofs++] = rgbaz[1];
194
 
                        fbdata[ofs++] = rgbaz[2];
195
 
                        fbdata[ofs++] = rgbaz[3];
196
 
                        fbdata[ofs] = rgbaz[4];
197
 
                        break;
198
 
                default:
199
 
                case MD_RGB:
200
 
                        fbdata[ofs++] = rgbaz[0];
201
 
                        fbdata[ofs++] = rgbaz[1];
202
 
                        fbdata[ofs] = rgbaz[2];
203
 
        }
204
 
}
205
 
 
206
 
// Quantize image or given subrect with start coords (xs,ys) & end coords (xe,ye)
207
 
void FrameBuffer::quantizeImage()
208
 
{
209
 
        if (fbdata==NULL) return;
210
 
 
211
 
        int dpx = (dataPerPix <= 3) ? 3 : 4;
212
 
        qdata = new unsigned char[width*height*dpx];
213
 
 
214
 
        const float igam = (gamma==0.f) ? 1.f : (1.f/ABS(gamma));
215
 
 
216
 
        for (unsigned int y=0; y<height; ++y) {
217
 
                for (unsigned int x=0; x<width; ++x) {
218
 
 
219
 
                        float* data = &fbdata[(x + y*width) * dataPerPix];
220
 
                        float fr=0, fg=0, fb=0, fa=1;
221
 
                        switch (dataPerPix) {
222
 
                                // Z case is handled separately
223
 
                                case 1:
224
 
                                case 2:
225
 
                                {
226
 
                                        // MD_A or MD_AZ (Z is not saved in image, handled separately)
227
 
                                        fr = fg = fb = 0, fa = 1.f-data[0];
228
 
                                        break;
229
 
                                }
230
 
                                case 3:
231
 
                                {
232
 
                                        fr = data[0];
233
 
                                        fg = data[1];
234
 
                                        fb = data[2];
235
 
                                        break;
236
 
                                }
237
 
                                case 4:
238
 
                                case 5:
239
 
                                {
240
 
                                        // rgba, composite on top of background
241
 
                                        fa = 1.f - data[3];
242
 
                                        fr = data[0] + fa*data[0];
243
 
                                        fg = data[1] + fa*data[1];
244
 
                                        fb = data[2] + fa*data[2];
245
 
                                }
246
 
                        }
247
 
 
248
 
                        // 'exposure' & gamma
249
 
                        if (gain != 1.f) {
250
 
                                fr *= gain;  fg *= gain;  fb *= gain;
251
 
                        }
252
 
                        if (igam != 1.f){
253
 
                                fr = pow(CLAMP0(fr), igam);
254
 
                                fg = pow(CLAMP0(fg), igam);
255
 
                                fb = pow(CLAMP0(fb), igam);
256
 
                        }
257
 
 
258
 
                        // quantize
259
 
                        unsigned char* qd = &qdata[(x + y*width)*dpx];
260
 
                        qd[0] = (unsigned char)CLAMP((int)(0.5f + colQ.one*fr + colQ.dither_amplitude*frand()), colQ.minimum, colQ.maximum);
261
 
                        qd[1] = (unsigned char)CLAMP((int)(0.5f + colQ.one*fg + colQ.dither_amplitude*frand()), colQ.minimum, colQ.maximum);
262
 
                        qd[2] = (unsigned char)CLAMP((int)(0.5f + colQ.one*fb + colQ.dither_amplitude*frand()), colQ.minimum, colQ.maximum);
263
 
                        if (dpx==4)
264
 
                                qd[3] = (unsigned char)CLAMP((int)(0.5f + colQ.one*fa + colQ.dither_amplitude*frand()), colQ.minimum, colQ.maximum);
265
 
 
266
 
                }
267
 
        }
268
 
}
269
 
 
270
 
// save the image as a raw targa file
271
 
bool FrameBuffer::saveImage()
272
 
{
273
 
        if (qdata==NULL) return false;
274
 
        // raw tga output for now
275
 
        // name is assigned by default
276
 
        std::cout << "Saving Targa file as " << dispname << std::endl;
277
 
 
278
 
        const unsigned char TGAHDR[12] = {0, 0, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0};
279
 
 
280
 
        FILE* fp;
281
 
        unsigned short w, h, x, y;
282
 
        unsigned char* yscan;
283
 
        unsigned char btsdesc[2];
284
 
        unsigned int dto;
285
 
        int dpx = (dataPerPix <= 3) ? 3 : 4;
286
 
        if (dpx==4) {
287
 
                btsdesc[0] = 0x20; // 32 bits
288
 
                btsdesc[1] = 0x28; // topleft / 8 bit alpha
289
 
        }
290
 
        else {
291
 
                btsdesc[0] = 0x18; // 24 bits
292
 
                btsdesc[1] = 0x20; // topleft / no alpha
293
 
        }
294
 
        w = (unsigned short)width;
295
 
        h = (unsigned short)height;
296
 
        fp = fopen(dispname, "wb");
297
 
        if (fp == NULL) {
298
 
                std::cout << "Could not open file for writing!\n";
299
 
                return false;
300
 
        }
301
 
        fwrite(&TGAHDR, 12, 1, fp);
302
 
        fputc(w, fp);
303
 
        fputc(w >> 8, fp);
304
 
        fputc(h, fp);
305
 
        fputc(h >> 8, fp);
306
 
        fwrite(&btsdesc, 2, 1, fp);
307
 
        for (y=0; y<h; y++) {
308
 
                // swap R & B channels
309
 
                dto = y*w;
310
 
                yscan = &qdata[dto*dpx];
311
 
                for (x=0; x<w; x++, yscan+=dpx) {
312
 
                        fputc(*(yscan+2), fp);
313
 
                        fputc(*(yscan+1), fp);
314
 
                        fputc(*yscan,  fp);
315
 
                        if (dpx==4) fputc(*(yscan+3), fp);
316
 
                }
317
 
        }
318
 
        fclose(fp);
319
 
        std::cout << "OK" << std::endl;
320
 
        return true;
321
 
}
322
 
 
323
 
 
324
 
bool FrameBuffer::saveZ()
325
 
{
326
 
        // handles Z data only, MD_AZ/MD_RGBAZ not yet
327
 
        if ((fbdata==NULL) || (mode!=MD_Z)) return false;
328
 
        std::cout << "Saving Z file as " << dispname << std::endl;
329
 
        Transform w2c = *State::Instance()->getNamedCoordSys("world"), 
330
 
                  c2r = State::Instance()->cam.getCam2Ras();
331
 
        //char fname[512] = {0};
332
 
        //Options options = State::Instance()->topOptions();
333
 
        //snprintf(fname, 512, "%s%s", options.basepath, dispname);
334
 
        writeTiledZ(dispname, fbdata, width, height, (ortho ? 1 : 0), *w2c.getRtMatrixPtr(), *c2r.getRtMatrixPtr());
335
 
        return true;
336
 
}
337
 
 
338
 
 
339
 
void FrameBuffer::finalize()
340
 
{
341
 
#ifdef WITH_CIMG
342
 
        if (fbdisplay_img) {
343
 
                // draw final scanline block too
344
 
                fbdisplay->display(*fbdisplay_img);
345
 
                // framebuffer, wait until window closed
346
 
                std::cout << "Close display window or press ESC key to quit...\n";
347
 
                while (!fbdisplay->is_closed && (fbdisplay->key!=cimg_library::cimg::keyESC))
348
 
                        fbdisplay->wait();
349
 
                return;
350
 
        }
351
 
#endif
352
 
        // file, z file is saved as float
353
 
        if (type == TP_ZFILE)
354
 
                saveZ();
355
 
        else    {
356
 
                // this still includes the AZ & RGBAZ cases, not sure what to do about that yet,
357
 
                // will be very straightforward with exr support though... TODO
358
 
                quantizeImage();
359
 
                saveImage();
360
 
        }
361
 
}
362
 
 
363
 
// bucket to display, only used in framebuffer mode
364
 
void FrameBuffer::toImage(int bx, int by, int bw, int bh, bool draw)
365
 
{
366
 
#ifdef WITH_CIMG
367
 
        if (fbdisplay==NULL) return;
368
 
 
369
 
        // just exit if window closed
370
 
        if (fbdisplay->is_closed)
371
 
                exit(0);
372
 
 
373
 
        float fr, fg, fb;
374
 
        const float igam = (gamma==0.f) ? 1.f : (1.f/ABS(gamma));
375
 
 
376
 
        const unsigned int chanofs = width*height;
377
 
 
378
 
        for (int y=by; y<(by+bh); y++) {
379
 
                if (y >= (int)height)continue;
380
 
                const unsigned int yx = y*width;
381
 
                for (int x=bx; x<(bx+bw); x++) {
382
 
                        if (x >= (int)width) continue;
383
 
 
384
 
                        const float* data = &fbdata[(x + yx) * dataPerPix];
385
 
                        fr = fg = fb = 0;
386
 
                        // display color channel indices
387
 
                        const unsigned int idxR = x + y*width;
388
 
                        const unsigned int idxG = idxR + chanofs;
389
 
                        const unsigned int idxB = idxG + chanofs;
390
 
                        switch (dataPerPix) {
391
 
                                // z not handled yet
392
 
                                case 1:
393
 
                                        fr = fg = fb = data[0]*0.0001f; // scale to make depth more visible, temporary
394
 
                                        break;
395
 
                                case 2:
396
 
                                        fr = fg = fb = data[0];
397
 
                                        break;
398
 
                                case 3:
399
 
                                        fr = data[0];
400
 
                                        fg = data[1];
401
 
                                        fb = data[2];
402
 
                                        break;
403
 
                                case 4:
404
 
                                case 5:
405
 
                                        // rgba, composite on top of display background.
406
 
                                        // side effect here is that background will also be affected by gam/exp
407
 
                                        // though this might actually be useful as progress visual feedback.
408
 
                                        // and only display is affected anyway, not actual picture
409
 
                                        const float ia = (1.f - data[3])*(1.f/255.f);
410
 
                                        fr = data[0] + ia*fbdisplay_img->data[idxR];
411
 
                                        fg = data[1] + ia*fbdisplay_img->data[idxG];
412
 
                                        fb = data[2] + ia*fbdisplay_img->data[idxB];
413
 
                        }
414
 
 
415
 
                        // 'exposure' & gamma
416
 
                        if (igam != 1.f) {
417
 
                                fr = (fr < 0.f) ? 0.f : powf(fr*gain, igam);
418
 
                                fg = (fg < 0.f) ? 0.f : powf(fg*gain, igam);
419
 
                                fb = (fb < 0.f) ? 0.f : powf(fb*gain, igam);
420
 
                        }
421
 
 
422
 
                        // quantize and set pixel
423
 
                        // R
424
 
                        fbdisplay_img->data[idxR] = (unsigned char)CLAMP((int)(0.5f + colQ.one*fr + colQ.dither_amplitude*frand()), colQ.minimum, colQ.maximum);
425
 
                        // G
426
 
                        fbdisplay_img->data[idxG] = (unsigned char)CLAMP((int)(0.5f + colQ.one*fg + colQ.dither_amplitude*frand()), colQ.minimum, colQ.maximum);
427
 
                        // B
428
 
                        fbdisplay_img->data[idxB] = (unsigned char)CLAMP((int)(0.5f + colQ.one*fb + colQ.dither_amplitude*frand()), colQ.minimum, colQ.maximum);
429
 
 
430
 
                }
431
 
        }
432
 
        // only redraw image if draw == true
433
 
        if (draw) fbdisplay->display(*fbdisplay_img);
434
 
#endif
435
 
}
436
 
 
437
 
__END_QDRENDER