Site hosted by Angelfire.com: Build your free website today!

/**************************************************************************** 
 *  BIOC -- Biomorph Generator - BMP and TIFF format (color)                *
 *  Coded by Carlos Suberviola Oroz.                                        *
 *                                                                          *
 *  Copyright (c) 2002 Carlos Suberviola Oroz -- http://biomorph.tk         *
 *                                                                          *
 *  This program is free software; you can redistribute it and/or modify    *
 *  it under the terms of the GNU General Public License as published by    *
 *  the Free Software Foundation as version 2 of the License.               *
 *                                                                          *
 *  This program is distributed in the hope that it will be useful,         *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of          *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
 *  GNU General Public License for more details.                            *
 *                                                                          *
 *  You should have received a copy of the GNU General Public License       *
 *  along with this program; if not, write to the Free Software             *
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
 *                                                                          *
 ****************************************************************************/

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <complex>

using namespace std;

const char _c_[] = "Made by BioC - (c) 2002 Carlos Suberviola Oroz - "
                   "<http://biomorph.tk>";

#define DIMOF(a) (sizeof(a)/sizeof((a)[0]))

#define min(a,b) ((a)<(b)?(a):(b))

typedef double complex_t__value_type;
typedef complex<complex_t__value_type> complex_t;
typedef complex_t (*pfcpx_t)(complex_t&);

complex_t N, M, _c;
pfcpx_t _f;

complex_t f0 (complex_t& z)
{
  return sin(z) + complex_t__value_type(exp(real(z)))
                * complex_t(cos(real(z)), sin(imag(z)));
}
complex_t f1 (complex_t& z)
{
  return pow(z,N);
}
complex_t f2 (complex_t& z)
{
  return pow(z,N)+pow(z,M);
}
complex_t f3 (complex_t& z)
{
  return pow(z,z);
}
complex_t f4 (complex_t& z)
{
  return pow(z,z)+pow(z,N);
}
complex_t f5 (complex_t& z)
{
  return sin(z);
}
complex_t f6 (complex_t& z)
{
  return sin(z)+pow(z,N);
}
complex_t f7 (complex_t& z)
{
  return sin(z)+exp(z);
}
complex_t f8 (complex_t& z)
{
  return sin(z)+pow(N,z);
}
complex_t f9 (complex_t& z)
{
  return sin(z)+pow(z,z);
}
complex_t f10 (complex_t& z)
{
  return sin(z)/cos(z)+pow(z,N);
}
complex_t f11 (complex_t& z)
{
  return log(z)+pow(z,N);
}

const pfcpx_t Function[] =
{
  f0,f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11
};

const char* FunctExpr[] =
{
  "sin(z) + e^Re(z)*[cos(Re(z))+i*sin(Im(z))]",
  "z^N","z^N + z^M","z^z","z^z + z^N",
  "sin(z)","sin(z) + z^N","sin(z) + e^z","sin(z) + N^z","sin(z) + z^z",
  "tan(z) + z^N","log(z) + z^N"
};

enum FileFormat {
  FORMAT_NONE = 0,
  FORMAT_TIFF = 1,
  FORMAT_BMP  = 2,
};

struct params_t {
  unsigned Q;
  unsigned X, Y;
  complex_t z0;
  complex_t__value_type w;
  const char *name;
  FileFormat format;
  unsigned bpp;
  params_t();
};
params_t::params_t() :
  Q(1), X(256), Y(256), z0(0), w(3), name(0), format(FORMAT_NONE), bpp(8)
{
  _f = Function[Q];
  N = 3, M = 7;
  _c = 0.5;
}

#define MAX 10

class ostreambit {
  ostream& out;
  unsigned bb, k, w;
public:
  ostreambit(ostream& os) : out(os), bb(0), k(0), w(0) {}
  void put_bits(unsigned bits, unsigned n)
  {
    bb <<= n; bb |= bits; k+=n;
    if (k>=8) {
      unsigned c = k>>3; k &= 7;
      unsigned b = bb>>k;
      out.write((const char*)&b,c); w+=c;
    }
  }
  void flush()
  {
    if (k>0)
      out.put(bb), w++;
    bb=0; k=0;
  }
  void put(char c)
  {
    out.put(c); w++;
  }
  unsigned bytes()
  {
    return w;
  }
};

