/* Copyright 1996 Acorn Computers Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/************************************************************************/
/* � Acorn Computers Ltd, 1992.                                         */
/*                                                                      */
/* This file forms part of an unsupported source release of RISC_OSLib. */
/*                                                                      */
/* It may be freely used to create executable images for saleable       */
/* products but cannot be sold in source form or as an object library   */
/* without the prior written consent of Acorn Computers Ltd.            */
/*                                                                      */
/* If this file is re-distributed (even if modified) it should retain   */
/* this copyright notice.                                               */
/*                                                                      */
/************************************************************************/

/*
 * Title  : c.sprite
 * Purpose: provide access to RISC OS sprite facilities
 * History: IDJ: 07-Feb-92: prepared for source release
 *
 */

#include <stddef.h>
#include "os.h"

#include "sprite.h"


/* Basic primitive used by sprite_xxx calls */

#define OS_SpriteOp 0x2E

#define ScreenSave            2
#define ScreenLoad            3

#define ReadAreaCB            8  /* *SInfo */
#define ClearSprites          9  /* *SNew */
#define LoadSpriteFile        10 /* *SLoad <filename> */
#define MergeSpriteFile       11 /* *SMerge <filename> */
#define SaveSpriteFile        12 /* *SSave <filename> */
#define ReturnName            13
#define GetSprite             14 /* *SGet <n> */
#define CreateSprite          15
#define GetSpriteUserCoords   16

#define SelectSprite          24 /* *SChoose <n> [<m>] */
#define DeleteSprite          25 /* *SDelete <n> */
#define RenameSprite          26 /* *SRename */
#define CopySprite            27
#define PutSprite             28
#define CreateMask            29
#define RemoveMask            30
#define InsertRow             31
#define DeleteRow             32
#define FlipAboutXAxis        33
#define PutSpriteUserCoords   34
#define AppendSprite          35
#define SetPointerShape       36

#define ReadSpriteSize        40
#define ReadPixelColour       41
#define WritePixelColour      42
#define ReadPixelMask         43
#define WritePixelMask        44
#define InsertCol             45
#define DeleteCol             46
#define FlipAboutYAxis        47
#define PlotMask              48
#define PlotMaskUserCoords    49

#define PlotMaskScaled        50
#define PaintCharScaled       51
#define PutSpriteScaled       52
#define PutSpriteGreyScaled   53
#define RemoveLeftHandWastage 54
#define PlotMaskTransformed   55
#define PutSpriteTransformed  56
#define InsertDeleteRows      57
#define InsertDeleteColumns   58

#define SwitchOutputToSprite  60
#define SwitchOutputToMask    61
#define ReadSaveAreaSize      62

#define BadReasonCode         63

#pragma -s1

static os_error * sprite__op(os_regset *r)
{
  return os_swix(OS_SpriteOp, r);
}


/******** Simple operations, use no sprite area, no name/sprite pointer ***/

#ifndef UROM
os_error * sprite_screensave(const char *filename, sprite_palflag palflag)
{
  os_regset r;
  os_error *result;
  r.r[0] = 2;
/*r.r[1] unused */
  r.r[2] = (int) filename;
  r.r[3] = palflag;
  result = sprite__op(&r);
  return result;
}
#endif

#ifndef UROM
os_error * sprite_screenload(const char *filename)
{
  os_regset r;
  os_error *result;
  r.r[0] = 3;
/*r.r[1] unused */
  r.r[2] = (int) filename;
  result = sprite__op(&r);
  return result;
}
#endif

/****** Operations on either system/user area, no name/sprite pointer *****/

static void setfromarea(int op, sprite_area *area, os_regset *r)
{
  if (area == sprite_mainarea)
  {
    r->r[0] = op;
/*  r->r[1] unused */
  }
  else
  {
    r->r[0] = op + 256;
    r->r[1] = (int) area;
  }
}


void sprite_area_initialise(sprite_area *area, int length)
{
  area->size    = length; /* No SpriteOp to do this ! */
  area->number  = 0;
  area->sproff  = 16;
  area->freeoff = 16;
}


