root/OpenSceneGraph/trunk/src/osgPlugins/hdr/hdrwriter.cpp @ 12912

Revision 12912, 8.1 kB (checked in by robert, 2 years ago)

Added support for using GL_UNPACK_ROW_LENGTH in conjunction with texture's + osg::Image via new RowLength?
parameter in osg::Image. To support this Image::setData(..) now has a new optional rowLength parameter which
defaults to 0, which provides the original behaviour, Image::setRowLength(int) and int Image::getRowLength() are also provided.

With the introduction of RowLength? support in osg::Image it is now possible to create a sub image where
the t size of the image are smaller than the row length, useful for when you have a large image on the CPU
and which to use a small portion of it on the GPU. However, when these sub images are created the data
within the image is no longer contiguous so data access can no longer assume that all the data is in
one block. The new method Image::isDataContiguous() enables the user to check whether the data is contiguous,
and if not one can either access the data row by row using Image::data(column,row,image) accessor, or use the
new Image::DataIterator? for stepping through each block on memory assocatied with the image.

To support the possibility of non contiguous osg::Image usage of image objects has had to be updated to
check DataContiguous? and handle the case or use access via the DataIerator? or by row by row. To achieve
this a relatively large number of files has had to be modified, in particular the texture classes and
image plugins that doing writing.

  • Property svn:eol-style set to native