unsigned MapColor (complex_t &z, complex_t__value_type zz, unsigned bpp)
{
  unsigned B = (1<<bpp) - 1, C = B>>1;
  complex_t__value_type re = fabs(real(z)), im = fabs(imag(z));
  complex_t__value_type m = min(re,im);
  return (m<MAX) ? B-C*sqrt(m/MAX) : C*pow(2*MAX*MAX/zz,1/4.0);
}

void CalcBiomorph (ostream& os, params_t &o, int xalign, void (*signal)(void))
{
  ostreambit osbit(os); --xalign;
  complex_t__value_type hh = (o.Y*o.w)/o.X;
  complex_t__value_type dx = o.w/o.X;
  complex_t__value_type dy = hh/o.Y;
  complex_t__value_type y = imag(o.z0) - hh/2;
  for(int j=0; j<o.Y; ++j, y+=dy) { if (signal) signal();
    complex_t__value_type x = real(o.z0) - o.w/2;
    for(int i=0; i<o.X; ++i, x+=dx) {
      complex_t z(x,y); complex_t__value_type zz;
      for (int M = 50; M; --M) {
        z = (*_f)(z) + _c;
        if ((zz = norm(z)) > MAX*MAX)
          break;
      }
      osbit.put_bits(MapColor(z,zz,o.bpp),o.bpp);
    }
    osbit.flush();
    while(osbit.bytes()&xalign) osbit.put(0);
  }
}

int ParseCommandLine (int argc, char *argv[], params_t &o)
{
  for (int i = 1; i < argc; ++i) {
    const char *p = argv[i];
    if (*p == '-') { ++p;
      char opt = *p++; int r = 0; float x,y; unsigned a,b; char c;
      stringstream s(p);
      switch (opt) {
      case 'R':
        if ((r = sscanf(p, "%u,%u%c", &a, &b, &c)) != 2)
          return 1;
        o.X = a, o.Y = b;
        break;
      case 'O':
        if ((r = sscanf(p, "%f,%f%c", &x, &y, &c)) != 2)
          return 1;
        o.z0 = complex_t(x,y);
        break;
      case 'W':
        if ((r = sscanf(p, "%f%c", &x, &c)) != 1)
          return 1;
        o.w = x;
        break;
      case 'F':
        if ((r = sscanf(p, "%u%c", &a, &c)) != 1)
          return 1;
        if (a >= DIMOF(Function))
          return 1;
        o.Q = a, _f = Function[a];
        break;
      case 'N':
        if ((r = sscanf(p, "%f,%f%c", &x, &y, &c)) != 2)
          return 1;
        N = complex_t(x,y);
        break;
      case 'M':
        if ((r = sscanf(p, "%f,%f%c", &x, &y, &c)) != 2)
          return 1;
        M = complex_t(x,y);
        break;
      case 'C':
        if ((r = sscanf(p, "%f,%f%c", &x, &y, &c)) != 2)
          return 1;
        _c = complex_t(x,y);
        break;
      case 'B':
        if ((r = sscanf(p, "%u%c", &a, &c)) != 1)
          return 1;
        o.bpp = a;
        break;
      default:
        return 1;
      }
      if (r == EOF)
        return 1;
    }
    else {
      if (o.name)
        return 1;
      else {
        const char *ext = strrchr(p,'.');
        o.name = p;
        if (!ext)
          return 1;
        else if (!stricmp(ext,".bmp"))
          o.format = FORMAT_BMP;
        else if (!stricmp(ext,".tif"))
          o.format = FORMAT_TIFF;
        else
          return 1;
      }
    }
  }
  return 0;
}

