/*
  ArtToSpr Artworks/Draw to Sprite convertor
  Copyright (c) 1998 Tony Houghton

  This source is distributed under the GPL. Please see the file
  "COPYING" for details.
*/

#include <limits.h>
#include <stdlib.h>

#include "os.h"

#include "flex.h"

#include "artworks.h"
#include "awrender.h"
#include "msgtrans.h"

#define MIN2(a, b) ((a)<(b) ? (a) : (b))
#define MAX2(a, b) ((a)>(b) ? (a) : (b))
#define MIN4(a, b, c, d) (MIN2 (MIN2((a),(b)), MIN2((c),(d)) ) )
#define MAX4(a, b, c, d) (MAX2 (MAX2((a),(b)), MAX2((c),(d)) ) )

typedef struct
{
  flex_ptr resizable_block;
  flex_ptr fixed_block;
} artworks_handle;

static const int wysiwyg_quality[] = { 110, 100, 50, 0 };

static _kernel_oserror *artworks_callback(int new_size,
	awrender_callback_regs *regs, artworks_handle *handle)
{
  regs->resizable_size = flex_size(handle->resizable_block);
  if (new_size > regs->resizable_size)
  {
    if (!flex_extend(handle->resizable_block, new_size))
    {
      return msgs_nomem();
    }
    regs->resizable_size = new_size;
  }
  regs->resizable_block = *handle->resizable_block;
  if ((int) handle->fixed_block == -1)
  {
    regs->fixed_block = (void *) -1;
    regs->fixed_size = regs->resizable_size;
  }
  else
  {
    regs->fixed_block = *handle->fixed_block;
    regs->fixed_size = flex_size(handle->fixed_block);
  }
  return 0;
}

_kernel_oserror *artworks_render(picture *pic,
	const picture_matrix *trfm, const BBox *bbox)
{
  awrender_info_block info_block;
  awrender_vdu_block vdu_block;
  _kernel_oserror *e;
  artworks_handle handle;
  void *workspace;
  os_mode_var vartags[] = {4, 5, 9, -1};

  bbox=bbox;

  info_block.dither_x = info_block.dither_y = 0;
  info_block.clip_rect.xmin = info_block.clip_rect.ymin = INT_MIN;
  info_block.clip_rect.xmax = info_block.clip_rect.ymax = INT_MAX;

  xos_read_vdu_variables((os_vdu_var_list const *) vartags,
  	(int *) &vdu_block);
  wimp_read_palette(&vdu_block.palette);

  if (!flex_alloc(&workspace, awrender_DefaultWorkSpace))
    return msgs_nomem();
  handle.resizable_block = &workspace;
  handle.fixed_block = &pic->data;

  e = awrender_render(pic->data, &info_block, (awrender_matrix const *) trfm,
  	&vdu_block, workspace, (awrender_callback_handler) artworks_callback,
  	wysiwyg_quality[pic->opts->quality], awrender_OutputToVDU, &handle);

  flex_free(&workspace);

  return e;
}

_kernel_oserror *artworks_bbox(picture *pic, const picture_matrix *trfm,
	BBox *result)
{
  BBox bbox;
  _kernel_oserror *e;
  float a = (float) trfm->a / 65536.0f,
  	b = (float) trfm->b / 65536.0f,
  	c = (float) trfm->c / 65536.0f,
  	d = (float) trfm->d / 65536.0f;
  struct { int x, y;} x0y0, x1y0, x0y1, x1y1;

  if (e = awrender_doc_bounds(pic->data, &bbox), e)
    return e;
  x0y0.x = (int) ((float) bbox.xmin * a + (float) bbox.ymin * c) + trfm->e;
  x0y0.y = (int) ((float) bbox.xmin * b + (float) bbox.ymin * d) + trfm->f;
  x1y0.x = (int) ((float) bbox.xmax * a + (float) bbox.ymin * c) + trfm->e;
  x1y0.y = (int) ((float) bbox.xmax * b + (float) bbox.ymin * d) + trfm->f;
  x0y1.x = (int) ((float) bbox.xmin * a + (float) bbox.ymax * c) + trfm->e;
  x0y1.y = (int) ((float) bbox.xmin * b + (float) bbox.ymax * d) + trfm->f;
  x1y1.x = (int) ((float) bbox.xmax * a + (float) bbox.ymax * c) + trfm->e;
  x1y1.y = (int) ((float) bbox.xmax * b + (float) bbox.ymax * d) + trfm->f;
  result->xmin = MIN4(x0y0.x, x1y0.x, x0y1.x, x1y1.x);
  result->ymin = MIN4(x0y0.y, x1y0.y, x0y1.y, x1y1.y);
  result->xmax = MAX4(x0y0.x, x1y0.x, x0y1.x, x1y1.x);
  result->ymax = MAX4(x0y0.y, x1y0.y, x0y1.y, x1y1.y);

  return 0;
}

extern _kernel_oserror *artworks_prepare(picture *pic)
{
  artworks_handle handle;

  handle.resizable_block = &pic->data;
  handle.fixed_block = (void **) -1;
  return awrender_file_init(pic->data,
  	(awrender_callback_handler) artworks_callback,
  	flex_size(&pic->data), &handle);
}
