e576bb2002-10-11Martin Nilsson /* || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. */
1159952000-03-21Peter Bortas #include "global.h" #include "image_machine.h" #include <math.h> #include <ctype.h> #include "object.h" #include "interpret.h" #include "svalue.h" #include "mapping.h"
b2d3e42000-12-01Fredrik Hübinette (Hubbe) #include "pike_error.h"
1159952000-03-21Peter Bortas #include "operators.h" #include "builtin_functions.h" #include "module_support.h"
6a932b2014-08-18Martin Nilsson #include "pike_types.h"
1159952000-03-21Peter Bortas  #include "image.h"
82ff642000-07-03Henrik Grubbström (Grubba) #include "encodings.h"
6dc2772000-07-28Fredrik Hübinette (Hubbe) 
1159952000-03-21Peter Bortas extern struct program *image_program; /* **! module Image **! submodule TIM **! **! Handle decoding of TIM images.
29edef2014-07-31Per Hedbor **!
1159952000-03-21Peter Bortas **! TIM is the framebuffer format of the PSX game system.
8392722000-04-09Peter Bortas **! It is a simple, uncompressed, truecolor or CLUT format **! with a one bit alpha channel.
1159952000-03-21Peter Bortas */ /* **! method object decode(string data) **! method object decode_alpha(string data) **! method mapping decode_header(string data) **! method mapping _decode(string data) **! decodes a TIM image **! **! The <ref>decode_header</ref> and <ref>_decode</ref> **! has these elements: **! **! <pre> **! "image":object - image object \- not decode_header **! "alpha":object - decoded alpha /
13670c2015-05-25Martin Nilsson **!
1159952000-03-21Peter Bortas **! "type":"image/x-tim" - image type **! "xsize":int - horisontal size in pixels **! "ysize":int - vertical size in pixels **! "attr":int - texture attributes **! </pre> */ #define MODE_CLUT4 0 #define MODE_CLUT8 1 #define MODE_DC15 2 #define MODE_DC24 3 #define MODE_MIXED 4 #define FLAG_CLUT 8
8392722000-04-09Peter Bortas 
1159952000-03-21Peter Bortas static void tim_decode_rect(INT32 attr, unsigned char *src, rgb_group *dst,
93f4d02000-03-22Peter Bortas  unsigned char *clut, unsigned int h, unsigned int w)
1159952000-03-21Peter Bortas { INT32 cnt = h * w; switch(attr&7) { case MODE_DC15: while(cnt--) { unsigned int p = src[0]|(src[1]<<8); dst->b = ((p&0x7c00)>>7)|((p&0x7000)>>12); dst->g = ((p&0x03e0)>>2)|((p&0x0380)>>7); dst->r = ((p&0x001f)<<3)|((p&0x001c)>>2); src+=2; dst++; } break;
93f4d02000-03-22Peter Bortas  case MODE_CLUT4: cnt = cnt/2; while(cnt--) { int i, cluti = (src[0]&0xf)*2; unsigned int p; for(i=0; i<2; i++) { p = clut[cluti]|(clut[cluti+1]<<8); dst->b = ((p&0x7c00)>>7)|((p&0x7000)>>12); dst->g = ((p&0x03e0)>>2)|((p&0x0380)>>7); dst->r = ((p&0x001f)<<3)|((p&0x001c)>>2); dst++; cluti = (src[0]>>4)*2; } src++; } break; case MODE_CLUT8: while(cnt--) {
340c562001-06-13Henrik Grubbström (Grubba)  int cluti = (src[0])*2;
93f4d02000-03-22Peter Bortas  unsigned int p = clut[cluti]|(clut[cluti+1]<<8); dst->b = ((p&0x7c00)>>7)|((p&0x7000)>>12); dst->g = ((p&0x03e0)>>2)|((p&0x0380)>>7); dst->r = ((p&0x001f)<<3)|((p&0x001c)>>2); dst++; src++; } break;
1159952000-03-21Peter Bortas  } }
e006c02000-09-17Henrik Grubbström (Grubba) #define ALPHA(a) if(!a) /* Transparent */ \
8392722000-04-09Peter Bortas  dst->b = dst->g = dst->r = 0; \ else if(!(a&0x80)) /* Not transparent */ \
e006c02000-09-17Henrik Grubbström (Grubba)  dst->b = dst->g = dst->r = 0xff; \
8392722000-04-09Peter Bortas  else if(!(a&0x7f)) /* Non-transparent black */ \
e006c02000-09-17Henrik Grubbström (Grubba)  dst->b = dst->g = dst->r = 0xff; \
8392722000-04-09Peter Bortas  else /* Semi transparent */ \
e006c02000-09-17Henrik Grubbström (Grubba)  dst->b = dst->g = dst->r = 0x7f
8392722000-04-09Peter Bortas 
93f4d02000-03-22Peter Bortas static void tim_decode_alpha_rect(INT32 attr, unsigned char *src,
13670c2015-05-25Martin Nilsson  rgb_group *dst, unsigned char *clut,
1159952000-03-21Peter Bortas  unsigned int h, unsigned int w) {
8392722000-04-09Peter Bortas  /* Pixels rendereding on the PSX is made in one of two modes. One of them has semi transparency, but what mode to use is not indicated in the TIM as far as I know. Let's render everything in semi transparent mode with .5 from source and .5 from destination. */
1159952000-03-21Peter Bortas  INT32 cnt = h * w; switch(attr&7) { case MODE_DC15: while(cnt--) {
8392722000-04-09Peter Bortas  ALPHA(src[1]);
1159952000-03-21Peter Bortas  src+=2; dst++; } break;
93f4d02000-03-22Peter Bortas  case MODE_CLUT4: cnt = cnt/2; while(cnt--) {
8392722000-04-09Peter Bortas  ALPHA( clut[(src[0]&0xf)*2] );
93f4d02000-03-22Peter Bortas  dst++;
8392722000-04-09Peter Bortas  ALPHA( clut[(src[0]>>4)*2] );
93f4d02000-03-22Peter Bortas  src++; dst++; } break; case MODE_CLUT8: while(cnt--) {
8392722000-04-09Peter Bortas  ALPHA( clut[(src[0])*2] );
93f4d02000-03-22Peter Bortas  src++; dst++; } break;
1159952000-03-21Peter Bortas  } } void img_tim_decode(INT32 args, int header_only) {
93f4d02000-03-22Peter Bortas  struct pike_string *str; unsigned char *s, *clut; int n=0, hasalpha=0, bitpp=0, bsize=0;
3bd87a2000-08-03Henrik Grubbström (Grubba)  ptrdiff_t len; INT32 attr;
340c562001-06-13Henrik Grubbström (Grubba)  unsigned int h=0, w=0;
13670c2015-05-25Martin Nilsson 
391ac52018-08-05Martin Nilsson  get_all_args(NULL, args, "%S", &str);
93f4d02000-03-22Peter Bortas  clut=s=(unsigned char *)str->str; clut+=20;
3bd87a2000-08-03Henrik Grubbström (Grubba)  len = str->len;
93f4d02000-03-22Peter Bortas  pop_n_elems(args-1);
13670c2015-05-25Martin Nilsson 
93f4d02000-03-22Peter Bortas  if(len < 12 || (s[0] != 0x10 || s[2] != 0 || s[3] != 0))
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("not a TIM texture\n");
93f4d02000-03-22Peter Bortas  else if(s[2] != 0)
13670c2015-05-25Martin Nilsson  Pike_error("unknown version of TIM texture\n");
93f4d02000-03-22Peter Bortas  s += 4; len -= 4;
13670c2015-05-25Martin Nilsson 
6a932b2014-08-18Martin Nilsson  ref_push_string(literal_type_string);
5e9fc02015-08-18Per Hedbor  push_static_text("image/x-tim");
93f4d02000-03-22Peter Bortas  n++;
13670c2015-05-25Martin Nilsson 
93f4d02000-03-22Peter Bortas  attr = s[0]|(s[1]<<8)|(s[2]<<16)|(s[3]<<24); if(attr&0xfffffff0)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("unknown flags in TIM texture\n");
13670c2015-05-25Martin Nilsson 
93f4d02000-03-22Peter Bortas  s += 4; len -= 4;
1159952000-03-21Peter Bortas 
5e9fc02015-08-18Per Hedbor  push_static_text("attr");
93f4d02000-03-22Peter Bortas  push_int(attr); n++;
13670c2015-05-25Martin Nilsson 
93f4d02000-03-22Peter Bortas  if(attr&FLAG_CLUT) {
13670c2015-05-25Martin Nilsson  bsize = s[0]|(s[1]<<8)|(s[2]<<16)|(s[3]<<24);
93f4d02000-03-22Peter Bortas #ifdef TIM_DEBUG printf("bsize: %d\n", bsize); #endif s += bsize; len -= bsize; } /* FIXME: Unknown what this comes from */ s += 4; len -= 4;
1159952000-03-21Peter Bortas 
93f4d02000-03-22Peter Bortas  switch(attr&7) { case MODE_DC15: #ifdef TIM_DEBUG printf("15bit\n"); printf("dx: %d, dy: %d\n", s[0]|(s[1]<<8), s[2]|(s[3]<<8)); #endif s += 4; len -= 4; w = s[0]|(s[1]<<8); h = s[2]|(s[3]<<8); s += 4; len -= 4; bitpp = 16; hasalpha = 1; break; case MODE_DC24: #ifdef TIM_DEBUG printf("24bit\n"); #endif
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("24bit TIMs not supported. Please send an example to peter@roxen.com\n");
93f4d02000-03-22Peter Bortas  case MODE_CLUT4:
1abbbc2000-03-25Fredrik Hübinette (Hubbe)  /* dx and dy word ignored */
93f4d02000-03-22Peter Bortas #ifdef TIM_DEBUG printf("CLUT4\n"); printf("dx: %d, dy: %d\n", s[0]|(s[1]<<8), s[2]|(s[3]<<8)); #endif s += 4; len -= 4; w = (s[0]|(s[1]<<8))*4; h = s[2]|(s[3]<<8); s += 4; len -= 4; bitpp = 4; hasalpha = 1;
13670c2015-05-25Martin Nilsson  break;
93f4d02000-03-22Peter Bortas  case MODE_CLUT8:
1abbbc2000-03-25Fredrik Hübinette (Hubbe)  /* dx and dy word ignored */
93f4d02000-03-22Peter Bortas #ifdef TIM_DEBUG printf("CLUT8\n"); printf("dx: %d, dy: %d\n", s[0]|(s[1]<<8), s[2]|(s[3]<<8)); #endif s += 4; len -= 4; w = (s[0]|(s[1]<<8))*2; h = s[2]|(s[3]<<8); s += 4; len -= 4; bitpp = 8; hasalpha = 1; break; case MODE_MIXED: #ifdef TIM_DEBUG printf("Mixed\n"); #endif
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("mixed TIMs not supported\n");
93f4d02000-03-22Peter Bortas  default:
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("unknown TIM format\n");
93f4d02000-03-22Peter Bortas  }
13670c2015-05-25Martin Nilsson 
5e9fc02015-08-18Per Hedbor  push_static_text("xsize");
93f4d02000-03-22Peter Bortas  push_int(w);
13670c2015-05-25Martin Nilsson  n++;
5e9fc02015-08-18Per Hedbor  push_static_text("ysize");
93f4d02000-03-22Peter Bortas  push_int(h);
13670c2015-05-25Martin Nilsson  n++;
93f4d02000-03-22Peter Bortas  #ifdef TIM_DEBUG printf("w: %d, h: %d\n", w, h);
13670c2015-05-25Martin Nilsson #endif
93f4d02000-03-22Peter Bortas  if(!header_only) { struct object *o; struct image *img;
13670c2015-05-25Martin Nilsson 
93f4d02000-03-22Peter Bortas  if(len < (INT32)(bitpp*(h*w)/8))
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("short pixel data\n");
13670c2015-05-25Martin Nilsson 
5e9fc02015-08-18Per Hedbor  push_static_text("image");
93f4d02000-03-22Peter Bortas  push_int(w); push_int(h); o=clone_object(image_program,2);
13b5ed2014-05-26Per Hedbor  img=get_storage(o,image_program);
93f4d02000-03-22Peter Bortas  push_object(o); n++;
13670c2015-05-25Martin Nilsson 
93f4d02000-03-22Peter Bortas  tim_decode_rect(attr, s, img->img, clut, h, w);
13670c2015-05-25Martin Nilsson 
93f4d02000-03-22Peter Bortas  if(hasalpha) {
5e9fc02015-08-18Per Hedbor  push_static_text("alpha");
93f4d02000-03-22Peter Bortas  push_int(w); push_int(h); o=clone_object(image_program,2);
13b5ed2014-05-26Per Hedbor  img=get_storage(o,image_program);
93f4d02000-03-22Peter Bortas  push_object(o); n++;
13670c2015-05-25Martin Nilsson 
93f4d02000-03-22Peter Bortas  tim_decode_alpha_rect(attr, s, img->img, clut, h, w); } }
13670c2015-05-25Martin Nilsson 
93f4d02000-03-22Peter Bortas  f_aggregate_mapping(2*n);
13670c2015-05-25Martin Nilsson 
93f4d02000-03-22Peter Bortas  stack_swap(); pop_stack();
1159952000-03-21Peter Bortas } static void image_tim_f_decode(INT32 args) { img_tim_decode(args,0);
90e0f72003-12-12Martin Nilsson  push_constant_text("image");
1159952000-03-21Peter Bortas  f_index(2); } static void image_tim_f_decode_alpha(INT32 args) { img_tim_decode(args,0);
90e0f72003-12-12Martin Nilsson  push_constant_text("alpha");
1159952000-03-21Peter Bortas  f_index(2); } void image_tim_f_decode_header(INT32 args) { img_tim_decode(args,1); } void image_tim_f__decode(INT32 args) { img_tim_decode(args,0); }
c9eefb2014-08-21Martin Nilsson void init_image_tim(void)
1159952000-03-21Peter Bortas { ADD_FUNCTION( "decode", image_tim_f_decode, tFunc(tStr,tObj), 0); ADD_FUNCTION( "decode_alpha", image_tim_f_decode_alpha, tFunc(tStr,tObj), 0); ADD_FUNCTION( "_decode", image_tim_f__decode, tFunc(tStr,tMapping), 0); ADD_FUNCTION( "decode_header", image_tim_f_decode_header, tFunc(tStr,tMapping), 0); }
c9eefb2014-08-21Martin Nilsson void exit_image_tim(void)
1159952000-03-21Peter Bortas { }