os_error * sprite_area_readinfo(sprite_area *area, sprite_area *resultarea)
{
  os_regset r;
  os_error *result;
  setfromarea(8, area, &r);
  result = sprite__op(&r);
  if (result == NULL) /* Only return result if no error */
  {
    resultarea->size    = r.r[2];
    resultarea->number  = r.r[3];
    resultarea->sproff  = r.r[4];
    resultarea->freeoff = r.r[5];
  }
  return result;
}


#ifndef UROM
os_error * sprite_area_reinit(sprite_area *area)
{
  os_regset r;
  os_error *result;
  setfromarea(9, area, &r);
  result = sprite__op(&r);
  return result;
}
#endif

os_error * sprite_area_save(sprite_area *area, const char *filename)
{
  os_regset r;
  os_error *result;
  os_filestr file;
  int oldattribs = -1;

  file.action = 17; /* Read cat info */
  file.name = (char *) filename;
  (void) os_file(&file);
  /* if something is already there,remember its attributes */
  if (file.action != 0) oldattribs = file.end;

  setfromarea(12, area, &r);
  r.r[2] = (int) filename;
  result = sprite__op(&r); /* Save */

  if (oldattribs != -1) {
    file.action = 4; /* Write attribs */
    file.end = oldattribs;
    (void) os_file(&file);
  };

  return result;
}


os_error * sprite_area_load(sprite_area *area, const char *filename)
{
  os_regset r;
  os_error *result;
  setfromarea(10, area, &r);
  r.r[2] = (int) filename;
  result = sprite__op(&r);
  return result;
}

#ifndef UROM
os_error * sprite_area_merge(sprite_area *area, const char *filename)
{
  os_regset r;
  os_error *result;
  setfromarea(11, area, &r);
  r.r[2] = (int) filename;
  result = sprite__op(&r);
  return result;
}
#endif

os_error * sprite_getname(sprite_area *area, void *buffer,
                          int *length, int index)
{
  os_regset r;
  os_error *result;
  setfromarea(13, area, &r);
  r.r[2] = (int) buffer;
  r.r[3] = *length;
  r.r[4] = index;
  result = sprite__op(&r);
  if (result == NULL) /* Only return result if no error */
  {
    *length = r.r[3];
  }
  return result;
}

#ifndef UROM
os_error * sprite_get(sprite_area *area, char *name, sprite_palflag palflag)
{
  os_regset r;
  os_error *result;
  setfromarea(14, area, &r);
  r.r[2] = (int) name;
  r.r[3] = palflag;
  result = sprite__op(&r);
  return result;
}
#endif

#ifndef UROM
os_error * sprite_get_rp(sprite_area *area, char *name, sprite_palflag palflag,
                         sprite_ptr *resultaddress)
{
  os_regset r;
  os_error *result;
  setfromarea(14, area, &r);
  r.r[2] = (int) name;
  r.r[3] = palflag;
  result = sprite__op(&r);
  if (result == NULL) /* Only return result if no error */
  {
    *resultaddress = (void *) r.r[2];
  }
  return result;
}
#endif

os_error * sprite_get_given(sprite_area *area, char *name,
                            sprite_palflag palflag,
                            int x0, int y0, int x1, int y1)
{
  os_regset r;
  os_error *result;
  setfromarea(16, area, &r);
  r.r[2] = (int) name;
  r.r[3] = palflag;
  r.r[4] = x0;
  r.r[5] = y0;
  r.r[6] = x1;
  r.r[7] = y1;
  result = sprite__op(&r);
  return result;
}

os_error * sprite_get_given_rp(sprite_area *area, char *name,
                               sprite_palflag palflag, int x0, int y0,
                               int x1, int y1, sprite_ptr *resultaddress)
{
  os_regset r;
  os_error *result;
  setfromarea(16, area, &r);
  r.r[2] = (int) name;
  r.r[3] = palflag;
  r.r[4] = x0;
  r.r[5] = y0;
  r.r[6] = x1;
  r.r[7] = y1;
  result = sprite__op(&r);
  if (result == NULL) /* Only return result if no error */
  {
    *resultaddress = (void *) r.r[2];
  }
  return result;
}