void PrinUsage (const char *command)
{
  cout << endl;
  cout << "Biomorph 1.00 - <http://oroz.tk>" << endl;
  cout << endl;
  cout << command << " [options] outfile.{bmp|tif}" << endl;
  cout << endl;
  cout << "Options:" << endl << endl;
  cout << "  -Rh,v Resolution(Horiz,Vert) = 256,256" << endl;
  cout << "  -Or,i Origin(Real,Imag) = (0,0)" << endl;
  cout << "  -Ww   Wide[Real] = 3" << endl;
  cout << "  -Fn   Function[0.." << DIMOF(Function)-1 << ']' << " = 1" << endl;
  for (int i=0; i<DIMOF(Function); i++)
  cout << "          " << i << ": " << FunctExpr[i] << endl;
  cout << "  -Nr,i Param. N(Real,Imag) = (3,0)" << endl;
  cout << "  -Mr,i Param. M(Real,Imag) = (7,0)" << endl;
  cout << "  -Cr,i Const. C(Real,Imag) = (0.5,0)" << endl;
  cout << "  -Bn   bits per pixel(Int) = 8" << endl;
  cout << endl;
  cout << "Examples:" << endl;
  cout << "  bioc bio.tif" << endl;
  cout << "  bioc -R1024,768 -F2 -N5,0 -M7,0 -C0.8,0 bio.tif" << endl;
  cout << endl;
}

void PrintParams (params_t &o)
{
  cout << "Resol.:   " << o.X << 'x' << o.Y << endl;
  cout << "Origin:   " << o.z0 << endl;
  cout << "Wide:     " << o.w << endl;
  cout << "Funcion:  " << FunctExpr[o.Q] << endl;
  cout << "Param. N: " << N << endl;
  cout << "Param. M: " << M << endl;
  cout << "Const. C: " << _c << endl;
}

void WriteInfo (stringstream &ss, params_t &o)
{
  ss << endl;
  ss << "Orig: " << o.z0 << endl;
  ss << "Wide: " << o.w << endl;
  ss << "Func: " << FunctExpr[o.Q] << ';';
  ss << " N=" << N << ';';
  ss << " M=" << M << ';';
  ss << " C=" << _c;
  ss << endl << endl << '\0';
}

void BuildIFDirTIFF (ostream& os,
                     unsigned w, unsigned h, unsigned bpp,
                     const string& comment);
void BuildHeaderBMP (ostream& os,
                     unsigned horiz, unsigned vert, unsigned bpp,
                     const string& comment);
void alive () { cout << '.' << flush; }

int main (int argc, char *argv[])
{
  params_t params = params_t();
  stringstream ss;
  if (argc < 2 || ParseCommandLine(argc, argv, params)) {
    PrinUsage(argv[0]);
    return 0;
  }

  ofstream os(params.name, ios::out|ios::binary);
  if(!os) cout << "Can't open file: " << params.name << endl, exit(1);
  PrintParams(params);
  WriteInfo(ss, params);
  int align;
  if (params.format==FORMAT_BMP) {
    BuildHeaderBMP(os,params.X,params.Y,params.bpp,ss.str());
    align = 4;
  }
  else if (params.format==FORMAT_TIFF) {
    BuildIFDirTIFF(os,params.X,params.Y,params.bpp,ss.str());
    align = 1;
  }
  CalcBiomorph(os,params,align,alive);
  cout << endl;
  return 0;
}



template<class T>
ostream& operator<< (ostream& os, const T& t)
{ os.write((const char*)&t, sizeof(T)); return os;}

typedef unsigned char  BYTE;
typedef unsigned short WORD;
typedef unsigned long  DWORD;

#pragma pack(push,1)

struct BITMAPFILEHEADER {
  WORD   bfType;
  DWORD  bfSize;
  DWORD  bfReserved;
  DWORD  bfOffBits;
  BITMAPFILEHEADER(unsigned sz, unsigned off)
    : bfType('B'+'M'*256), bfSize(sz), bfReserved(0), bfOffBits(off) {}
};

struct BITMAPINFOHEADER {
  DWORD  biSize;
  DWORD  biWidth;
  DWORD  biHeight;
  WORD   biPlanes;
  WORD   biBitCount;
  DWORD  biCompression;
  DWORD  biSizeImage;
  DWORD  biXPelsPerMeter;
  DWORD  biYPelsPerMeter;
  DWORD  biClrUsed;
  DWORD  biClrImportant;
  BITMAPINFOHEADER(unsigned w, unsigned h, unsigned p, unsigned b)
    : biSize(sizeof(BITMAPINFOHEADER)),
      biWidth(w),biHeight(h),
      biPlanes(p),biBitCount(b) {}
};

