Tidying.
[synfig.git] / synfig-core / trunk / src / modules / mod_mng / trgt_mng.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file trgt_mng.cpp
3 **      \brief MNG Target Module
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright 2007 Paul Wise
9 **
10 **      This package is free software; you can redistribute it and/or
11 **      modify it under the terms of the GNU General Public License as
12 **      published by the Free Software Foundation; either version 2 of
13 **      the License, or (at your option) any later version.
14 **
15 **      This package is distributed in the hope that it will be useful,
16 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 **      General Public License for more details.
19 **      \endlegal
20 **
21 ** === N O T E S ===========================================================
22 **
23 ** FIXME: THIS DOES NOT ACTUALLY WORK YET
24 **
25 ** You will need to read the PNG and MNG specs to understand this code
26 **
27 ** ========================================================================= */
28
29 /* === H E A D E R S ======================================================= */
30
31 #define SYNFIG_TARGET
32
33 #ifdef USING_PCH
34 #       include "pch.h"
35 #else
36 #ifdef HAVE_CONFIG_H
37 #       include <config.h>
38 #endif
39
40 #include "trgt_mng.h"
41 #include <libmng.h>
42 #include <ETL/stringf>
43 #include <cstdio>
44 #include <algorithm>
45 #include <functional>
46 #include <ETL/misc>
47
48 #endif
49
50 /* === M A C R O S ========================================================= */
51
52 using namespace synfig;
53 using namespace std;
54 using namespace etl;
55
56 /* === G L O B A L S ======================================================= */
57
58 SYNFIG_TARGET_INIT(mng_trgt);
59 SYNFIG_TARGET_SET_NAME(mng_trgt,"mng");
60 SYNFIG_TARGET_SET_EXT(mng_trgt,"mng");
61 SYNFIG_TARGET_SET_VERSION(mng_trgt,"0.1");
62 SYNFIG_TARGET_SET_CVS_ID(mng_trgt,"$Id$");
63
64 /* === M E T H O D S ======================================================= */
65
66 static mng_ptr MNG_DECL
67 mng_alloc_proc(mng_size_t size)
68 {
69         return (mng_ptr)calloc(1,size);
70 }
71
72 static void MNG_DECL
73 mng_free_proc(mng_ptr ptr, mng_size_t size)
74 {
75         free(ptr); return;
76 }
77
78 static mng_bool MNG_DECL
79 mng_null_proc(mng_handle mng)
80 {
81         synfig::error("mng_trgt: error: mng_null_proc");
82         return MNG_TRUE;
83 }
84
85 static mng_bool MNG_DECL
86 mng_write_proc(mng_handle mng, mng_ptr buf, mng_uint32 size, mng_uint32* written)
87 {
88         synfig::error("mng_trgt: error: mng_write_proc");
89         FILE* file = (FILE*)mng_get_userdata (mng);
90         *written = fwrite(buf, 1, size, file);
91         return MNG_TRUE;
92 }
93
94 static mng_bool MNG_DECL
95 mng_error_proc(mng_handle mng, mng_int32 error, mng_int8 severity, mng_chunkid chunkname,
96                            mng_uint32 chunkseq, mng_int32 extra1, mng_int32 extra2, mng_pchar errortext)
97 {
98         // mng_trgt* me =
99         (mng_trgt*)mng_get_userdata (mng);
100         fprintf(stderr,"mng_trgt: error: %s",errortext);
101         // me->ready=false;
102         return MNG_TRUE;
103 }
104
105 mng_trgt::mng_trgt(const char *Filename):
106         filename(Filename)
107 {
108         file=NULL;
109         buffer=NULL;
110         color_buffer=NULL;      
111         zbuffer=NULL;   
112         zbuffer_len=0;
113         ready=false;
114 }
115
116 mng_trgt::~mng_trgt()
117 {
118         synfig::error("mng_trgt: error: ~mng_trgt");
119         if (mng != MNG_NULL)
120         {
121                 mng_putchunk_mend(mng);
122                 if (mng_write(mng) != 0 )
123                 {
124                         mng_int8 severity;
125                         mng_chunkid chunkname;
126                         mng_uint32 chunkseq;
127                         mng_int32 extra1;
128                         mng_int32 extra2;
129                         mng_pchar errortext;
130                         mng_getlasterror(mng, &severity, &chunkname, &chunkseq, &extra1,&extra2, &errortext);
131                         synfig::error("mng_trgt: error: couldn't write mng: %s",errortext);
132                 }
133                 mng_cleanup (&mng);
134         }
135         if (file != NULL ) fclose(file); file=NULL;
136         if (buffer != NULL ) { delete [] buffer; buffer = NULL; }
137         if (color_buffer != NULL ) { delete [] color_buffer; color_buffer = NULL; }
138         if (zbuffer != NULL ) { free(zbuffer); zbuffer = NULL; zbuffer_len = 0; }
139 }
140
141 bool
142 mng_trgt::set_rend_desc(RendDesc *given_desc)
143 {
144         desc=*given_desc;
145         imagecount=desc.get_frame_start();
146         if(desc.get_frame_end()-desc.get_frame_start()>0)
147                 multi_image=true;
148         else
149                 multi_image=false;
150         return true;
151 }
152
153
154 bool
155 mng_trgt::init()
156 {
157         time_t t = time (NULL);
158         struct tm* gmt = gmtime(&t);
159         w=desc.get_w(); h=desc.get_h();
160         //synfig::error("mng_trgt: init %d %d",w,h); 
161         file = fopen(filename.c_str(), POPEN_BINARY_WRITE_TYPE);
162         if (file == NULL ) goto cleanup_on_error;
163         mng = mng_initialize((mng_ptr)file, mng_alloc_proc, mng_free_proc, MNG_NULL);
164         if(mng == MNG_NULL) goto cleanup_on_error;
165         if (mng_setcb_errorproc(mng, mng_error_proc) != 0 ) goto cleanup_on_error;
166         if (mng_setcb_writedata(mng, mng_write_proc) != 0 ) goto cleanup_on_error;
167         if (mng_setcb_openstream(mng, mng_null_proc) != 0 ) goto cleanup_on_error;
168         if (mng_setcb_closestream(mng, mng_null_proc) != 0 ) goto cleanup_on_error;
169         if (mng_create(mng) != 0 ) goto cleanup_on_error;
170         if (mng_putchunk_mhdr(mng, w, h, multi_image?1000:0, 1, desc.get_frame_end()-desc.get_frame_start(), 0, 0) != 0 ) goto cleanup_on_error;
171         if (mng_putchunk_term(mng, MNG_TERMACTION_REPEAT, MNG_ITERACTION_LASTFRAME, 0, 0x7fffffff) != 0 ) goto cleanup_on_error;
172         if (mng_putchunk_text(mng, sizeof(MNG_TEXT_TITLE), MNG_TEXT_TITLE, get_canvas()->get_name().length(), const_cast<char *>(get_canvas()->get_name().c_str()) ) != 0 ) goto cleanup_on_error;
173         if (mng_putchunk_text(mng, sizeof(MNG_TEXT_DESCRIPTION), MNG_TEXT_DESCRIPTION, get_canvas()->get_description().length(), const_cast<char *>(get_canvas()->get_description().c_str()) ) != 0 ) goto cleanup_on_error;
174         if (mng_putchunk_text(mng, sizeof(MNG_TEXT_SOFTWARE), MNG_TEXT_SOFTWARE, sizeof("SYNFIG"), "SYNFIG" ) != 0 ) goto cleanup_on_error;
175         /* FIXME: not sure if this is correct */
176         if (mng_putchunk_gama(mng, MNG_FALSE, (int)(1.0/gamma().get_gamma()*100000)) != 0 ) goto cleanup_on_error;
177         if (mng_putchunk_phyg(mng, MNG_FALSE,round_to_int(desc.get_x_res()),round_to_int(desc.get_y_res()),MNG_UNIT_METER) != 0 ) goto cleanup_on_error;
178         if (mng_putchunk_time(mng, gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday, gmt->tm_hour, gmt->tm_min, gmt->tm_sec) != 0 ) goto cleanup_on_error;
179         buffer=new unsigned char[4*w];
180         if (buffer == NULL ) goto cleanup_on_error;
181         color_buffer=new Color[w];
182         if (color_buffer == NULL ) goto cleanup_on_error;
183         return true;
184         
185 cleanup_on_error:
186         ready=false;
187         if (mng != MNG_NULL)
188         {
189                 mng_int8 severity;
190                 mng_chunkid chunkname;
191                 mng_uint32 chunkseq;
192                 mng_int32 extra1;
193                 mng_int32 extra2;
194                 mng_pchar errortext;
195                 mng_getlasterror (mng, &severity, &chunkname, &chunkseq, &extra1,&extra2, &errortext);
196                 synfig::error("mng_trgt: libmng: %s",errortext); 
197                 mng_cleanup (&mng);
198         }
199         if (file && file!=stdout ) fclose(file); file=NULL;
200         if (buffer != NULL ) { delete [] buffer; buffer = NULL; }
201         if (color_buffer != NULL ) { delete [] color_buffer; color_buffer = NULL; }
202         return false;   
203 }
204
205 void
206 mng_trgt::end_frame()
207 {
208         //synfig::error("mng_trgt: endf %d %d",w,h); 
209         //synfig::error("mng_trgt: error: endframe");
210         deflate(&zstream,Z_FINISH);
211         deflateEnd(&zstream);
212         if (mng != MNG_NULL )
213         {
214                 // mng_int8 severity;
215                 // mng_chunkid chunkname;
216                 // mng_uint32 chunkseq;
217                 // mng_int32 extra1;
218                 // mng_int32 extra2;
219                 // mng_pchar errortext;
220                 mng_putchunk_idat(mng, zbuffer_len, zbuffer);
221                 //mng_getlasterror (mng, &severity, &chunkname, &chunkseq, &extra1,&extra2, &errortext);
222                 //synfig::error("mng_trgt: libmng: %s %d",errortext,zbuffer_len); 
223                 mng_putchunk_iend(mng);
224                 //mng_getlasterror (mng, &severity, &chunkname, &chunkseq, &extra1,&extra2, &errortext);
225                 //synfig::error("mng_trgt: libmng: %s %d",errortext); 
226         }
227         imagecount++;
228         ready=false;
229 }
230
231 bool
232 mng_trgt::start_frame(synfig::ProgressCallback *callback)
233 {
234         //synfig::error("mng_trgt: startf %d %d",w,h); 
235         //synfig::error("mng_trgt: error: startframe");
236         /*
237         FIXME: figure out if we need this
238         mng_putchunk_fram(mng,
239                 MNG_FALSE,
240                 MNG_FRAMINGMODE_NOCHANGE,
241                 0,
242                 NULL,
243                 MNG_CHANGEDELAY_NO,
244                 MNG_CHANGETIMOUT_NO,
245                 MNG_CHANGECLIPPING_NO,
246                 MNG_CHANGESYNCID_NO,
247                 0,
248                 0,
249                 0,
250                 layer_offset_x,
251                 layer_offset_x + layer_cols,
252                 layer_offset_y,
253                 layer_offset_y + layer_rows,
254                 0,
255                 0)
256         mng_getchunk_fram(mng_handle       hHandle,
257                 mng_handle       hChunk,
258                 mng_bool         *bEmpty,
259                 mng_uint8        *iMode,
260                 mng_uint32       *iNamesize,
261                 mng_pchar        *zName,
262                 mng_uint8        *iChangedelay,
263                 mng_uint8        *iChangetimeout,
264                 mng_uint8        *iChangeclipping,
265                 mng_uint8        *iChangesyncid,
266                 mng_uint32       *iDelay,
267                 mng_uint32       *iTimeout,
268                 mng_uint8        *iBoundarytype,
269                 mng_int32        *iBoundaryl,
270                 mng_int32        *iBoundaryr,
271                 mng_int32        *iBoundaryt,
272                 mng_int32        *iBoundaryb,
273                 mng_uint32       *iCount,
274                 mng_uint32p      *pSyncids);
275         */
276         if (mng == MNG_NULL ) return false;
277         if (mng_putchunk_defi(mng,0,MNG_DONOTSHOW_VISIBLE,MNG_ABSTRACT,MNG_FALSE,0,0,MNG_FALSE,0,0,0,0) != 0) return false;
278         if (mng_putchunk_ihdr(mng,w,h,MNG_BITDEPTH_8,MNG_COLORTYPE_RGBA,MNG_COMPRESSION_DEFLATE, 0/*MNG_FILTER_NO_DIFFERING*/,MNG_INTERLACE_NONE) != 0) return false;
279         zstream.zalloc = Z_NULL;
280         zstream.zfree = Z_NULL;
281         zstream.opaque = Z_NULL;
282         zstream.data_type = Z_BINARY; 
283         if (deflateInit(&zstream, Z_DEFAULT_COMPRESSION) != Z_OK ) return false;
284         //zbuffer_len = deflateBound(&zstream,4*w*h);
285         if(zbuffer == NULL)
286         {
287                 zbuffer_len = 4*w*h;
288                 zbuffer = (unsigned char*)realloc(zbuffer, zbuffer_len);
289                 zstream.next_out = zbuffer;
290                 zstream.avail_out = zbuffer_len;
291         }
292         ready=true;
293         return true;
294 }
295
296 Color*
297 mng_trgt::start_scanline(int scanline)
298 {
299         //synfig::error("mng_trgt: starts %d %d",w,h); 
300         //synfig::error("mng_trgt: error: startscanline");
301         return color_buffer;
302 }
303
304 bool
305 mng_trgt::end_scanline()
306 {
307         //synfig::error("mng_trgt: ends %d %d",w,h); 
308         //synfig::error("mng_trgt: error: endscanline");
309         if(!file || !ready)
310                 return false;
311         convert_color_format(buffer, color_buffer, desc.get_w(), PF_RGB|PF_A, gamma());
312         /* FIXME: Implement buffer management */
313         zstream.next_in = buffer;
314         zstream.avail_in = 4*w;
315         deflate(&zstream,Z_NO_FLUSH);
316         return true;
317 }