os_error * sprite_create(sprite_area *area, char *name, sprite_palflag palflag,
                         int width, int height, int mode)
{
  os_regset r;
  os_error *result;
  setfromarea(15, area, &r); /* NB. Not all done in numeric order !! */
  r.r[2] = (int) name;
  r.r[3] = palflag;
  r.r[4] = width;
  r.r[5] = height;
  r.r[6] = mode;
  result = sprite__op(&r);
  return result;
}

os_error * sprite_create_rp(sprite_area *area, char *name,
                            sprite_palflag palflag,
                            int width, int height, int mode,
                            sprite_ptr *resultaddress)
{
  os_regset r;
  os_error *result;
  setfromarea(15, area, &r); /* NB. Not all done in numeric order !! */
  r.r[2] = (int) name;
  r.r[3] = palflag;
  r.r[4] = width;
  r.r[5] = height;
  r.r[6] = mode;
  result = sprite__op(&r);
  if (result == NULL) /* Only return result if no error */
  {
    /* spriteop 15 doesn't return pointer to sprite in r2, so....*/
    /* select the sprite just created (gets its address in r2) */
    setfromarea(24, area, &r);
    r.r[2] = (int)name;
    result = sprite__op(&r);
    if (result == NULL)
       *resultaddress = (void *) r.r[2];
  }
  return result;
}

/*********** Operations on system/user area, name/sprite pointer **********/

/* Modify op if using sprite address is address, not name */
/* But only if using own sprite area */
static void setfromtag(int op, sprite_area *area, sprite_id *spr, os_regset *r)
{
  if (area == sprite_mainarea)
  {
    r->r[0] = op;
 /* r->r[1] unused */
  }
  else
  {
    r->r[1] = (int) area;
    if ((spr->tag) == sprite_id_addr)
    {
      r->r[0] = 512 + op;
      r->r[2] = (int) (spr->s.addr);
    }
    else
    {
      r->r[0] = 256 + op;
      r->r[2] = (int) (spr->s.name);
    }
  }
}

#ifndef UROM
os_error * sprite_readinfo(sprite_area *area, sprite_id *spr,
                           sprite_info *resultinfo)
{
  os_regset r;
  os_error *result;
  setfromtag(40, area, spr, &r);
  result = sprite__op(&r);
  if (result == NULL) /* Only return result if no error */
  {
    resultinfo->width  = r.r[3];
    resultinfo->height = r.r[4];
    resultinfo->mask   = r.r[5];
    resultinfo->mode   = r.r[6];
  }
  return result;
}
#endif

os_error * sprite_select(sprite_area *area, sprite_id *spr)
{
  os_regset r;
  os_error *result;
  setfromtag(24, area, spr, &r);
  result = sprite__op(&r);
  return result;
}


os_error * sprite_select_rp(sprite_area *area, sprite_id *spr,
                            sprite_ptr *resultaddress)
{
  os_regset r;
  os_error *result;
  setfromtag(24, area, spr, &r);
  result = sprite__op(&r);
  if (result == NULL) /* Only return result if no error */
  {
    *resultaddress = (void *) r.r[2];
  }
  return result;
}


os_error * sprite_delete(sprite_area *area, sprite_id *spr)
{
  os_regset r;
  os_error *result;
  setfromtag(25, area, spr, &r);
  result = sprite__op(&r);
  return result;
}


os_error * sprite_rename(sprite_area *area, sprite_id *spr, char *newname)
{
  os_regset r;
  os_error *result;
  setfromtag(26, area, spr, &r);
  r.r[3] = (int) newname;
  result = sprite__op(&r);
  return result;
}


os_error * sprite_copy(sprite_area *area, sprite_id *spr, char *copyname)
{
  os_regset r;
  os_error *result;
  setfromtag(27, area, spr, &r);
  r.r[3] = (int) copyname;
  result = sprite__op(&r);
  return result;
}

#ifndef UROM
os_error * sprite_put(sprite_area *area, sprite_id *spr, int gcol_action)
{
  os_regset r;
  os_error *result;
  setfromtag(28, area, spr, &r);
  r.r[5] = gcol_action;
  result = sprite__op(&r);
  return result;
}
#endif