struct BITMAPCOREHEADER {
  DWORD  bcSize;
  WORD   bcWidth;
  WORD   bcHeight;
  WORD   bcPlanes;
  WORD   bcBitCount;
  BITMAPCOREHEADER(unsigned w, unsigned h, unsigned p, unsigned b)
    : bcSize(sizeof(BITMAPCOREHEADER)),
      bcWidth(w),bcHeight(h),
      bcPlanes(p),bcBitCount(b) {}
};

struct RGBTRIPLE {
  BYTE   rgbtBlue;
  BYTE   rgbtGreen;
  BYTE   rgbtRed;
  RGBTRIPLE(BYTE r, BYTE g, BYTE b)
    : rgbtBlue(b), rgbtGreen(g), rgbtRed(r) {}
};

struct RGBQUAD {
  BYTE   rgbBlue;
  BYTE   rgbGreen;
  BYTE   rgbRed;
  BYTE   rgbReserved;
  RGBQUAD(BYTE r, BYTE g, BYTE b, BYTE z=0)
    : rgbBlue(b), rgbGreen(g), rgbRed(r), rgbReserved(z) {}
};

#pragma pack(pop)


void BuildHeaderBMP (ostream& os,
                     unsigned w, unsigned h, unsigned bpp,
                     const string& comment)
{
  const char *cptr = comment.c_str();
  size_t clen = comment.size();
  unsigned colors = 1 << bpp, amp = 1 << (8-bpp);
  unsigned hdrsz = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPCOREHEADER)
                   + colors*sizeof(RGBTRIPLE);
  unsigned begin = hdrsz + clen + sizeof(_c_);
  unsigned llen = (w*bpp)/8; llen = (llen+3)&~3;
  os << BITMAPFILEHEADER(begin+llen*h, begin);
  os << BITMAPCOREHEADER(w, h, 1, bpp);
  unsigned i;
/*for(i=1; i<colors; i++)
    os << RGBTRIPLE(0,0,i);
  os << RGBTRIPLE(255,0,0);*/
  for(i=1; i<colors; i+=2)
    os << RGBTRIPLE(0,0,amp*i);
  for(i=1; i<colors; i+=2)
    os << RGBTRIPLE(amp*i,0,0);
/*for(i=1; i<colors; i+=2)
    os << RGBTRIPLE(0,0,i);
  for(i=0; i<colors; i+=4)
    os << RGBTRIPLE(255-i,0,0);
  for(i=3; i<colors; i+=4)
    os << RGBTRIPLE(i,0,0);*/
  os.write(_c_,sizeof(_c_));
  os.write(cptr,clen);
}


#pragma pack(push,1)

typedef unsigned char  uint8;
typedef unsigned short uint16;
typedef unsigned long  uint32;

enum {
  TIFF_NOTYPE    = 0,  // placeholder
  TIFF_BYTE      = 1,  // 8-bit unsigned integer
  TIFF_ASCII     = 2,  // 8-bit bytes w/ last byte null
  TIFF_SHORT     = 3,  // 16-bit unsigned integer
  TIFF_LONG      = 4,  // 32-bit unsigned integer
  TIFF_RATIONAL  = 5,  // 64-bit unsigned fraction
  TIFF_SBYTE     = 6,  // !8-bit signed integer
  TIFF_UNDEFINED = 7,  // !8-bit untyped data
  TIFF_SSHORT    = 8,  // !16-bit signed integer
  TIFF_SLONG     = 9,  // !32-bit signed integer
  TIFF_SRATIONAL = 10, // !64-bit signed fraction
  TIFF_FLOAT     = 11, // !32-bit IEEE floating point
  TIFF_DOUBLE    = 12  // !64-bit IEEE floating point
} TIFFDataType;

#define _II_ ('I'+'I'*256)
#define _MM_ ('M'+'M'*256)