Line 
1/*
2 The following code was based on code from the following location:
3    http://www.graphics.cornell.edu/online/formats/rgbe/
4
5 It includes the following information :
6
7    "This file contains code to read and write four byte rgbe file format
8    developed by Greg Ward.  It handles the conversions between rgbe and
9    pixels consisting of floats.  The data is assumed to be an array of floats.
10    By default there are three floats per pixel in the order red, green, blue.
11    (RGBE_DATA_??? values control this.)  Only the mimimal header reading and
12    writing is implemented.  Each routine does error checking and will return
13    a status value as defined below.  This code is intended as a skeleton so
14    feel free to modify it to suit your needs.
15
16    (Place notice here if you modified the code.)
17    posted to http://www.graphics.cornell.edu/~bjw/
18    written by Bruce Walter  (bjw@graphics.cornell.edu)  5/26/95
19    based on code written by Greg Ward"
20
21 Modified for OSG September 2007 david.spilling@gmail.com :
22    The file format is described fully in http://radsite.lbl.gov/radiance/refer/filefmts.pdf
23    For the moment, we don't output most of the header fields
24
25 
26*/
27
28#include <stdlib.h>
29
30#include "hdrwriter.h"
31
32#include <sstream>
33#include <ostream>
34#include <string>
35#include <math.h>
36#include <ctype.h>
37
38
39bool HDRWriter::writeRAW(const osg::Image *img, std::ostream& fout)
40{
41    bool result = true;
42    for(int row=0; result && row<img->t(); ++row)
43    {
44        result = writePixelsRAW(fout,(unsigned char*) img->data(0, row), img->s());
45    }
46    return result;
47}
48
49/* number of floats per pixel */
50#define RGBE_DATA_SIZE   3
51
52/* offsets to red, green, and blue components in a data (float) pixel */
53#define R            0
54#define G            1
55#define B            2
56#define E            3
57
58#define  MINELEN    8                // minimum scanline length for encoding
59#define  MAXELEN    0x7fff            // maximum scanline length for encoding
60
61/* default minimal header. modify if you want more information in header */
62bool HDRWriter::writeHeader(const osg::Image *img, std::ostream& fout)
63{
64    std::stringstream stream;    // for conversion to strings
65
66    stream << "#?RADIANCE\n";    // Could be RGBE, but some 3rd party software doesn't interpret the file correctly
67                                // if it is.
68    stream << "FORMAT=32-bit_rle_rgbe\n\n";
69
70    // Our image data is usually arranged row major, with the origin at the bottom left of the image.
71    // Based on the Radiance file format, this would be "+Y blah +X blah". However, no software (including
72    // HDRShop v1!) seems to support this; they all expect -Y blah +X blah, and then flip the image. This
73    // is unfortunate, and is what provokes the default behaviour of OSG having to flip the image prior to
74    // write.
75    stream << "-Y "<<img->s()<<" +X "<<img->t()<<"\n";
76
77    fout.write(stream.str().c_str(), stream.str().length());
78
79    return true;
80}
81
82/* simple write routine that does not use run length encoding */
83/* These routines can be made faster by allocating a larger buffer and
84   fread-ing and fwrite-ing the data in larger chunks */
85bool HDRWriter::writeNoRLE( std::ostream& fout, const osg::Image* img)
86{
87  unsigned char rgbe[4];
88
89  for(int row=0; row<img->t(); ++row)
90  {
91    float* data = (float*)img->data(0,row);
92    for(int column=0; column<img->s(); ++column)
93    {
94      float2rgbe(
95        rgbe,
96        data[R],
97        data[G],
98        data[B]
99        );
100      data += RGBE_DATA_SIZE;
101      fout.write(reinterpret_cast<const char*>(rgbe), sizeof(rgbe));
102    }
103  }
104
105  return true;
106}
107
108bool HDRWriter::writePixelsRAW( std::ostream& fout, unsigned char* data, int numpixels)
109{
110  unsigned char rgbe[4];
111
112  while (numpixels-- > 0)
113  {
114    rgbe[0] = (unsigned char) *(data+R);
115    rgbe[1] = (unsigned char) *(data+G);
116    rgbe[2] = (unsigned char) *(data+B);
117    rgbe[3] = (unsigned char) *(data+E);
118    data += RGBE_DATA_SIZE;
119    fout.write(reinterpret_cast<const char*>(rgbe), sizeof(rgbe)); //img->getTotalSizeInBytesIncludingMipmaps()
120  }
121  return true;
122}
123
124/* The code below is only needed for the run-length encoded files. */
125/* Run length encoding adds considerable complexity but does */
126/* save some space.  For each scanline, each channel (r,g,b,e) is */
127/* encoded separately for better compression. */
128bool HDRWriter::writeBytesRLE(std::ostream& fout, unsigned char *data, int numbytes)
129{
130#define MINRUNLENGTH 4
131    int cur, beg_run, run_count, old_run_count, nonrun_count;
132    unsigned char buf[2];
133
134    cur = 0;
135    while(cur < numbytes)
136    {
137        beg_run = cur;
138        /* find next run of length at least 4 if one exists */
139        run_count = old_run_count = 0;
140        while((run_count < MINRUNLENGTH) && (beg_run < numbytes))
141        {
142            beg_run += run_count;
143            old_run_count = run_count;
144            run_count = 1;
145            while((data[beg_run] == data[beg_run + run_count])
146                && (beg_run + run_count < numbytes)
147                && (run_count < 127))
148            {
149                run_count++;
150            }
151        }
152        /* if data before next big run is a short run then write it as such */
153        if ((old_run_count > 1)&&(old_run_count == beg_run - cur))
154        {
155            buf[0] = 128 + old_run_count;   /*write short run*/
156            buf[1] = data[cur];
157            fout.write(reinterpret_cast<const char*>(buf), sizeof(buf[0])*2);
158            //if (fwrite(buf,sizeof(buf[0])*2,1,fp) < 1) return false
159            cur = beg_run;
160        }
161        /* write out bytes until we reach the start of the next run */
162        while(cur < beg_run)
163        {
164            nonrun_count = beg_run - cur;
165            if (nonrun_count > 128) nonrun_count = 128;
166            buf[0] = nonrun_count;
167            fout.write(reinterpret_cast<const char*>(buf),sizeof(buf[0]));
168            //if (fwrite(buf,sizeof(buf[0]),1,fp) < 1) return false
169            fout.write(reinterpret_cast<const char*>(&data[cur]),sizeof(data[0])*nonrun_count);
170            // if (fwrite(&data[cur],sizeof(data[0])*nonrun_count,1,fp) < 1) return false;
171            cur += nonrun_count;
172        }
173        /* write out next run if one was found */
174        if (run_count >= MINRUNLENGTH)
175        {
176            buf[0] = 128 + run_count;
177            buf[1] = data[beg_run];
178            fout.write(reinterpret_cast<const char*>(buf),sizeof(buf[0])*2);
179            //if (fwrite(buf,sizeof(buf[0])*2,1,fp) < 1) return false;
180            cur += run_count;
181        }
182    }
183    return true;
184#undef MINRUNLENGTH
185}
186
187bool HDRWriter::writeRLE( const osg::Image* img, std::ostream& fout)
188{
189    int scanline_width = img->s();
190    int num_scanlines = img->t();
191
192    unsigned char rgbe[4];
193    unsigned char *buffer;
194
195    if ((scanline_width < MINELEN)||(scanline_width > MAXELEN))
196        // run length encoding is not allowed so write flat
197        return writeNoRLE(fout,img);
198
199    buffer = (unsigned char *)malloc(sizeof(unsigned char)*4*scanline_width);
200    if (buffer == NULL)
201        // no buffer space so write flat
202        return writeNoRLE(fout,img);
203
204    for(int row = 0; row<num_scanlines; ++row)
205    {
206        float* data = (float*) img->data(0, row);
207       
208        rgbe[0] = 2;
209        rgbe[1] = 2;
210        rgbe[2] = scanline_width >> 8;
211        rgbe[3] = scanline_width & 0xFF;
212
213        fout.write(reinterpret_cast<const char*>(rgbe), sizeof(rgbe));
214        /*
215        if (fwrite(rgbe, sizeof(rgbe), 1, fp) < 1)
216        {
217            free(buffer);
218            return rgbe_error(rgbe_write_error,NULL);
219        }
220        */
221        for(int i=0;i<scanline_width;i++)
222        {
223            float2rgbe(rgbe,data[R], data[G],data[B]);
224            buffer[i] = rgbe[0];
225            buffer[i+scanline_width] = rgbe[1];
226            buffer[i+2*scanline_width] = rgbe[2];
227            buffer[i+3*scanline_width] = rgbe[3];
228            data += RGBE_DATA_SIZE;
229        }
230        /* write out each of the four channels separately run length encoded */
231        /* first red, then green, then blue, then exponent */
232        for(int i=0;i<4;i++)
233        {
234            if (writeBytesRLE(fout,&buffer[i*scanline_width],scanline_width) != true)
235            {
236                free(buffer);
237                return false;
238            }
239        }
240    }
241
242    free(buffer);
243    return true;
244}
Note: See TracBrowser for help on using the browser.