os_error * sprite_put_given(sprite_area *area, sprite_id *spr, int gcol_action,
                            int x, int y)
{
  os_regset r;
  os_error *result;
  setfromtag(34, area, spr, &r);
  r.r[3] = x;
  r.r[4] = y;
  r.r[5] = gcol_action;
  result = sprite__op(&r);
  return result;
}

os_error * sprite_put_scaled(sprite_area *area, sprite_id *spr,
                             int gcol_action,
                             int x, int y,
                             sprite_factors *factors,
                             sprite_pixtrans *pixtrans)
{
  os_regset r;
  os_error *result;
  setfromtag(52, area, spr, &r);
  r.r[3] = x;
  r.r[4] = y;
  r.r[5] = gcol_action;
  r.r[6] = (int) factors;
  r.r[7] = (int) pixtrans;
  result = sprite__op(&r);
  return result;
}

#ifndef UROM
os_error * sprite_put_greyscaled(sprite_area *area, sprite_id *spr,
                                 int x, int y,
                                 sprite_factors *factors,
                                 sprite_pixtrans *pixtrans)
{
  os_regset r;
  os_error *result;
  setfromtag(53, area, spr, &r);
  r.r[3] = x;
  r.r[4] = y;
  r.r[5] = 0;                   /* doesn't support mask or gcol action */
  r.r[6] = (int) factors;
  r.r[7] = (int) pixtrans;
  result = sprite__op(&r);
  return result;
}
#endif

#ifndef UROM
os_error * sprite_put_mask(sprite_area *area, sprite_id *spr)
{
  os_regset r;
  os_error *result;
  setfromtag(48, area, spr, &r);
  result = sprite__op(&r);
  return result;
}
#endif

os_error * sprite_put_mask_given(sprite_area *area, sprite_id *spr,
                                 int x, int y)
{
  os_regset r;
  os_error *result;
  setfromtag(49, area, spr, &r);
  r.r[3] = x;
  r.r[4] = y;
  result = sprite__op(&r);
  return result;
}

#ifndef UROM
os_error * sprite_put_mask_scaled(sprite_area *area, sprite_id *spr,
                                  int x, int y,
                                  sprite_factors *factors)
{
  os_regset r;
  os_error *result;
  setfromtag(50, area, spr, &r);
  r.r[3] = x;
  r.r[4] = y;
  r.r[6] = (int) factors;
  result = sprite__op(&r);
  return result;
}
#endif

#ifndef UROM
os_error * sprite_put_char_scaled(char ch,
                                  int x, int y,
                                  sprite_factors *factors)
{
  os_regset r;
  os_error *result;
  r.r[0] = 51;
  r.r[1] = ch;
  r.r[3] = x;
  r.r[4] = y;
  r.r[6] = (int) factors;
  result = sprite__op(&r);
  return result;
}
#endif

os_error * sprite_create_mask(sprite_area *area, sprite_id *spr)
{
  os_regset r;
  os_error *result;
  setfromtag(29, area, spr, &r);
  result = sprite__op(&r);
  return result;
}


os_error * sprite_remove_mask(sprite_area *area, sprite_id *spr)
{
  os_regset r;
  os_error *result;
  setfromtag(30, area, spr, &r);
  result = sprite__op(&r);
  return result;
}

#ifndef UROM
os_error * sprite_insert_row(sprite_area *area, sprite_id *spr, int row)
{
  os_regset r;
  os_error *result;
  setfromtag(31, area, spr, &r);
  r.r[3] = row;
  result = sprite__op(&r);
  return result;
}
#endif

#ifndef UROM
os_error * sprite_delete_row(sprite_area *area, sprite_id *spr, int row)
{
  os_regset r;
  os_error *result;
  setfromtag(32, area, spr, &r);
  r.r[3] = row;
  result = sprite__op(&r);
  return result;
}
#endif

#ifndef UROM
os_error * sprite_insert_column(sprite_area *area, sprite_id *spr, int column)
{
  os_regset r;
  os_error *result;
  setfromtag(45, area, spr, &r);
  r.r[3] = column;
  result = sprite__op(&r);
  return result;
}
#endif

#ifndef UROM
os_error * sprite_delete_column(sprite_area *area, sprite_id *spr, int column)
{
  os_regset r;
  os_error *result;
  setfromtag(46, area, spr, &r);
  r.r[3] = column;
  result = sprite__op(&r);
  return result;
}
#endif