struct TIFFHeader {
  uint16 Endian;
  uint16 Magic;
  uint32 IFDofs;
  TIFFHeader(uint32 ofs) : IFDofs(ofs), Magic(42) {
    Endian = (*(uint8*)&Magic==42) ? _II_ : _MM_;
  }
};

struct IFDEntry {
  uint16 Tag;
  uint16 Type;
  uint32 Count;
  uint32 Value;
  IFDEntry(uint16 tag, uint16 t, uint32 c, uint32 v)
    : Tag(tag), Type(t), Count(c), Value(v) {}
};

struct RATIONAL {
  uint32 num, dem;
  RATIONAL(uint32 n, uint32 d) : num(n), dem(d) {}
};


#pragma pack(pop)


void BuildIFDirTIFF (ostream& os,
                     unsigned w, unsigned h, unsigned bpp,
                     const string& comment)
{
  const char *cptr = comment.c_str();
  size_t clen = comment.size();
  unsigned colors = 1 << bpp, amp = 1 << (16-bpp);
  uint32 ofsArtist = 8;
  uint32 ofsDescr  = 8 + sizeof(_c_); ofsDescr = (ofsDescr+1)&~1;
  uint32 ofs = ofsDescr + clen; ofs = (ofs+1)&~1;
  os << TIFFHeader(ofs);
  os.write(_c_,sizeof(_c_)); if(sizeof(_c_)&1) os.put(0);
  os.write(cptr,clen); if(clen&1) os.put(0);
  uint16 n = 18; ofs += 2+n*12+4;
  os.write((const char*)&n,2);
  os << IFDEntry(254, TIFF_LONG,  1, 0);      // NewSubFileType
  os << IFDEntry(256, TIFF_SHORT, 1, w);      // ImageWidth
  os << IFDEntry(257, TIFF_SHORT, 1, h);      // ImageLenght
  os << IFDEntry(258, TIFF_SHORT, 1, bpp);    // BitsPerSample
  os << IFDEntry(259, TIFF_SHORT, 1, 1);      // Compression (None)
  os << IFDEntry(262, TIFF_SHORT, 1, 3);      // PhotometricInterpretation (Palette)
  os << IFDEntry(270, TIFF_ASCII, clen, ofsDescr); // ImageDescription
  os << IFDEntry(273, TIFF_LONG,  1, ofs+8+2*3*colors); // StripOffsets
  os << IFDEntry(274, TIFF_SHORT, 1, 4);      // Orientation (bottom-left)
  os << IFDEntry(277, TIFF_SHORT, 1, 1);      // SamplesPerPixel
  os << IFDEntry(278, TIFF_LONG,  1, -1);     // RowsPerStrip
  os << IFDEntry(279, TIFF_LONG,  1, (((uint32)w*bpp+7)>>3)*h); // StripByteCounts
  os << IFDEntry(282, TIFF_RATIONAL, 1, ofs); // XResolution
  os << IFDEntry(283, TIFF_RATIONAL, 1, ofs); // YResolution
  os << IFDEntry(284, TIFF_SHORT, 1, 1);      // PlanarConfiguration
  os << IFDEntry(296, TIFF_SHORT, 1, 2);      // ResolutionUnit (Inch)
  os << IFDEntry(315, TIFF_ASCII, sizeof(_c_), ofsArtist); // Artist
  os << IFDEntry(320, TIFF_SHORT, 3*colors, ofs+8); // ColorMap
  ofs = 0;
  os.write((const char*)&ofs,4);
  os << RATIONAL(72*0x1000000,0x1000000);
  unsigned i; uint16 c; n = 0;
  for(i=1; i<colors; i+=2)
    os.write((const char*)&n,2);
  for(i=1; i<colors; i+=2)
    c=amp*i, os.write((const char*)&c,2);
  for(i=0; i<colors; i++)
    os.write((const char*)&n,2);
  for(i=1; i<colors; i+=2)
    c=amp*i, os.write((const char*)&c,2);
  for(i=1; i<colors; i+=2)
    os.write((const char*)&n,2);
}