Corrections to SVN properties.
[AROS.git] / workbench / classes / datatypes / gemimage / gemimage.c
blob7306b0c1edee69e87a899f887743b90e7e45a411
1 /*
3 Author: Neil Cafferkey
4 Copyright (C) 2002-2011 Neil Cafferkey
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston,
19 MA 02111-1307, USA.
24 #include <exec/memory.h>
25 #include <utility/hooks.h>
26 #include <datatypes/pictureclass.h>
27 #include <intuition/classusr.h>
29 #include <proto/exec.h>
30 #include <proto/dos.h>
31 #include <proto/intuition.h>
32 #include <proto/utility.h>
33 #include <proto/graphics.h>
34 #include <proto/datatypes.h>
35 #include <proto/alib.h>
37 #include "datatype.h"
39 #include "gemimage_protos.h"
42 #define MIN_HEADER_SIZE 16
43 #define VDI_ENTRY_SIZE 6
44 #define XBIOS_ENTRY_SIZE 2
45 #define XIMG_ID ('X' << 24 | 'I' << 16 | 'M' << 8 | 'G')
46 #define STTT_ID ('S' << 24 | 'T' << 16 | 'T' << 8 | 'T')
48 enum
50 NO_PALETTE,
51 BUILTIN_PALETTE,
52 GREYSCALE_PALETTE,
53 XBIOS_PALETTE,
54 VDI_PALETTE
58 #define SCALEVDI(A) ((A) * ((1 << 29) / 125))
59 #define SCALEXBIOS(A) ((A) * 0x24924924)
62 static UPINT DispatchOp(struct IClass *class REG("a0"),
63 Object *object REG("a2"), Msg op REG("a1"));
64 static UPINT OMNew(struct IClass *class, Object *object, struct opSet *op,
65 struct GemImgBase *base);
68 static const struct ColorRegister bilevel_palette[] =
70 {0xff, 0xff, 0xff},
71 {0x00, 0x00, 0x00}
75 static const struct ColorRegister pc_palette[]=
77 {0xff, 0xff, 0xff},
78 {0xff, 0x00, 0x00},
79 {0x00, 0xff, 0x00},
80 {0xff, 0xff, 0x00},
81 {0x00, 0x00, 0xff},
82 {0xff, 0x00, 0xff},
83 {0x00, 0xff, 0xff},
84 {0xaa, 0xaa, 0xaa},
85 {0x55, 0x55, 0x55},
86 {0xaa, 0x00, 0x00},
87 {0x00, 0xaa, 0x00},
88 {0xaa, 0xaa, 0x00},
89 {0x00, 0x00, 0xaa},
90 {0xaa, 0x00, 0xaa},
91 {0x00, 0xaa, 0xaa},
92 {0x00, 0x00, 0x00}
97 /****i* gemimage.datatype/MakeGemImgClass **********************************
99 * NAME
100 * MakeGemImgClass
102 * SYNOPSIS
103 * class = MakeGemImgClass()
105 * struct IClass *MakeGemImgClass(VOID);
107 ****************************************************************************
111 struct IClass *MakeGemImgClass(struct GemImgBase *base)
113 BOOL success = TRUE;
114 struct IClass *class;
116 class =
117 MakeClass(base->library.lib_Node.ln_Name, PICTUREDTCLASS, NULL, 0, 0);
118 if(class == NULL)
119 success = FALSE;
121 if(success)
123 class->cl_Dispatcher.h_Entry = (HOOKFUNC)DispatchOp;
124 class->cl_UserData = (IPTR)base;
125 AddClass(class);
128 return class;
133 /****i* gemimage.datatype/DispatchOp ***************************************
135 * NAME
136 * DispatchOp
138 * SYNOPSIS
139 * result = DispatchOp(class, object, op)
141 * UPINT DispatchOp(struct IClass, Object, Msg);
143 ****************************************************************************
147 static UPINT DispatchOp(struct IClass *class REG("a0"),
148 Object *object REG("a2"), Msg op REG("a1"))
150 struct GemImgBase *base;
151 UPINT result;
153 base = (APTR)class->cl_UserData;
154 switch(op->MethodID)
156 case OM_NEW:
157 result = OMNew(class, object, (APTR)op, base);
158 break;
160 default:
161 result = DoSuperMethodA(class, object, op);
164 return result;
169 /****i* gemimage.datatype/OMNew ********************************************
171 * NAME
172 * OMNew
174 * SYNOPSIS
175 * result = OMNew(class, object, op)
177 * UPINT OMNew(struct IClass, Object, struct opSet);
179 ****************************************************************************
183 static UPINT OMNew(struct IClass *class, Object *object, struct opSet *op,
184 struct GemImgBase *base)
186 LONG error = 0;
187 struct TagItem *tags;
188 UWORD header_size, extension_size, pattern_size, pixel_width,
189 pixel_height, in_line_size, out_line_size, repeat_count = 0,
190 colour_count, i, j, k, entry, version;
191 UBYTE datum, *buffer = NULL, *buffer_end, *in, *out, *in_stop, *out_stop,
192 *end_of_line, fill, *pattern, palette_type;
193 BPTR file;
194 struct FileInfoBlock *info = NULL;
195 struct BitMap *bitmap = NULL;
196 struct BitMapHeader *bitmap_header;
197 struct ColorRegister *colour_registers;
198 const struct ColorRegister *palette;
199 BOOL repeat = FALSE, il = TRUE, reverse_planes = FALSE;
200 ULONG screen_mode, *c_regs, *c_reg, level;
202 /* Get a new picture object */
204 object = (Object *)DoSuperMethodA(class, object, (Msg)op);
205 if(object == NULL)
206 error = IoErr();
208 /* Examine file */
210 tags = op->ops_AttrList;
211 if(GetTagData(DTA_SourceType, DTST_FILE, tags) != DTST_FILE)
212 error = ERROR_OBJECT_WRONG_TYPE;
214 if(error == 0)
216 GetDTAttrs(object, DTA_Handle, (UPINT)&file,
217 PDTA_BitMapHeader, (UPINT)&bitmap_header, TAG_END);
218 if(Seek(file, 0, OFFSET_BEGINNING) == -1)
219 error = IoErr();
220 info = AllocDosObject(DOS_FIB, NULL);
221 if(info == NULL)
222 error = IoErr();
225 if(error == 0)
227 if(!ExamineFH(file, info))
228 error = IoErr();
231 if(error == 0)
233 if(info->fib_Size < MIN_HEADER_SIZE)
234 error = ERROR_OBJECT_WRONG_TYPE;
236 buffer = AllocVec(info->fib_Size, MEMF_ANY);
237 buffer_end = buffer + info->fib_Size;
238 if(buffer == NULL)
239 error = IoErr();
242 if(error == 0)
244 /* Read entire file */
246 if(Read(file, buffer, info->fib_Size) == -1)
247 error = IoErr();
250 if(error == 0)
252 /* Interpret header */
254 in = buffer;
255 version = BEWord(*(UWORD *)in);
256 in += 2;
257 header_size = BEWord(*(UWORD *)in) * sizeof(UWORD);
258 in += 2;
259 bitmap_header->bmh_Depth = BEWord(*(UWORD *)in);
260 in += 2;
261 pattern_size = BEWord(*(UWORD *)in);
262 in += 2;
263 pixel_width = BEWord(*(UWORD *)in);
264 in += 2;
265 pixel_height = BEWord(*(UWORD *)in);
266 in += 2;
267 bitmap_header->bmh_Width = BEWord(*(UWORD *)in);
268 in += 2;
269 bitmap_header->bmh_Height = BEWord(*(UWORD *)in);
270 in += 2;
272 if(info->fib_Size < header_size)
273 error = ERROR_OBJECT_WRONG_TYPE;
275 in_line_size = (bitmap_header->bmh_Width - 1) / 8 + 1;
276 colour_count = 1 << bitmap_header->bmh_Depth;
277 SetDTAttrs(object, NULL, NULL, PDTA_NumColors, colour_count, TAG_END);
278 GetDTAttrs(object, PDTA_ColorRegisters, (UPINT)&colour_registers,
279 PDTA_CRegs, (UPINT)&c_regs, TAG_END);
281 /* Allocate picture's bitmap */
283 bitmap = AllocBitMap(bitmap_header->bmh_Width,
284 bitmap_header->bmh_Height, bitmap_header->bmh_Depth, BMF_CLEAR,
285 NULL);
286 if(bitmap == NULL)
287 error = IoErr();
290 if(error == 0)
292 /* Determine subformat */
294 extension_size = header_size - MIN_HEADER_SIZE;
296 if(extension_size == colour_count * XBIOS_ENTRY_SIZE)
298 /* "No Sig" subformat */
300 palette_type = XBIOS_PALETTE;
301 il = FALSE;
303 else if(extension_size == 2 + colour_count * XBIOS_ENTRY_SIZE
304 && BEWord(*(UWORD *)in) == 0x0080)
306 /* HyperPaint subformat */
308 palette_type = XBIOS_PALETTE;
309 in += 2;
311 else if(extension_size == (1 + colour_count) * VDI_ENTRY_SIZE
312 && BELong(*(ULONG *)in) == XIMG_ID
313 && BEWord(*(UWORD *)(in + 4)) == 0x0000
314 && (version == 2 || version == 1))
316 /* XIMG subformat */
318 palette_type = VDI_PALETTE;
319 in += VDI_ENTRY_SIZE;
321 else if(extension_size == 2 + colour_count * XBIOS_ENTRY_SIZE
322 && BELong(*(ULONG *)in) == STTT_ID
323 && BEWord(*(UWORD *)(in + 4)) == 0x0010)
325 /* ST/TT subformat */
327 il = FALSE;
328 palette_type = XBIOS_PALETTE;
329 in += 6;
331 else if(extension_size == 0)
333 /* Original format or a paletteless subformat */
335 switch(bitmap_header->bmh_Depth)
337 case 1:
338 palette = bilevel_palette;
339 palette_type = BUILTIN_PALETTE;
340 break;
341 case 4:
342 palette = pc_palette;
343 palette_type = BUILTIN_PALETTE;
344 break;
345 case 8:
346 palette_type = GREYSCALE_PALETTE;
347 reverse_planes = TRUE;
348 break;
349 case 16:
350 case 24:
351 il = FALSE;
352 palette_type = NO_PALETTE;
353 default:
354 error = ERROR_OBJECT_WRONG_TYPE;
357 else
358 error = ERROR_OBJECT_WRONG_TYPE;
361 if(error == 0)
363 /* Fill in bitmap's palette */
365 c_reg = c_regs;
366 switch(palette_type)
368 case VDI_PALETTE:
369 for(i = 0; i < colour_count * 3; i++)
371 *(c_reg++) = SCALEVDI(BEWord(*(UWORD *)in));
372 in += 2;
374 break;
375 case XBIOS_PALETTE:
376 for(i = 0; i < colour_count; i++)
378 c_reg += 3;
379 entry = BEWord(*(UWORD *)in);
380 for(j = 1; j <= 3; j++)
382 *(c_reg - j) = SCALEXBIOS(entry & 0x7);
383 entry = entry >> 4;
385 in += 2;
387 break;
388 case BUILTIN_PALETTE:
389 for(i = 0; i < colour_count; i++, palette++)
391 *(c_reg++) = palette->red << 24;
392 *(c_reg++) = palette->green <<24;
393 *(c_reg++) = palette->blue << 24;
395 break;
396 case GREYSCALE_PALETTE:
397 level = 0xff << 24;
398 for(i = 0; i < colour_count; i++)
400 for(j = 0; j < 3; j++)
401 *(c_reg++) = level;
402 level -= 1 << 24;
406 /* Make lower-precision copy of palette */
408 if(palette_type != NO_PALETTE)
410 for(i = 0; i < colour_count; i++, colour_registers++)
412 colour_registers->red = *(c_regs++) >> 24;
413 colour_registers->green = *(c_regs++) >> 24;
414 colour_registers->blue = *(c_regs++) >> 24;
418 /* Read image data into bitmap */
420 out_line_size = bitmap->BytesPerRow;
421 in = buffer + header_size;
423 for(il? (i = 0): (j = 0);
424 il? i < bitmap_header->bmh_Height: j < bitmap_header->bmh_Depth;
425 il? i++: j++)
427 if(!repeat)
429 if(in + 1 < buffer_end)
431 if(*((UWORD *)in) == 0)
433 if(in + 3 < buffer_end)
435 in += 3;
436 repeat_count = *(in++);
437 if(repeat_count != 0)
438 repeat_count--;
440 else
441 error = ERROR_OBJECT_WRONG_TYPE;
446 for(il? (j = 0): (i = 0);
447 il? j < bitmap_header->bmh_Depth: i < bitmap_header->bmh_Height;
448 il? j++: i++)
450 if(reverse_planes)
451 k = bitmap_header->bmh_Depth - (j + 1);
452 else
453 k = j;
454 out = bitmap->Planes[k] + out_line_size * i;
455 end_of_line = out + in_line_size;
457 if(repeat)
458 CopyMem(out - out_line_size, out, out_line_size);
459 else
461 while(error == 0 && out < end_of_line)
463 if(in == buffer_end)
464 error = ERROR_OBJECT_WRONG_TYPE;
466 if(error == 0)
468 datum = *in++;
469 if((datum & ~0x80) == 0)
471 if(in == buffer_end)
472 error = ERROR_OBJECT_WRONG_TYPE;
473 if(error == 0)
475 if(datum == 0x00)
477 datum = *in++;
478 in_stop = in + pattern_size;
479 out_stop = out + pattern_size * datum;
480 if(in_stop <= buffer_end
481 && out_stop <= end_of_line)
483 pattern = in; in++;
484 while(out < out_stop)
486 in = pattern;
487 while(in < in_stop)
488 *out++ = *in++;
491 else
492 error = ERROR_OBJECT_WRONG_TYPE;
494 else
496 datum = *in++;
497 in_stop = in + datum;
498 if(in_stop <= buffer_end
499 && out + datum <= end_of_line)
501 while(in < in_stop)
502 *out++ = *in++;
504 else
505 error = ERROR_OBJECT_WRONG_TYPE;
509 else
511 if((datum & 0x80) != 0)
512 fill = 0xff;
513 else
514 fill = 0x00;
515 datum &= ~0x80;
516 out_stop = out + datum;
517 if(out_stop <= end_of_line)
519 while(out < out_stop)
520 *out++ = fill;
522 else
523 error = ERROR_OBJECT_WRONG_TYPE;
530 if(repeat_count != 0)
532 repeat = TRUE;
533 repeat_count--;
535 else
536 repeat = FALSE;
539 /* Check there isn't any unused picture data */
541 if(in < buffer_end)
542 error = ERROR_OBJECT_WRONG_TYPE;
545 if(error == 0)
547 #ifndef AMIGAOS
548 screen_mode = BestModeID(
549 BIDTAG_DesiredWidth, bitmap_header->bmh_Width,
550 BIDTAG_DesiredHeight, bitmap_header->bmh_Height,
551 BIDTAG_NominalWidth, (pixel_width * bitmap_header->bmh_Width),
552 BIDTAG_NominalHeight, (pixel_height * bitmap_header->bmh_Height),
553 BIDTAG_Depth, bitmap_header->bmh_Depth,
554 TAG_END);
555 #else
556 screen_mode = BestModeID(
557 BIDTAG_NominalWidth, bitmap_header->bmh_Width,
558 BIDTAG_NominalHeight, bitmap_header->bmh_Height,
559 BIDTAG_Depth, bitmap_header->bmh_Depth,
560 TAG_END);
561 #endif
563 SetDTAttrs(object, NULL, NULL,
564 DTA_ObjName,
565 (UPINT)FilePart((APTR)GetTagData(DTA_Name, (UPINT)NULL, tags)),
566 DTA_NominalHoriz, bitmap_header->bmh_Width,
567 DTA_NominalVert, bitmap_header->bmh_Height,
568 PDTA_BitMap, (UPINT)bitmap,
569 PDTA_ModeID, screen_mode,
570 TAG_END);
573 /* Free Resources */
575 FreeVec(buffer);
576 FreeDosObject(DOS_FIB, info);
578 if(error != 0)
580 FreeBitMap(bitmap);
581 CoerceMethod(class, object, OM_DISPOSE);
582 object = NULL;
585 /* Return new object */
587 SetIoErr(error);
588 return (UPINT)object;