os_error * sprite_flip_x(sprite_area *area, sprite_id *spr)
{
  os_regset r;
  os_error *result;
  setfromtag(33, area, spr, &r);
  result = sprite__op(&r);
  return result;
}


os_error * sprite_flip_y(sprite_area *area, sprite_id *spr)
{
  os_regset r;
  os_error *result;
  setfromtag(47, area, spr, &r);
  result = sprite__op(&r);
  return result;
}

os_error * sprite_readsize(sprite_area *area, sprite_id *spr,
                           sprite_info *resultinfo)
{
  os_regset r;
  os_error *result;
  setfromtag(40, area, spr, &r);
  result = sprite__op(&r);
/* now copy returned data */
  resultinfo->width = r.r[3] ;
  resultinfo->height = r.r[4] ;
  resultinfo->mask = r.r[5] ;
  resultinfo->mode = r.r[6] ;
  return result;
}

os_error * sprite_readpixel(sprite_area *area, sprite_id *spr, int x, int y,
                            sprite_colour *resultcolour)
{
  os_regset r;
  os_error *result;
  setfromtag(41, area, spr, &r);
  r.r[3] = x;
  r.r[4] = y;
  result = sprite__op(&r);
  if (result == NULL) /* Only return result if no error */
  {
    resultcolour->colour = r.r[5];
    resultcolour->tint   = r.r[6];
  }
  return result;
}


os_error * sprite_writepixel(sprite_area *area, sprite_id *spr, int x, int y,
                            sprite_colour *colour)
{
  os_regset r;
  os_error *result;
  setfromtag(42, area, spr, &r);
  r.r[3] = x;
  r.r[4] = y;
  r.r[5] = colour->colour;
  r.r[6] = colour->tint;
  result = sprite__op(&r);
  return result;
}


os_error * sprite_readmask(sprite_area *area, sprite_id *spr, int x, int y,
                           sprite_maskstate *resultmaskstate)
{
  os_regset r;
  os_error *result;
  setfromtag(43, area, spr, &r);
  r.r[3] = x;
  r.r[4] = y;
  result = sprite__op(&r);
  if (result == NULL) /* Only return result if no error */
  {
    *resultmaskstate = (sprite_maskstate) r.r[5];
  }
  return result;
}


os_error * sprite_writemask(sprite_area *area, sprite_id *spr, int x, int y,
                            sprite_maskstate *maskstate)
{
  os_regset r;
  os_error *result;
  setfromtag(44, area, spr, &r);
  r.r[3] = x;
  r.r[4] = y;
  r.r[5] = (int) (*maskstate); /* Use pointer here for consistent interface */
  result = sprite__op(&r);
  return result;
}

#ifndef UROM
os_error *sprite_restorestate(sprite_state state)
{
  os_regset r;
  os_error *result;

  r.r[0] = state.r[0];
  r.r[1] = state.r[1];
  r.r[2] = state.r[2];
  r.r[3] = state.r[3];

  result = sprite__op(&r);
  return result;
}
#endif

#ifndef UROM
os_error *sprite_outputtosprite(sprite_area *area, sprite_id *id,
                                int *save_area, sprite_state *state)
{
  os_regset r;
  os_error *result;

  setfromtag(0x3c, area, id, &r);
  r.r[3] = (int) save_area;

  result = sprite__op(&r);
  if (result == NULL)
  {
    state->r[0] = r.r[0];
    state->r[1] = r.r[1];
    state->r[2] = r.r[2];
    state->r[3] = r.r[3];
  }
  return result;
}
#endif

#ifndef UROM
os_error *sprite_outputtomask(sprite_area *area, sprite_id *id,
                              int *save_area, sprite_state *state)
{
  os_regset r;
  os_error *result;

  setfromtag(0x3d, area, id, &r);
  r.r[3] = (int) save_area;

  result = sprite__op(&r);
  if (result == NULL)
  {
    state->r[0] = r.r[0];
    state->r[1] = r.r[1];
    state->r[2] = r.r[2];
    state->r[3] = r.r[3];
  }
  return result;
}
#endif

#ifndef UROM
os_error *sprite_outputtoscreen(int *save_area, sprite_state *state)
{
  os_regset r;
  os_error *result;

  r.r[0] = 0x3c;
  r.r[2] = 0;
  r.r[3] = (int)save_area;

  result = sprite__op(&r);
  if (result == NULL)
  {
    state->r[0] = r.r[0];
    state->r[1] = r.r[1];
    state->r[2] = r.r[2];
    state->r[3] = r.r[3];
  }
  return result;

}
#endif

#ifndef UROM
os_error *sprite_sizeof_spritecontext(sprite_area *area, sprite_id *id,
                                      int *size)
{
  os_regset r;
  os_error *result;

  setfromtag(0x3e, area, id, &r);

  result = sprite__op(&r);

  if (result == NULL)
    *size = r.r[3];

  return result;
}
#endif

#ifndef UROM
os_error *sprite_sizeof_screencontext(int *size)
{
  os_regset r;
  os_error *result;

  r.r[0] = 0x3e;
  r.r[2] = 0;

  result = sprite__op(&r);

  if (result == NULL)
    *size = r.r[3];

  return result;
}
#endif


os_error *sprite_removewastage(sprite_area *area, sprite_id *id)
{
  os_regset r;
  os_error *result;

  setfromtag(0x36, area, id, &r);

  result = sprite__op(&r);

  return result;
}


os_error  *sprite_change_size(sprite_area *area,
                              sprite_id *id,
                              BOOL rows,
                              int at,
                              int number)
{
  os_regset reg_set;
  setfromtag (rows? InsertDeleteRows: InsertDeleteColumns, area, id, &reg_set);
  reg_set.r [3] = at;
  reg_set.r [4] = number;
  return sprite__op (&reg_set);
}

os_error *sprite_put_mask_trans(sprite_area *area,
                                sprite_id *id,
                                sprite_box *box,
                                sprite_transmat *trans_mat)
{
  os_regset reg_set;
  setfromtag (PlotMaskTransformed, area, id, &reg_set);
  reg_set.r [3] = box == NULL? 0: 1 << 1;
  reg_set.r [4] = (int) box;
  reg_set.r [6] = (int) trans_mat;
  return sprite__op (&reg_set);
}

#ifndef UROM
os_error *sprite_put_mask_pgm(sprite_area *area,
                              sprite_id *id,
                              sprite_box *box,
                              sprite_pgm *pgm)
{
  os_regset reg_set;
  setfromtag (PlotMaskTransformed, area, id, &reg_set);
  reg_set.r [3] = (box == NULL? 0: 1 << 1) | (1 << 0);
  reg_set.r [4] = (int) box;
  reg_set.r [6] = (int) pgm;
  return sprite__op (&reg_set);
}
#endif

os_error *sprite_put_trans(sprite_area *area,
                           sprite_id *id,
                           int gcol_action,
                           sprite_box *box,
                           sprite_transmat *trans_mat,
                           sprite_pixtrans *pix_trans)
{
  os_regset reg_set;
  setfromtag (PutSpriteTransformed, area, id, &reg_set);
  reg_set.r [3] = box == NULL? 0: 1 << 1;
  reg_set.r [4] = (int) box;
  reg_set.r [5] = gcol_action;
  reg_set.r [6] = (int) trans_mat;
  reg_set.r [7] = (int) pix_trans;
  return sprite__op (&reg_set);
}

#ifndef UROM
os_error *sprite_put_pgm(sprite_area *area,
                         sprite_id *id,
                         int gcol_action,
                         sprite_box *box,
                         sprite_pgm *pgm,
                         sprite_pixtrans *pix_trans)
{
  os_regset reg_set;
  setfromtag (PutSpriteTransformed, area, id, &reg_set);
  reg_set.r [3] = (box == NULL? 0: 1 << 1) | (1 << 0);
  reg_set.r [4] = (int) box;
  reg_set.r [5] = gcol_action;
  reg_set.r [6] = (int) pgm;
  reg_set.r [7] = (int) pix_trans;
  return sprite__op (&reg_set);
}
#endif

#pragma -s0

/* end of c.sprite */