/* 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. */ /* c.psprite * * Paint: Arthur 2 sprite editor * Sprite handling * * Author: A.P. Thompson * Others: * DAHE David Elworthy * JRC Jonathan Coxhead * JSR Jonathan Roach * CDP Christopher Partington (Cambridge Systems Design) * TMD Tim Dobson * * Upgraded to RISC_OSlib - DAHE - 16 Aug 1989 * DAHE, 28 Aug 89 - internationalisation * DAHE, 13 Sept 89 - get round static data init. problem for module * version * JSR, 25 Oct 89 - Fix up (*= 0x11) wimp palette after reading it. * Don't fixup 256 colour palettes when reading them for * generating translation table * Filename changed to avoid conflict with RISCOSlib * CDP, 20 Feb 92 * Added FIX9544: part of fix of G-RO-9544 (large shear factor causes * arithmetic exception). Checks for float becoming too big for an int. * See also Menus.c. * Added FIX8482: fixes RO-8482 (crash when rotating doesn't cause change * of size) by not calling SpriteExtend when size change = 0 which would * cause problems. * Added FIX8490: fixes RO-8482 (crash when scale factor < 1) by * calculating deletion row/column correctly. Also avoids calling * SpriteExtend when count = 0 as for FIX8482. * CDP, 27 Feb 92 * Added FIX0553: fixes RP-0553 (create sprite, new sprite not shown in * summary in full-info mode). * TMD, 12 Mar 92 * Check in psprite_scale, psprite_rotate that x- or y-size does not * become zero. * TMD, 16 Mar 92 * Fix psprite_size to work correctly for modes where log2bpc > 3 (eg * mode 10) * TMD, 23 Mar 92 * Fix psprite_rotate to delete columns/rows from sensible position, and * optimise order for space. Removed use of FIX8482, since code * rewritten. */ #include <limits.h> #include <math.h> #include <stddef.h> /*font.h needs it, but not all get it*/ #include <swis.h> #include "Global/VduExt.h" #include "bbc.h" #include "colourtran.h" #include "flex.h" #include "help.h" #include "resspr.h" #include "visdelay.h" #include "werr.h" #include "wimpt.h" #include "ftrace.h" #include "m.h" #include "main.h" #include "SprWindow.h" #include "PSprite.h" #include "ToolWindow.h" #include "Tools.h" #include "Colours.h" #include "Menus.h" #include "MenuD.h" #if TRACE /*#define XTRACE for extended tracing*/ #endif /*#define DUMPING*/ /*dump tables when put sprite scaled fails*/ /************************************ * Static variables * ************************************/ static char ecfstring [] = { /*VDU*/ 23, 17, 4, 1, 0, 0, 0, 0, 0, 0, /*set native E C F's*/ /*VDU*/ 23, 5, 0, 0, 0, 0, 0, 0, 0, 0 /*clear E C F pattern 4*/ }; static main_ttab *tbchain = NULL; /*static main_ttab *default_translations [4];*/ /*default palette translations*/ /*!!!static main_ttab *icon_translations [4];*/ /*translations if want WIMP colours*/ /*!!!static main_ttab *brush_translations [8];*/ /*for brush sprite*/ /*copies of the current palette*/ static int wimp_colours [20], twowimp_colours [2], fourwimp_colours [4]; /* statics for sprite create stuff */ static dbox Create; static win_event_handler Old_Create_Handler; static void *Old_Create_Handle; static wimp_w Source; /* handle of the source window */ static unsigned Mode; /*just a cache to avoid flicker*/ /*mode numbers to use for x x y modes (indexed by lb_bpp)*/ static int modes_1x2 [] = {0, 8, 12, 15}, modes_2x2 [] = {-1, 1, 9, 13}, modes_1x1 [] = {25, 26, 27, 28}; /******************************** * Has the sprite got a palette * ********************************/ sprite_palflag psprite_haspal (main_sprite *sprite) { sprite_header *addr = psprite_address (sprite); ftracef2 ("psprite_haspal \"%.12s\": %s\n", addr->name, WHETHER ((char *) addr + addr->image != (char *) &addr->mode + sizeof (int))); return (sprite_palflag) ((char *) addr + addr->image != (char *) &addr->mode + sizeof (int)); } /************************************************ * Has the sprite got a palette of true colours * ************************************************/ BOOL psprite_hastruecolpal (main_sprite *sprite) { sprite_header *addr = psprite_address (sprite); int truecolpalsize = 2*4*colours_count (sprite); /*i e, 2048 for 256-colour sprites*/ ftracef2 ("psprite_hastruecolpal \"%.12s\": %s\n", addr->name, WHETHER (MIN (addr->image, addr->mask) == truecolpalsize + 44)); return MIN (addr->image, addr->mask) == truecolpalsize + 44; } /******************************** * Has the sprite got a mask * ********************************/ BOOL psprite_hasmask (main_sprite *sprite) { sprite_header *addr = psprite_address (sprite); ftracef2 ("psprite_hasmask \"%.12s\": %s\n", addr->name, WHETHER (addr->image != addr->mask)); return addr->image != addr->mask; } /******************************** * Calculate sizeof a sprite * ********************************/ int psprite_size (int width, int height, int mode, int mask, int palette) { int log2bpp = bbc_modevar (mode, bbc_Log2BPC), bpr, spritesize, palsize = 0; /*Modifed 4th Nov 1993 J R C so that |palette| may be 0 => no palette 1 => colour palette 2 => mono palette colour and mono palettes are the same except in 256-colour modes, where a 'mono' palette has 256 entries rather than 16. */ if (palette != 0) { int nc = bbc_modevar (mode, bbc_NColour) + 1; ftracef1 ("nc %d\n", nc); if (nc == 64 && palette == 2) nc = 256; palsize = 2*sizeof (int)*nc; } /*how many bytes per row?*/ bpr = (width << log2bpp) + 31 >> 5 << 2; /*round up to word boundary*/ if (!(bpr < ((INT_MAX & ~3) - sizeof (sprite_header) - palsize)/height)) { ftracef1("psprite_size: bytes per row %d too big\n", bpr); return INT_MAX & ~3; } spritesize = bpr*height; if (mask) { if (!(spritesize < ((INT_MAX & ~3) - sizeof (sprite_header) - palsize)/2)) { ftracef1("psprite_size: got mask and spritesize %d too big\n", spritesize); return INT_MAX & ~3; } if ((unsigned) mode < 256u) { /*Old-format sprite.*/ spritesize += spritesize; } else if (mode & 0x80000000) { /*8bpp alpha mask.*/ spritesize += height*((width+3)&~3); } else { /*New format sprite - 1bpp mask.*/ spritesize += height*(width + 31 >> 5 << 2); } } spritesize += sizeof (sprite_header) + palsize; #if TRACE ftracef (__FILE__, __LINE__, "psprite_size (width %d, height %d, mode %d, mask %s, " "palette %d) -> %d\n", width, height, mode, WHETHER (mask), palette, spritesize); #endif return spritesize; } /******************************** * Get full info on a sprite * ********************************/ void psprite_read_full_info (main_sprite *sprite, psprite_info *sinfo) { sprite_id sid; int i; sprite_header *header = psprite_address (sprite); ftracef1 ("read_psprite_info: (spriteno + 1) %d\n", sprite->spriteno + 1); sprite_getname (sprite->file->spritearea, sinfo->name, (i = NAME_LIMIT + 1, &i), sprite->spriteno + 1); sinfo->name [i] = '\0'; ftracef1 ("name is \"%.12s\"\n", sinfo->name); sid.tag = sprite_id_name; sid.s.name = sinfo->name; if (sprite_readsize (sprite->file->spritearea, &sid, (sprite_info *) sinfo) != NULL) { sinfo->width = -1; sinfo->height = -1; } sinfo->mode = header->mode; sinfo->mask = psprite_hasmask (sprite); sinfo->size = header->next; sinfo->palette = psprite_haspal (sprite); sinfo->truepalette = sinfo->palette && psprite_hastruecolpal (sprite); } /************************************************ * Sprite iteration: get first sprite offset * ************************************************/ int psprite_first (sprite_area **spritearea) { ftracef0 ("psprite_first\n"); if ((*spritearea)->number == 0) return 0; return (*spritearea)->sproff; } /*********************************************** * Sprite iteration: get next sprite offset * ***********************************************/ int psprite_next (sprite_area **spritearea, int sprite) { ftracef0 ("psprite_next\n"); sprite += ((sprite_header *) ((char *) *spritearea + sprite))->next; if (sprite >= (*spritearea)->freeoff) sprite = 0; return sprite; } /******************************************************** * Recalculate sprite offsets in a sprite area. * * There are already enough sprite info blocks, so * * just zap the offsets and numbers. * ********************************************************/ void psprite_recalculate_offsets (main_file *file) { main_sprite *sprite; int sproff; sprite_area *sarea = file->spritearea; int spriteno = 0; ftracef0 ("psprite_recalculate_offsets\n"); for (sprite = file->sprites, sproff = sarea->sproff; sprite != NULL && sproff < sarea->freeoff; sprite = sprite->link, sproff += ((sprite_header *) ((char *) sarea + sproff))->next) sprite->offset = sproff, sprite->spriteno = spriteno++; spencer2 ( if (sprite != NULL || sproff < file->spritearea->freeoff) { ftracef0 ("****ERROR**** mismatch between sprites and info blocks\n"); ftrace_off (); } ) ftracef0 ("psprite_recalculate_offsets: main_set_modified\n"); main_set_modified (file); ftracef0 ("psprite_recalculate_offsets -> EMPTY\n"); } /******************************************************** * Delete a sprite info block from its list * ********************************************************/ void psprite_delete (main_window *window, main_sprite *sprite) { main_sprite_window *spritewindow; main_file *file = sprite->file; main_sprite **prevsprite; int i; ftracef0 ("psprite_delete\n"); /* panic if this is the current brush */ if (sprite == tools_brushsprite_ptr) { if (toolwindow_current_tool == &tools_brushpaint) { toolwindow_stop_all_tools (); psprite_free_brush_blocks (); } tools_brushsprite_ptr = NULL; } /* free any brush translation table */ if (toolwindow_current_tool == &tools_brushpaint) psprite_drop_translation ((main_ttab **) &sprite->toolspace [2]); /* free normal translation table */ psprite_drop_translation (&sprite->transtab); /* close all windows onto the sprite */ for (spritewindow = sprite->windows; spritewindow != NULL; spritewindow = sprite->windows) sprwindow_delete (spritewindow->window); /* delete any ECFs set up */ for (i = 0; i < 4; i++) if (sprite->ECFs [i].sarea != NULL) { ftracef2 ("ECF %d freeing: 0x%X\n", i, sprite->ECFs [i].sarea); flex_free ((flex_ptr) &sprite->ECFs [i].sarea); } /* now find it on the chain, delink it and free */ for (prevsprite = &file->sprites; *prevsprite != NULL; prevsprite = &(*prevsprite)->link) if (*prevsprite == sprite) { *prevsprite = sprite->link; break; } if (sprite->flags & MSF_SELECTED) window->selection.count--; m_FREE (sprite, sizeof (main_sprite)); /*always free it! J R C 6th Dec 1993*/ } /*************************************************** * Add a sprite info block to the list indicated * ***************************************************/ main_sprite *psprite_new (int offset, int spriteno, main_file *parent) { main_sprite *sprite; int i; ftracef0 ("psprite_new\n"); if ((sprite = m_ALLOC (sizeof (main_sprite))) == NULL) { main_NO_ROOM ("main_sprite"); return 0; /* return false to abort any adding of more sprites */ } sprite->link = NULL; sprite->offset = offset; sprite->spriteno = spriteno; sprite->file = parent; sprite->windows = NULL; sprite->colourhandle = 0; sprite->gcol.colour = colours_count (sprite) - 1; sprite->gcol.alpha = 255; sprite->gcol.ecf = FALSE; sprite->flags = 0; ftracef2 ("initialised sprite \"%.12s\" GCOL 0x%X\n", psprite_address (sprite)->name, sprite->gcol); sprite->gcol2.colour = 0; sprite->gcol2.alpha = 255; sprite->gcol2.ecf = FALSE; for (i = 0; i < toolspacesize; i++) sprite->toolspace [i] = 0; ftracef2 ("0x%X->toolspace [0]: 0x%X\n", sprite, sprite->toolspace [0]); for (i = 0; i < 4; i++) sprite->ECFs [i].sarea = NULL; sprite->colourdialogue = 0; sprite->needsnull = toolwindow_current_tool == &tools_textpaint || toolwindow_current_tool == &tools_brushpaint; sprite->transtab = NULL; sprite->coloursize = main_current_options.colours.small_colours? colours_SIZE/2: colours_SIZE; return sprite; } /* Make a table - just a wrapper for 2 calls to ColourTrans_GenerateTable. An * error has happened if (*size != 0 && *table == NULL) on exit. The returned * value must be flex_free()d at some point. */ static void table_new (void *a0, void *a1, int dmode, int *dpal, int flags, int *size, char **table) { ftracef0 ("table_new\n"); os_swi6r (ColourTrans_GenerateTable, a0, a1, dmode, dpal, 0 /*read size*/, flags, NULL, NULL, NULL, NULL, size, NULL); ftracef1 ("size %d\n", *size); if (*size == 0) *table = NULL; else { if (!flex_alloc ((flex_ptr) table, *size)) { ftracef0 ("*** failed to find memory\n"); *table = NULL; return; } os_swi6 (ColourTrans_GenerateTable, a0, a1, dmode, dpal, *table, flags); } } /********************************************* * Call the SWI to build a translation table * *********************************************/ static const unsigned int modesixteen [] = /* actual colour values */ { 0, /* black */ 0xFF00, /* red */ 0xFF0000, /* green */ 0xFFFF00, /* yellow */ 0xFF000000, /* blue */ 0xFF00FF00, /* magenta */ 0xFFFF0000, /* cyan */ 0xFFFFFF00, /* white */ 0, /* black - flashing */ 0xFF00, /* red */ 0xFF0000, /* green */ 0xFFFF00, /* yellow */ 0xFF000000, /* blue */ 0xFF00FF00, /* magenta */ 0xFFFF0000, /* cyan */ 0xFFFFFF00 /* white */ }; static const unsigned int hardmode_defpal [] = /* default palette for 256 colour modes */ { 0, /* 0000 */ 0x10101000, /* 0001 */ 0x20202000, /* 0010 */ 0x30303000, /* 0011 */ 0x00004000, /* 0100 */ 0x10105000, /* 0101 */ 0x20206000, /* 0110 */ 0x30307000, /* 0111 */ 0x40000000, /* 1000 */ 0x50101000, /* 1001 */ 0x60202000, /* 1010 */ 0x70303000, /* 1011 */ 0x40004000, /* 1100 */ 0x50105000, /* 1101 */ 0x60206000, /* 1110 */ 0x70307000 /* 1111 */ }; static const unsigned int black_and_white [] = { 0, /* black */ 0xFFFFFF00 /* white */ }; static const unsigned int fourcolourpal [] = { 0, /* black */ 0xFF00, /* red */ 0xFFFF00, /* yellow */ 0xFFFFFF00 /* white */ }; int *psprite_std_palettes [2] [4]; static void init_palettes (void) { /* Required to generate relocatable code */ ftracef0 ("init_palettes\n"); psprite_std_palettes [0] [0] = twowimp_colours; psprite_std_palettes [0] [1] = fourwimp_colours; psprite_std_palettes [0] [2] = wimp_colours; psprite_std_palettes [0] [3] = (int *)hardmode_defpal; psprite_std_palettes [1] [0] = (int *)black_and_white; psprite_std_palettes [1] [1] = (int *)fourcolourpal; psprite_std_palettes [1] [2] = (int *)modesixteen; psprite_std_palettes [1] [3] = (int *)hardmode_defpal; } static int Current_Palette [256]; #ifdef XTRACE static void Trace_Ttab (main_ttab *ttab) { int i; ftracef1 ("Trace_Ttab: refcount %d table1 {", ttab->refcount); for (i = 0; i < ttab->ttab_size; i++) ftracef (NULL, 0, i == 0? "%d": ", %d", ttab->table [i]); ftracef (NULL, 0, "} sbpp %d, table2 {", ttab->sbpp); for (i = 0; i < ttab->ttab2_size; i++) ftracef (NULL, 0, i == 0? "%d": ", %d", ttab->table2 [i]); ftracef (NULL, 0, "} dbpp %d\n", ttab->dbpp); } #else #define Trace_Ttab(ttab) ((void) 0) #endif #ifdef DUMPING static void Dump_Ttab (main_ttab *ttab) { FILE *f; ftracef0 ("Dump_Ttab\n"); if ((f = fopen ("$.table", "wb")) != NULL) { fwrite (ttab->table, 1, ttab->ttab_size, f); fclose (f); } if ((f = fopen ("$.table2", "wb")) != NULL) { fwrite (ttab->table2, 1, ttab->ttab2_size, f); fclose (f); } } #endif main_ttab *psprite_ttab_for_sprite (main_sprite *sprite, int dmode, int *dpal) { main_ttab *tb = NULL; int smode, slb_bpp, dlb_bpp, sbpp, dbpp, spal [256 /*no palette can be larger than this*/], *destpal, spalsize, dncolour, dmodeflags; os_error *error; char *msg = NULL; /*this is our error indicator*/ ftracef3 ("psprite_ttab_for_sprite \"%.12s\", dmode %d, dpal 0x%X\n", psprite_address (sprite)->name, dmode, dpal); /*Get smode and spal.*/ smode = psprite_address (sprite)->mode; slb_bpp = bbc_modevar (smode, bbc_Log2BPP); dlb_bpp = bbc_modevar (dmode, bbc_Log2BPP); dncolour = bbc_modevar (dmode, bbc_NColour); dmodeflags = bbc_modevar (dmode, bbc_ModeFlags); ftracef3 ("smode 0x%X, slb_bpp %d, dlb_bpp %d\n", smode, slb_bpp, dlb_bpp); /*Catch attempts to use sprites of unknown mode.*/ if (slb_bpp != -1 && dlb_bpp != -1) { sbpp = 1 << slb_bpp; dbpp = 1 << dlb_bpp; if (sbpp <= 8) { if (psprite_haspal (sprite)) { /*Extract the (expanded) source palette from the sprite.*/ ftracef0 ("ColourTrans_ReadPalette\n"); spalsize = 4 << sbpp; if ((error = os_swix5 (ColourTrans_ReadPalette, sprite->file->spritearea, psprite_address (sprite), spal, spalsize, 1 << 0 /*R1 -> sprite*/)) != NULL) { msg = error->errmess; goto finish; } } else { /*Copy the relevant standard palette.*/ spalsize = sbpp != 8? 4 << sbpp: 4*16; memcpy (spal, psprite_std_palettes [sprite->file->use_current_palette? 0: 1] [slb_bpp], spalsize); } } else spalsize = 0; /**/ if (dmode == -1 && dbpp <= 8) { ftracef0 ("using the current palette\n"); destpal = Current_Palette; } else { ftracef0 ("using the given palette\n"); destpal = dpal; } #ifdef XTRACE { int i; ftracef1 ("source palette: %d entries\n", spalsize/4); if (sbpp <= 8) for (i = 0; i < spalsize/4; i++) ftracef2 ("%d: 0x%X\n", i, spal [i]); ftracef1 ("destination palette: %d entries\n", 1 << dbpp); if (dbpp <= 8) for (i = 0; i < 1 << dbpp; i++) ftracef2 ("%d: 0x%X\n", i, destpal [i]); } #endif /*If the table already exists, reuse it.*/ ftracef0 ("looking for table\n"); for (tb = tbchain; tb != NULL; tb = tb->link) if (tb->smode == smode && tb->dlog2bpp == dlb_bpp && tb->dncolour == dncolour && tb->dmodeflags == dmodeflags && tb->spalsize == spalsize && (sbpp <= 8? memcmp (tb->spal, spal, 4 << sbpp) == 0: TRUE) && (dbpp <= 8? memcmp (tb->dpal, destpal, 4 << dbpp) == 0: TRUE)) { tb->refcount++; break; } if (tb == NULL) { if ((tb = psprite_ttab_new (sprite, dmode, dpal)) == NULL) { msg = msgs_lookup ("PntEG"); goto finish; } /*Link this block into the list.*/ tb->link = tbchain; tbchain = tb; ftracef0 ("Made new translation table\n"); } else { ftracef0 ("using preexisting table\n"); } } finish: if (msg != NULL) { ftracef1 ("psprite_ttab_for_sprite got error \"%s\"\n", msg); return NULL; } else { Trace_Ttab (tb); ftracef0 ("psprite_ttab_for_sprite got no error\n"); return tb; } } main_ttab *psprite_ttab_new (main_sprite *sprite, int dmode, int *dpal) { main_ttab *tb = NULL; int smode, slb_bpp, dlb_bpp, sbpp, dbpp, spal [256 /*no palette can be larger than this*/], *destpal, spalsize, dncolour, dmodeflags; os_error *error; char *msg = NULL; /*this is our error indicator*/ BOOL done_tb = FALSE, done_spal = FALSE, done_dpal = FALSE, done_table = FALSE, done_table2 = FALSE; /* Returns NULL if something goes wrong, but in practice this can only be * NoMem. */ /* J R C 14th Jun 1994: rewritten again for Black: uses the fact that wide * and shallow entries are the same if dlb_bpp <= 3. Also ... * |ttab| is the translation table in the current mode (byte-, short- or * int-wide). This is used by both Sprite Extend and OS_SetColour for the * colours window. * |ttab2| is not used. * * Older operating systems are not supported - Paint uses OS_SetColour * extensively now. */ ftracef3 ("psprite_ttab_new (\"%.12s\", dmode %d, dpal 0x%X)\n", psprite_address (sprite)->name, dmode, dpal); /*Get smode and spal.*/ smode = psprite_address (sprite)->mode; slb_bpp = bbc_modevar (smode, bbc_Log2BPP); dlb_bpp = bbc_modevar (dmode, bbc_Log2BPP); dncolour = bbc_modevar (dmode, bbc_NColour); dmodeflags = bbc_modevar (dmode, bbc_ModeFlags); ftracef3 ("smode 0x%X, slb_bpp %d, dlb_bpp %d\n", smode, slb_bpp, dlb_bpp); /*Catch attempts to use sprites of unknown mode.*/ if (slb_bpp != -1 && dlb_bpp != -1) { sbpp = 1 << slb_bpp; dbpp = 1 << dlb_bpp; if (sbpp <= 8) { if (psprite_haspal (sprite)) { /*Extract the (expanded) source palette from the sprite.*/ ftracef0 ("ColourTrans_ReadPalette\n"); spalsize = 4 << sbpp; if ((error = os_swix5 (ColourTrans_ReadPalette, sprite->file->spritearea, psprite_address (sprite), spal, 4 << sbpp, 1 << 0 /*R1 -> sprite*/)) != NULL) { msg = error->errmess; goto finish; } } else { /*Copy the relevant standard palette.*/ spalsize = sbpp != 8? 4 << sbpp: 4*16; memcpy (spal, psprite_std_palettes [sprite->file->use_current_palette? 0: 1] [slb_bpp], spalsize); } } else spalsize = 0; /**/ if (dmode == -1 && dbpp <= 8) { ftracef0 ("using the current palette\n"); destpal = Current_Palette; } else { ftracef0 ("using the given palette\n"); destpal = dpal; } #ifdef XTRACE { int i; ftracef1 ("source palette: %d entries\n", spalsize/4); if (sbpp <= 8) for (i = 0; i < spalsize/4; i++) ftracef2 ("%d: 0x%X\n", i, spal [i]); ftracef1 ("destination palette: %d entries\n", 1 << dbpp); if (dbpp <= 8) for (i = 0; i < 1 << dbpp; i++) ftracef2 ("%d: 0x%X\n", i, destpal [i]); } #endif ftracef0 ("Allocate a new translation table block\n"); if ((tb = m_ALLOC (sizeof *tb)) == NULL) { msg = msgs_lookup ("PntEG"); goto finish; } done_tb = TRUE; tb->refcount = 1; ftracef0 ("Copy the palettes into the block\n"); tb->smode = smode; tb->spalsize = spalsize; if (sbpp <= 8) { if (!flex_alloc ((flex_ptr) &tb->spal, spalsize)) { tb->spal = 0; msg = msgs_lookup ("PntEG"); goto finish; } done_spal = TRUE; memcpy (tb->spal, spal, spalsize); } else tb->spal = 0; tb->dlog2bpp = dlb_bpp; tb->dncolour = dncolour; tb->dmodeflags = dmodeflags; if (dbpp <= 8) { if (!flex_alloc ((flex_ptr) &tb->dpal, 4 << dbpp)) { tb->dpal = 0; msg = msgs_lookup ("PntEG"); goto finish; } done_dpal = TRUE; memcpy (tb->dpal, destpal, 4 << dbpp); } else tb->dpal = 0; /*Black*/ if (slb_bpp > 3 || psprite_hastruecolpal (sprite)) { /*Use the sprites own palette if it has one, or if it is a deep sprite in the "new format" (in which case it's not allowed a palette at all, and ColourTrans understands this).*/ table_new (sprite->file->spritearea, psprite_address (sprite), dmode, dpal, 1 << 0 /*R1 is sprite*/ | 1 << 4 /*wide entries for deep modes*/, &tb->ttab_size, &tb->table); if (tb->ttab_size != 0 && tb->table == NULL) { msg = msgs_lookup ("PntEG"); goto finish; } done_table = TRUE; } else { /*Use one of the standard palettes for sprites without one.*/ table_new ((void *) psprite_address (sprite)->mode, psprite_std_palettes [sprite->file->use_current_palette? 0: 1] [slb_bpp], dmode, dpal, 1 << 4 /*wide entries for deep modes*/, &tb->ttab_size, &tb->table); if (tb->ttab_size != 0 && tb->table == NULL) { msg = msgs_lookup ("PntEG"); goto finish; } done_table = TRUE; } tb->table2 = NULL; tb->ttab2_size = 0; } finish: ftracef2 ("table 0x%X, table2 0x%X\n", tb->table, tb->table2); if (msg != NULL) { if (done_table2 && tb->ttab2_size != 0) flex_free ((flex_ptr) &tb->table2); if (done_table && tb->ttab_size != 0) flex_free ((flex_ptr) &tb->table); if (done_dpal) flex_free ((flex_ptr) &tb->dpal); if (done_spal) flex_free ((flex_ptr) &tb->spal); if (done_tb) m_FREE (tb, sizeof *tb); ftracef1 ("psprite_ttab_new got error \"%s\"\n", msg); werr (FALSE, msg); return NULL; } else { spencer (Trace_Ttab (tb)) ftracef0 ("psprite_ttab_new got no error\n"); return tb; } } void psprite_drop_translation (main_ttab **tb) { ftracef0 ("psprite_drop_translation\n"); if (*tb != NULL && --(*tb)->refcount == 0) { main_ttab **prev; for (prev = &tbchain; *prev != NULL; prev = &(*prev)->link) if (*prev == *tb) { ftracef1 ("ttab block @ 0x%X dies\n", *tb); *prev = (*tb)->link; psprite_ttab_delete (*tb); *tb = NULL; break; } } } void psprite_ttab_delete (main_ttab *tb) { ftracef0 ("psprite_ttab_delete\n"); ftracef0 ("psprite_ttab_delete: deleting tb->table2\n"); if (tb->table2 != 0) flex_free ((flex_ptr) &tb->table2); ftracef0 ("psprite_ttab_delete: deleting tb->table\n"); if (tb->table != 0) flex_free ((flex_ptr) &tb->table); ftracef0 ("psprite_ttab_delete: deleting tb->dpal\n"); if (tb->dpal != 0) flex_free ((flex_ptr) &tb->dpal); ftracef0 ("psprite_ttab_delete: deleting tb->spal\n"); if (tb->spal != 0) flex_free ((flex_ptr) &tb->spal); ftracef0 ("psprite_ttab_delete: deleting tb\n"); m_FREE (tb, sizeof *tb); } /*************************************************** * Calculate the default translation tables for * * the current mode. * ***************************************************/ os_error *psprite_set_default_translations (void) { int i, c1, c2, bitaddr, mode_bpp; wimp_palettestr palette_str; unsigned int mode_mask; os_error *error = NULL; ftracef0 ("psprite_set_default_translations\n"); init_palettes (); mode_bpp = 1 << bbc_modevar (-1, bbc_Log2BPP); ftracef1 ("mode_bpp %d\n", mode_bpp); mode_mask = ~0u >> 32 - mode_bpp; ftracef1 ("mode_mask %d\n", mode_mask); if (mode_bpp <= 8) os_swi5 (ColourTrans_ReadPalette, -1, -1, Current_Palette, sizeof Current_Palette, 0); /*otherwise, this is just untrustworthy*/ wimpt_noerr (wimp_readpalette (&palette_str)); /* Fix up the wimp palette */ for (i = 0; i < 20; i++) wimp_colours [i] = palette_str.c [i].word & 0xFFFFFF00; /*take out low byte*/ fourwimp_colours [0] = twowimp_colours [0] = wimp_colours [0]; fourwimp_colours [1] = wimp_colours [2/*was 1*/]; fourwimp_colours [2] = wimp_colours [4/*was 3*/]; fourwimp_colours [3] = twowimp_colours [1] = wimp_colours [7]; /*!!!for (i = 0; i < 4; i++) { psprite_drop_translation (&default_translations [i]); psprite_drop_translation (&icon_translations [i]); }*/ /* now set up an appropriate ECF string */ if (mode_bpp <= 8) { c1 = palette_str.c [0].bytes.gcol; c2 = palette_str.c [7].bytes.gcol; ftracef2 ("GCOL's are %d, %d\n", c1, c2); /* these should really be demunged if in 256 colour mode; see if anybody ever notices! */ for (i = 12; i < 20; i++) ecfstring [i] = '\0'; for (bitaddr = 0; bitaddr < 64; bitaddr += mode_bpp) { int temp, bytenum = 12 + (bitaddr >> 3), shift = bitaddr & 7, currmask = ~(mode_mask << shift); #if TRACE if (!(bytenum < 20)) werr (TRUE, "BUG!"); #endif ecfstring [bytenum] = (ecfstring [bytenum] & currmask) | c1 << shift; temp = c1; c1 = c2; c2 = temp; } } else { int black,white; os_swi3r(ColourTrans_ReturnColourNumberForMode,0,-1,-1,&black,NULL,NULL); os_swi3r(ColourTrans_ReturnColourNumberForMode,0xffffff00,-1,-1,&white,NULL,NULL); if (mode_bpp == 16) { *(short *) &ecfstring [12] = *(short *) &ecfstring [16] = white; *(short *) &ecfstring [14] = *(short *) &ecfstring [18] = black; } else /*mode_bpp == 32*/ { *(int *) &ecfstring [12] = white; *(int *) &ecfstring [16] = black; } } #if TRACE ftracef (__FILE__, __LINE__, "ecfstring %d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", ecfstring [0], ecfstring [1], ecfstring [2], ecfstring [3], ecfstring [4], ecfstring [5], ecfstring [6], ecfstring [7], ecfstring [8], ecfstring [9]); ftracef (__FILE__, __LINE__, "%d,%d,0x%X,0x%X,0x%X,0x%X,0x%X,0x%X,0x%X,0x%X\n", ecfstring [10], ecfstring [11], ecfstring [12], ecfstring [13], ecfstring [14], ecfstring [15], ecfstring [16], ecfstring [17], ecfstring [18], ecfstring [19]); #endif return error; } /**************************************************** * (Re)Calculate scaling needed for icon of sprite; * * needs mode scale already set * ****************************************************/ void psprite_set_icon_scale (main_sprite *sprite) { sprite_info infoblock; sprite_id sid; int iconwidth, iconheight, fullinfo; sprite_ptr sinfo = (sprite_ptr) psprite_address (sprite); ftracef0 ("psprite_set_icon_scale\n"); fullinfo = sprite->file->fullinfo; iconwidth = fullinfo? 3*main_FILER_TextHeight-main_FILER_Border: main_FILER_XSize; iconheight = fullinfo? iconwidth: main_FILER_YSize; ftracef2 ("iconwidth %d, iconheight %d\n", iconwidth, iconheight); sid.s.addr = sinfo; sid.tag = sprite_id_addr; /*can't do anything if mode invalid*/ if (sprite_readsize (sprite->file->spritearea, &sid, &infoblock) != NULL) return; /*But shut up about it! J R C 15th Oct 1993*/ ftracef2 ("spritewidth %d, spriteheight %d\n", infoblock.width, infoblock.height); /* do scaling to get sprite a fixed size in "filer" window */ sprite->iconsize.scale_xmul = sprite->iconsize.scale_xdiv = sprite->iconsize.scale_ymul = sprite->iconsize.scale_ydiv = 1; if (sprite->mode.scale_xmul*infoblock.width > iconwidth) { sprite->iconsize.scale_ymul = sprite->iconsize.scale_xmul = iconwidth; sprite->iconsize.scale_ydiv = sprite->iconsize.scale_xdiv = sprite->mode.scale_xmul*infoblock.width; } if (sprite->mode.scale_ymul*infoblock.height*sprite->iconsize.scale_ymul > sprite->iconsize.scale_ydiv*iconheight) /* Y dimension larger - it governs scale */ { sprite->iconsize.scale_ymul = sprite->iconsize.scale_xmul = iconheight; sprite->iconsize.scale_ydiv = sprite->iconsize.scale_xdiv = sprite->mode.scale_ymul*infoblock.height; } } /***************************************************** * Calculate the scaling tables for the given file * *****************************************************/ os_error *psprite_set_plot_info (main_file *file) { main_sprite *sprite; int mode_eig_x = bbc_modevar (-1, bbc_XEigFactor), mode_eig_y = bbc_modevar (-1, bbc_YEigFactor); os_error *error = NULL; ftracef0 ("psprite_set_plot_info\n"); for (sprite = file->sprites; sprite != NULL; sprite = sprite->link) { int mode = psprite_address (sprite)->mode, sprite_eig_x = bbc_modevar (mode, bbc_XEigFactor), sprite_eig_y = bbc_modevar (mode, bbc_YEigFactor); ftracef4 ("sprite 0x%X, mode %d, x eig %d, y eig %d\n", sprite, mode, sprite_eig_x, sprite_eig_y); sprite->mode.scale_xmul = 1 << sprite_eig_x; sprite->mode.scale_xdiv = 1 << mode_eig_x; sprite->mode.scale_ymul = 1 << sprite_eig_y; sprite->mode.scale_ydiv = 1 << mode_eig_y; ftracef0 ("calling psprite_set_icon_scale\n"); psprite_set_icon_scale (sprite); ftracef0 ("called psprite_set_icon_scale\n"); ftracef1 ("link is 0x%X\n", sprite->link); } return error; } /********************************************** * Calculate the colour translation tables * * for the sprites in the given file. * **********************************************/ int psprite_palsize (main_sprite *sprite) { sprite_header *header = psprite_address (sprite); int size, lb_bpp = bbc_modevar (header->mode, bbc_Log2BPP); /*Find out the palette size*/ if (psprite_haspal (sprite)) os_swi6r (ColourTrans_ReadPalette, sprite->file->spritearea, header, 0 /*read size*/, 0, 1 << 0 /*sprite in R1*/, 0, NULL, NULL, NULL, &size, NULL, NULL); else size = ENTRIES (lb_bpp)*sizeof (int); ftracef1 ("psprite_palsize: palette size is %d\n", size); return size; } /*New code - reallocs *palptr to point at the palette for the sprite. Sets to NULL (and frees the block) if it can't.*/ os_error *psprite_build_palette (main_sprite *sprite, int **palptr) { int size; os_error *error = NULL; ftracef0 ("psprite_build_palette\n"); m_FREE (*palptr, 0); *palptr = NULL; /*Find out the palette size*/ size = psprite_palsize (sprite); if (size != 0) { /*Get the store for the palette.*/ if ((*palptr = m_ALLOC (size)) == NULL) { error = main_error ("PntEG"); goto finish; } if (psprite_haspal (sprite)) { if ((error = os_swix6 (ColourTrans_ReadPalette, sprite->file->spritearea, psprite_address (sprite), *palptr, size, 1 << 0 /*sprite in R1*/, 0)) != NULL) goto finish; } else memcpy (*palptr, psprite_std_palettes [sprite->file->use_current_palette? 0: 1] [bbc_modevar (psprite_address (sprite)->mode, bbc_Log2BPP)], size); } finish: return error; } os_error *psprite_set_colour (main_sprite *sprite) { os_error *error = NULL; ftracef0 ("psprite_set_colour\n"); /*Not if the sprite hasn't got a sensible mode. J R C 20th Jun 1994*/ if (bbc_modevar (psprite_address (sprite)->mode, bbc_Log2BPP) != -1) { psprite_drop_translation (&sprite->transtab); ftracef0 ("calling psprite_ttab_for_sprite()\n"); if ((sprite->transtab = psprite_ttab_for_sprite (sprite, -1, (int *) -1)) == NULL) { error = main_error ("PntEG"); goto finish; } } finish: return error; } os_error *psprite_set_colour_info (main_file *file) { main_sprite *sprite; os_error *error = NULL; BOOL done_begin = FALSE; ftracef0 ("psprite_set_colour_info\n"); visdelay_begin (); done_begin = TRUE; for (sprite = file->sprites; sprite != NULL; sprite = sprite->link) if ((error = psprite_set_colour (sprite)) != NULL) goto finish; finish: if (done_begin) visdelay_end (); return error; } /*************************************************** * Plot sprite at coordinate given * * using sprites colour table, and scaled by * * sprites modescale*given scaling * ***************************************************/ os_error *psprite_plot_scaled (int x, int y, main_sprite *sprite, main_scaling_block *scale, int mode) /*Recoded to work with the new psprite_ttab_new(). J R C 17th Jun 1994*/ { main_scaling_block scaling; os_error *error; os_regset regs; ftracef1 ("psprite_plot_scaled \"%.12s\"\n", psprite_address (sprite)->name); scaling.scale_xmul = sprite->mode.scale_xmul*scale->scale_xmul; scaling.scale_xdiv = sprite->mode.scale_xdiv*scale->scale_xdiv; scaling.scale_ymul = sprite->mode.scale_ymul*scale->scale_ymul; scaling.scale_ydiv = sprite->mode.scale_ydiv*scale->scale_ydiv; Trace_Ttab (sprite->transtab); ftracef0 ("putting sprite scaled ...\n"); ftracef2 ("area 0x%X, sprite 0x%X\n", sprite->file->spritearea, psprite_address (sprite)); ftracef3 ("pos (%d, %d), action 0x%X\n", x, y, mode | 8 | psprite_haspal (sprite) << 4 | 1 << 5); ftracef4 ("factors (%d:%d, %d:%d)\n", scaling.scale_xmul, scaling.scale_xdiv, scaling.scale_ymul, scaling.scale_ydiv); ftracef1 ("table at 0x%X\n", sprite->transtab->table); /*Black*/ regs.r[0] = 512 | 52; regs.r[1] = (int)sprite->file->spritearea; regs.r[2] = (int)psprite_address (sprite); regs.r[3] = x; regs.r[4] = y; regs.r[5] = mode | 8 /*use mask if present*/ | 1 << 5 /*ttab is wide*/; regs.r[6] = (int)&scaling; regs.r[7] = (int)sprite->transtab->table; error = os_swix (OS_SpriteOp, ®s); ftracef0 ("putting sprite scaled ... done\n"); #ifdef DUMPING if (error != NULL) { Dump_Ttab (sprite->transtab); } #endif return error; } /*************************************************** * Read sprite size in os units * ***************************************************/ BOOL psprite_read_size (main_sprite *sprite, sprite_info *infoblock) { sprite_id sid; os_error *error; ftracef0 ("psprite_read_size\n"); sid.s.addr = (sprite_ptr) psprite_address (sprite); sid.tag = sprite_id_addr; if ((error = sprite_readsize (sprite->file->spritearea, &sid, infoblock)) != NULL) { ftracef1 ("sprite_readsize give error %s\n", error->errmess); return TRUE; } infoblock->width *= sprite->mode.scale_xmul; infoblock->height *= sprite->mode.scale_ymul; return FALSE; } /***************************************************** * Plot sprite at coordinate given * * using sprites colour table, and scaled by * * sprites modescale*given scaling. * * same parameters as ppsprite_plot_scaled_centred * * new 2007 CG * ****************************************************/ os_error *psprite_plot_scaled_m (int x, int y, main_sprite *sprite, main_scaling_block *scale, int mode, int maskreally) { main_scaling_block scaling; os_error *error = NULL; os_regset regs; int op, flags = 0; char *table = NULL; ftracef1 ("psprite_plot_scaled_m \"%.12s\"\n", psprite_address (sprite)->name); scaling.scale_xmul = sprite->mode.scale_xmul*scale->scale_xmul; scaling.scale_xdiv = sprite->mode.scale_xdiv*scale->scale_xdiv; scaling.scale_ymul = sprite->mode.scale_ymul*scale->scale_ymul; scaling.scale_ydiv = sprite->mode.scale_ydiv*scale->scale_ydiv; Trace_Ttab (sprite->transtab); if (!maskreally) { op = 512 | 52; flags = mode | 1 << 3 /*use mask if present*/ | 1 << 5 /*ttab is wide*/; /*JRC 30th Jan 1995*/ table = sprite->transtab->table; } else { op = 512 | 50; flags = mode; table = NULL; } ftracef0 ("putting sprite scaled ...\n"); ftracef1 ("R0 0x%X\n", op); ftracef1 ("R1 0x%X\n", sprite->file->spritearea); ftracef1 ("R2 0x%X\n", psprite_address (sprite)); ftracef1 ("R3 0x%X\n", x); ftracef1 ("R4 0x%X\n", y); ftracef1 ("R5 0x%X\n", flags); ftracef1 ("R6 0x%X\n", &scaling); ftracef1 ("R7 0x%X\n", table); ftracef4 ("factors (%d:%d, %d:%d)\n", scaling.scale_xmul, scaling.scale_xdiv, scaling.scale_ymul, scaling.scale_ydiv); regs.r[0] = op; regs.r[1] = (int)sprite->file->spritearea; regs.r[2] = (int)psprite_address (sprite); regs.r[3] = x; regs.r[4] = y; regs.r[5] = flags; regs.r[6] = (int)&scaling; regs.r[7] = (int)table; error = os_swix (OS_SpriteOp, ®s); ftracef0 ("putting sprite scaled ... done\n"); #ifdef DUMPING if (error != NULL) { Dump_Ttab (sprite->transtab); } #endif return error; } /*************************************************** * Plot sprite centred at coordinate given * * using sprites colour table, and scaled by * * sprites modescale*given scaling * ***************************************************/ os_error *psprite_plot_scaled_centred (int x, int y, main_sprite *sprite, main_scaling_block *scale, int mode, int maskreally) { sprite_info infoblock; main_scaling_block scaling; os_error *error = NULL; os_regset regs; int op, flags = 0; char *table = NULL; ftracef1 ("psprite_plot_scaled_centred \"%.12s\"\n", psprite_address (sprite)->name); psprite_read_size (sprite, &infoblock); scaling.scale_xmul = sprite->mode.scale_xmul*scale->scale_xmul; scaling.scale_xdiv = sprite->mode.scale_xdiv*scale->scale_xdiv; scaling.scale_ymul = sprite->mode.scale_ymul*scale->scale_ymul; scaling.scale_ydiv = sprite->mode.scale_ydiv*scale->scale_ydiv; infoblock.width *= scale->scale_xmul; infoblock.height *= scale->scale_ymul; infoblock.width /= scale->scale_xdiv*2; infoblock.height /= scale->scale_ydiv*2; Trace_Ttab (sprite->transtab); if (!maskreally) { op = 512 | 52; flags = mode | 1 << 3 /*use mask if present*/ | 1 << 5 /*ttab is wide*/; /*JRC 30th Jan 1995*/ table = sprite->transtab->table; } else { op = 512 | 50; flags = mode; table = NULL; } ftracef0 ("putting sprite scaled ...\n"); ftracef1 ("R0 0x%X\n", op); ftracef1 ("R1 0x%X\n", sprite->file->spritearea); ftracef1 ("R2 0x%X\n", psprite_address (sprite)); ftracef1 ("R3 0x%X\n", x - infoblock.width); ftracef1 ("R4 0x%X\n", y - infoblock.height); ftracef1 ("R5 0x%X\n", flags); ftracef1 ("R6 0x%X\n", &scaling); ftracef1 ("R7 0x%X\n", table); ftracef4 ("factors (%d:%d, %d:%d)\n", scaling.scale_xmul, scaling.scale_xdiv, scaling.scale_ymul, scaling.scale_ydiv); regs.r[0] = op; regs.r[1] = (int)sprite->file->spritearea; regs.r[2] = (int)psprite_address (sprite); regs.r[3] = x - infoblock.width; regs.r[4] = y - infoblock.height; regs.r[5] = flags; regs.r[6] = (int)&scaling; regs.r[7] = (int)table; error = os_swix (OS_SpriteOp, ®s); ftracef0 ("putting sprite scaled ... done\n"); #ifdef DUMPING if (error != NULL) { Dump_Ttab (sprite->transtab); } #endif return error; } /************************************ * Return sprite offset of a sprite * ************************************/ sprite_header *psprite_address (main_sprite *sprite) { return (sprite_header *) ((char *) sprite->file->spritearea + sprite->offset); } /********************************************* * Set fore/back GCOL and ECF to stipple * *********************************************/ void psprite_ecf (int where) { ftracef0 ("psprite_ecf\n"); #if TRACE ftracef (__FILE__, __LINE__, "VDU %d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", ecfstring [0], ecfstring [1], ecfstring [2], ecfstring [3], ecfstring [4], ecfstring [5], ecfstring [6], ecfstring [7], ecfstring [8], ecfstring [9]); ftracef (__FILE__, __LINE__, "VDU %d,%d,0x%X,0x%X,0x%X,0x%X,0x%X,0x%X,0x%X,0x%X\n", ecfstring [10], ecfstring [11], ecfstring [12], ecfstring [13], ecfstring [14], ecfstring [15], ecfstring [16], ecfstring [17], ecfstring [18], ecfstring [19]); #endif os_swix2 (OS_WriteN, (int) ecfstring, 20); bbc_gcol (64, where); } /********************************************* * Set fore/back GCOL and ECF to sprite ECF * *********************************************/ void psprite_set_ecf (main_sprite *sprite, int ECF, int where) { int i; ftracef0 ("psprite_set_ecf\n"); os_swix2 (OS_WriteN, (int) sprite->ECFs [ECF].set, 20); ftracef0 ("ecf:\n"); for (i = 12; i < 20; i++) ftracef1 (" 0x%X\n", sprite->ECFs [ECF].set [i]); bbc_gcol (64 + toolwindow_current_mode, where<<7); } /****************************************************** * Stuff dealing with brush sprite colour translation * ******************************************************/ static os_error *Set_Brush_Translation (main_sprite *sprite) { os_error *error = NULL; static int *Palette = NULL; ftracef0 ("Set_Brush_Translation\n"); /*amended to do nothing if a sprite has no windows open*/ if (sprite->windows != NULL) { /*sprite->needsnull = 1;*/ /* brush tool is now active */ /*now done in sprwindow__munge_window*/ /*Get the palette of the destination sprite.*/ ftracef1 ("building palette for \"%.12s\"\n", psprite_address (sprite)->name); if ((error = psprite_build_palette (sprite, &Palette)) != NULL) goto finish; ftracef1 ("Palette 0x%X\n", Palette); ftracef0 ("calling psprite_ttab_for_sprite()\n"); if ((sprite->toolspace [2] = (int) psprite_ttab_for_sprite (tools_brushsprite_ptr, psprite_address (sprite)->mode, Palette != NULL? Palette: (int *) -1)) == NULL) { error = main_error ("PntEG"); goto finish; } } finish: return error; } os_error *psprite_set_brush_translations (main_file *file) { BOOL done_begin = FALSE; os_error *error = NULL; ftracef0 ("psprite_set_brush_translations\n"); if (toolwindow_current_tool == &tools_brushpaint && tools_brushsprite_ptr != NULL) { main_sprite *sprite; visdelay_begin (); done_begin = TRUE; for (sprite = file->sprites; sprite != NULL; sprite = sprite->link) if ((error = Set_Brush_Translation (sprite)) != NULL) goto finish; } finish: if (done_begin) visdelay_end (); return error; } os_error *psprite_set_brush_translation (main_sprite *sprite) { os_error *error = NULL; ftracef0 ("psprite_set_brush_translation\n"); if (toolwindow_current_tool == &tools_brushpaint && tools_brushsprite_ptr != NULL) if ((error = Set_Brush_Translation (sprite)) != NULL) goto finish; finish: return error; } os_error *psprite_free_brush_blocks (void) /*free any sprite specific block*/ { os_error *error = NULL; ftracef0 ("psprite_free_brush_blocks\n"); if (tools_brushsprite_ptr != NULL) { main_window *window; /*int i;*/ /*!!!for (i = 0; i < 8; i++) { psprite_drop_translation (&brush_translations [i]); brush_translations [i] = NULL; }*/ for (window = main_windows; window != NULL; window = window->link) if (window->tag == main_window_is_file) { main_sprite *sprite; for (sprite = window->data->file.sprites; sprite != NULL; sprite = sprite->link) { psprite_drop_translation ((main_ttab **) &sprite->toolspace [2]); /*sprite->needsnull = 0;*/ /*not done here*/ } } } return error; } os_error *psprite_set_brush_colour_translations (void) { os_error *error = NULL; BOOL done_begin = FALSE; ftracef0 ("psprite_set_brush_colour_translations\n"); if (tools_brushsprite_ptr != NULL) { main_window *window; ftracef0 ("Do complete brush colour calculation\n"); visdelay_begin (); done_begin = TRUE; for (window = main_windows; window != NULL; window = window->link) if (window->tag == main_window_is_file) if ((error = psprite_set_brush_translations (&window->data->file)) != NULL) goto finish; } finish: if (done_begin) visdelay_end (); return error; } /************************************************ * Find a sprite of the given name - somewhere! * ************************************************/ main_sprite *psprite_find (char *sname, char *estring) { main_window *windows; sprite_id sid; main_sprite *spriteptr = NULL; ftracef0 ("psprite_find\n"); sid.tag = sprite_id_name; sid.s.name = sname; windows = main_windows; while (windows != NULL) { if (windows->tag == main_window_is_file) { sprite_area *area = windows->data->file.spritearea; sprite_ptr oursprite; ftracef1 ("try psprite_find in area 0x%X\n", area); if (!sprite_select_rp (area, &sid, &oursprite)) /* found it!! */ { ftracef2 ("Select sprite in area 0x%X, address 0x%X\n", area, oursprite); for (spriteptr = windows->data->file.sprites; spriteptr != NULL && psprite_address (spriteptr) != oursprite; spriteptr = spriteptr->link) ; ftracef1 ("set spriteptr to 0x%X\n", spriteptr); break; } } windows = windows->link; } if (spriteptr == NULL && estring != NULL) werr (FALSE, msgs_lookup (estring)); return spriteptr; } /************************************************************* * Extract an ECF from a sprite and attach to another sprite * *************************************************************/ void psprite_setup_ecf (main_sprite *sprite, int ECF, main_sprite *ECFsprite) { sprite_area *ecfarea; sprite_id ecfid; main_ttab *ttab; int spbpp, i, spritemode, ecfmode, splb_bpp, ecflb_bpp; main_ecf *ECFblock = &sprite->ECFs [ECF]; sprite_colour colour; BOOL ecfsmallpalette; static int *Palette = NULL; ftracef0 ("psprite_setup_ecf\n"); spritemode = psprite_address (sprite)->mode; ecfmode = psprite_address (ECFsprite)->mode; splb_bpp = bbc_modevar (spritemode, bbc_Log2BPP); ecflb_bpp = bbc_modevar (ecfmode, bbc_Log2BPP); ecfsmallpalette = ecflb_bpp == 3 && psprite_haspal (ECFsprite) && !psprite_hastruecolpal (ECFsprite); ftracef1 ("ecfsmallpalette: %s\n", ecfsmallpalette? "TRUE": "FALSE"); if (splb_bpp == -1 || ecflb_bpp == -1) { werr (FALSE, msgs_lookup ("PntEJ")); return; } psprite_build_palette (sprite, &Palette); ftracef0 ("calling psprite_ttab_for_sprite ...\n"); ttab = psprite_ttab_for_sprite (ECFsprite, spritemode, Palette); ftracef0 ("calling psprite_ttab_for_sprite ... done\n"); for (i = 0; i < 1 << (1 << ecflb_bpp); i++) ftracef2 ("%d: 0x%X\n", i, ttab->table [i]); spbpp = 1 << splb_bpp; ecfid.tag = sprite_id_addr; ecfid.s.addr = psprite_address (ECFsprite); ecfarea = ECFsprite->file->spritearea; memcpy (ECFblock->set, ecfstring, 20); if (ecflb_bpp <= 3) for (i = 0; i < 8; i++) { int j, shift, byte = 0; for (shift = 0, j = 0; shift < 8; shift += spbpp, j++) { if (main_read_pixel (ecfarea, &ecfid, j, 7 - i, &colour)) { colour.colour = 0; colour.tint = 0; /* ECFsprite may be too small really */ } ftracef3 ("pixel (%d, %d) = 0x%X\n", j, 7 - i, colour.colour); if (ecfsmallpalette) /*rotate inner bitfield thrice for inverse transform, add in tint*/ colour.colour = colours_gcol_ttab [colours_gcol_ttab [colours_gcol_ttab [colour.colour]]] << 2 | colour.tint >> 6; byte |= ttab->table [colour.colour] << shift; ftracef3 ("row %d, bit %d, byte 0x%X\n", 7 - i, shift, ttab->table [colour.colour]); } ftracef1 ("0x%X\n", byte); ECFblock->set [i + 12] = byte; } else if (ecflb_bpp == 4) for (i = 0; i < 4; i++) /*can only use 4 rows*/ { ftracef1 ("guard %.4s\n", ttab->table); main_read_pixel (ecfarea, &ecfid, 0, 3 - i, &colour); ftracef1 ("pixel value is 0x%X\n", colour.colour); *(short *) &ECFblock->set [2*i + 12] = ((char *) (((int *) ttab->table) [1])) [colour.colour]; ftracef2 ("row %d, byte 0x%X\n", 3 - i, *(short *) &ECFblock->set [2*i + 12]); } else /*ecflb_bpp == 5*/ for (i = 0; i < 2; i++) /*only 2 rows*/ { int c; ftracef1 ("guard %.4s\n", ttab->table); main_read_pixel (ecfarea, &ecfid, 0, 1 - i, &colour); ftracef1 ("pixel value is 0x%X\n", colour.colour); c = (colour.colour & 0xFF)*31/0xFF | (colour.colour >> 8 & 0xFF)*31/0xFF << 5 | (colour.colour >> 16 & 0xFF)*31/0xFF << 10; ftracef1 ("15-bit value is 0x%X\n", c); *(int *) &ECFblock->set [4*i + 12] = ((char *) (((int *) ttab->table) [1])) [c]; ftracef2 ("row %d, byte 0x%X\n", 1 - i, *(int *) &ECFblock->set [4*i + 12]); } /* now need to build a sprite of the right size and fill it */ /* Need a sprite that will appear colours_SIZE square on screen, after mode scaling */ { int spritesize, cmode; os_regset reg_set; /*For this to work the ECF sprite must have the same palette as the sprite in which it is to be painted; otherwise, it stands no chance of being rendered on screen correctly. Note that at this point we know that this must be a shallow sprite. JRC 10th Feb 1995*/ spritesize = psprite_size (colours_SIZE/sprite->mode.scale_xmul, colours_SIZE/sprite->mode.scale_ymul, spritemode, /*mask?*/ FALSE, /*palette?*/ 2) + sizeof (sprite_area); if (ECFblock->sarea == NULL) { flex_alloc ((flex_ptr) &ECFblock->sarea, spritesize); if (ECFblock->sarea == NULL) main_NO_ROOM ("ECF sprite"); } sprite_area_initialise (ECFblock->sarea, spritesize); sprite_create (ECFblock->sarea, "", sprite_nopalette, colours_SIZE/sprite->mode.scale_xmul, colours_SIZE/sprite->mode.scale_ymul, spritemode); if (os_swix4 (OS_SpriteOp, 37 | 0x200 /*create/remove palette*/, ECFblock->sarea, (int) ECFblock->sarea + sizeof (sprite_area), 1 /*create*/ | 1U << 31) != NULL) main_NO_ROOM ("ECF palette"); os_swix5 (ColourTrans_ReadPalette, sprite->file->spritearea, psprite_address (sprite), (int) ECFblock->sarea + sizeof (sprite_area) + sizeof (sprite_header), 8 << (1 << splb_bpp), (1 << 1) + 1); reg_set.r [0] = 0x23C /*switch output to sprite*/; reg_set.r [1] = (int) ECFblock->sarea; reg_set.r [2] = reg_set.r [1] + sizeof (sprite_area); /* address of first & only sprite in area */ reg_set.r [3] = 0; os_swix (OS_SpriteOp, ®_set); cmode = toolwindow_current_mode; toolwindow_current_mode = 0; psprite_set_ecf (sprite, ECF, /*bg?*/ 1); /* set background to ECF */ /* now need to set ECF origin so that bottom line of sprite has bottom line of ECF */ os_swix2 (OS_SetECFOrigin, 0, sprite->mode.scale_ymul*7); /* align top left of ECF with point 8 rows up */ bbc_clg (); /* fill the sprite with the ECF */ toolwindow_current_mode = cmode; os_swix (OS_SpriteOp, ®_set) /*unswitch output*/; } if (sprite->colourdialogue == 0) colours_set_extent (sprite); } /*************************************************** * Plot ECF sprite at coordinate given * * using sprites colour table, and scaled by * * sprites modescale * ***************************************************/ os_error *psprite_plot_ecf_sprite (main_sprite *sprite, int ECF, int x, int y) { os_error *error; os_regset regs; main_scaling_block scaling; ftracef0 ("psprite_plot_ecf_sprite\n"); scaling = sprite->mode; if (sprite->coloursize == colours_SIZE/2) scaling.scale_xdiv *= 2, scaling.scale_ydiv *= 2; ftracef0 ("putting ecf sprite scaled ...\n"); /*bad translation a pain*/ regs.r[0] = 512 | 52; regs.r[1] = (int)sprite->ECFs [ECF].sarea; regs.r[2] = (int)(sprite->ECFs [ECF].sarea + 1); regs.r[3] = x; regs.r[4] = y; regs.r[5] = psprite_haspal (sprite) << 4 /*use ttab if there is no palette*/ | 1 << 5 /*ttab is wide*/; regs.r[6] = (int)&scaling; regs.r[7] = (int)sprite->transtab->table; error = os_swix (OS_SpriteOp, ®s); ftracef0 ("putting ecf sprite scaled ... done\n"); #ifdef DUMPING if (error != NULL) { Dump_Ttab (sprite->transtab); } #endif return error; } /*********************************************************** * Merge a sprite area into another; an in-core version * * of MOS's file merging. * ***********************************************************/ BOOL psprite_merge_area (main_window *window, main_file *file, sprite_area **area) { sprite_area area_info; char sname [NAME_LIMIT + 1]; sprite_id sid; int i, len, no_sprites; main_sprite **endptr; char *msg = NULL; os_error *error; ftracef0 ("psprite_merge_area\n"); for (endptr = &file->sprites; *endptr != NULL; endptr = &(*endptr)->link) ; sid.tag = sprite_id_name; sid.s.name = sname; ftracef2 ("psprite_merge_area: sprite area 0x%X -> file area 0x%X\n", *area, file->spritearea); if ((error = sprite_area_readinfo (*area, &area_info)) != NULL) { msg = error->errmess; goto finish; } no_sprites = area_info.number; ftracef1 ("area has %d sprites\n", no_sprites); ftracef0 ("psprite_merge_area: now loop checking the sprites\n"); for (i = 1; i <= no_sprites; i++) { main_sprite **sprptr = NULL; sprite_header *header; BOOL newsprite; if ((error = sprite_getname (*area, sname, (len = NAME_LIMIT + 1, &len), 1)) != NULL) /*always looking at the first sprite in the area*/ { msg = error->errmess; goto finish; } sname [len] = '\0'; ftracef1 ("psprite_merge_area: Sprite called %.12s\n", sname); newsprite = sprite_select_rp (file->spritearea, &sid, (sprite_ptr) &header) != NULL; if (!newsprite) { ftracef0 ("psprite_merge_area: sprite exists; move its information " "block to the end of the chain\n"); for (sprptr = &file->sprites; *sprptr != NULL && psprite_address (*sprptr) != header; sprptr = &(*sprptr)->link) ; sprite_delete (file->spritearea, &sid); #if TRACE if (*sprptr == NULL) werr (TRUE, "Failed to find sprite info block"); #endif *endptr = *sprptr; /* point chain end at block */ endptr = &(*sprptr)->link; /* step end */ *sprptr = *endptr; /* delink block */ *endptr = NULL; /* terminate chain */ } if ((error = sprite_select_rp (*area, &sid, (sprite_ptr) &header)) != NULL) { msg = error->errmess; goto finish; } if (!menus_ensure_size (&file->spritearea, header->next)) { if (!newsprite && *sprptr != NULL) psprite_delete (window,*sprptr); psprite_recalculate_offsets (file); msg = msgs_lookup ("PntEG"); goto finish; } sprite_select_rp (*area, &sid, (sprite_ptr) &header); /*might have moved */ memmove ((char *) file->spritearea + file->spritearea->freeoff, header, header->next); if (newsprite) { ftracef0 ("created new sprite; make a new block at the chain end\n"); if ((*endptr = psprite_new (file->spritearea->freeoff, 0, file)) == NULL) { sprite_delete (file->spritearea, &sid); psprite_recalculate_offsets (file); msg = msgs_lookup ("PntEG"); goto finish; } endptr = &(*endptr)->link; } sprite_select_rp (*area, &sid, (sprite_ptr) &header); /*might have moved*/ file->spritearea->freeoff += header->next; file->spritearea->number++; ftracef0 ("sprite_delete\n"); sprite_delete (*area, &sid); ftracef0 ("menus_ensure_size\n"); menus_ensure_size (area, 0); ftracef0 ("psprite_recalculate_offsets\n"); psprite_recalculate_offsets (file); } finish: if (msg != NULL) { werr (FALSE, msg); return FALSE; } else return TRUE; } /************************************** * Rotate a sprite through n degrees. * **************************************/ void Temporary_Name (sprite_area *sarea, char *name) { int i; sprite_id sid; ftracef0 ("Temporary_Name\n"); sid.tag = sprite_id_name; sid.s.name = name; for (i = 0;; i++) { sprintf (name, "%d", i); if (sprite_select (sarea, &sid)) { ftracef1 ("temp sprite name generated is \"%s\"\n", name); return; } } } void psprite_rotate (main_sprite *sprite, int degrees) { ftracef0 ("psprite_rotate\n"); if ((degrees %= 360) != 0) /* optimise 0! */ { int ldx, ldy, dx, dy, nw, nh; double x, y, xmax = 0, ymax = 0, xmin = 0, ymin = 0, rads = (double) degrees/360.0*2*3.141592653589793, c = cos (rads), s = sin (rads); psprite_info sinfo; main_sprite_window *sprw; sprite_id sid, sid2; sprite_transmat trans_mat; char tempname [NAME_LIMIT + 1], realname [NAME_LIMIT + 1], *msg = NULL; BOOL created_sprite = FALSE, hourglass = FALSE, switched_output = FALSE; os_error *error; sprintf (realname, "%.12s", psprite_address (sprite)->name); ftracef5 ("psprite_rotate: \"%s\" %d deg = %g rad; cos %g sin %g\n", realname, degrees, rads, c, s); sprwindow_remove_wastage (sprite); psprite_read_full_info (sprite, &sinfo); dx = 1 << (ldx = bbc_modevar (sinfo.mode, bbc_XEigFactor)); dy = 1 << (ldy = bbc_modevar (sinfo.mode, bbc_YEigFactor)); sinfo.width <<= ldx; sinfo.height <<= ldy; /* size in OS units */ /* Now inspect all corners of the sprite to find new bounding box */ x = sinfo.width*c; y = sinfo.width*s; ftracef3 ("0, %d -> %g, %g\n", sinfo.width, x, y); if (x > xmax) xmax = x; if (x < xmin) xmin = x; if (y > ymax) ymax = y; if (y < ymin) ymin = y; x = -(sinfo.height*s); /*funny brackets*/ y = sinfo.height*c; ftracef3 ("%d, 0 -> %g, %g\n", sinfo.height, x, y); if (x > xmax) xmax = x; if (x < xmin) xmin = x; if (y > ymax) ymax = y; if (y < ymin) ymin = y; x = sinfo.width*c - sinfo.height*s; y = sinfo.width*s + sinfo.height*c; ftracef4 ("%d, %d -> %g, %g\n", sinfo.width, sinfo.height, x, y); if (x > xmax) xmax = x; if (x < xmin) xmin = x; if (y > ymax) ymax = y; if (y < ymin) ymin = y; nw = (int) ((xmax - xmin)/dx + 0.5); nh = (int) ((ymax - ymin)/dy + 0.5); /*in pixels*/ ftracef4 ("old sprite %dx%d; new %dx%d (O S units)\n", sinfo.width, sinfo.height, nw << ldx, nh << ldy); /*Disallow zero width or height*/ if (nw == 0 || nh == 0) { msg = msgs_lookup ("PntEA"); return; } /*Now know limits of sprite: ensure room for copy*/ ftracef4 ("psprite_rotate: changing size from (%d, %d) to (%d, %d) " "(O S units)\n", sinfo.width, sinfo.height, nw << ldx, nh << ldy); sinfo.width >>= ldx; sinfo.height >>= ldy; /*convert back to pixels*/ if (!menus_ensure_size (&sprite->file->spritearea, sinfo.size)) { msg = msgs_lookup ("PntEG"); goto finish; } sid.tag = sprite_id_name; sid.s.name = realname; Temporary_Name (sprite->file->spritearea, tempname); ftracef0 ("copying sprite\n"); if ((error = sprite_copy (sprite->file->spritearea, &sid, tempname)) != NULL) { ftracef0 ("ERROR\n"); msg = error->errmess; goto finish; } created_sprite = TRUE; sid2.tag = sprite_id_name; sid2.s.name = tempname; /* Make sure there is enough space for the rotated sprite. * We used to need MAX (nw, sinfo.width) and MAX (nh, sinfo.height), but * we don't any more because we always do any deletion of rows/columns * before insertion of columns/rows. */ if (!menus_ensure_size (&sprite->file->spritearea, psprite_size (nw, nh, sinfo.mode, sinfo.mask, !sinfo.palette? 0: !sinfo.truepalette? 1: 2) - sinfo.size)) { ftracef0 ("ERROR\n"); msg = msgs_lookup ("PntEG"); goto finish; } visdelay_begin (); hourglass = TRUE; ftracef2 ("adding %d columns and %d rows to source sprite\n", nw - sinfo.width, nh - sinfo.height); /*If reducing width then do (width, height) else do (height, width)*/ if (nw - sinfo.width < 0) if ((error = sprite_change_size (sprite->file->spritearea, &sid, /*rows?*/ FALSE, /*at*/ nw, nw - sinfo.width)) != NULL) { ftracef0 ("ERROR\n"); msg = error->errmess; goto finish; } if (nh - sinfo.height != 0) if ((error = sprite_change_size (sprite->file->spritearea, &sid, /*rows?*/ TRUE, /*at*/ nh > sinfo.height? sinfo.height: nh, nh - sinfo.height)) != NULL) { ftracef0 ("ERROR\n"); msg = error->errmess; goto finish; } if (nw - sinfo.width > 0) if ((error = sprite_change_size (sprite->file->spritearea, &sid, /*rows?*/ FALSE, /*at*/ sinfo.width, nw - sinfo.width)) != NULL) { ftracef0 ("ERROR\n"); msg = error->errmess; goto finish; } ftracef0 ("done\n"); c *= 0x10000; /* Scaled coordinates from now on */ s *= 0x10000; /*Now uses Fishface's new OS_SpriteOp SWI reason code to rotate the sprite. Infinitely faster. JRC 30th Nov '89*/ trans_mat [0] = (int) c; trans_mat [1] = (int) s; trans_mat [2] = -(int) s; trans_mat [3] = (int) c; trans_mat [4] = -(int) (0x100*xmin); trans_mat [5] = -(int) (0x100*ymin); ftracef2 ("int c = %d, int s = %d\n", (int) c, (int) s); sprwindow_swap_output_to_sprite (sprite); switched_output = TRUE; ftracef0 ("Plotting copy back to original, rotated\n"); os_swi2 (OS_SetColour, 1 << 4, 0); #if 0 /*replaces the following, avoiding need to check full-palette bit*/ bbc_gcol (0, 0); /*shurely this was shupposhed to set the background?*/ bbc_tint (0, 0); #endif bbc_clg (); if ((error = sprite_put_trans (sprite->file->spritearea, &sid2, 0, NULL, &trans_mat, NULL)) != NULL) { ftracef0 ("ERROR\n"); msg = error->errmess; goto finish; } if (sprwindow_swap_output_to_mask (sprite, TRUE)) { ftracef0 ("Same for mask\n"); os_swi2 (OS_SetColour, 1 << 4, 0); #if 0 /*replaces the following, avoiding need to check full-palette bit*/ bbc_gcol (0, 0); /*shurely this was shupposhed to set the background?*/ bbc_tint (0, 0); #endif bbc_clg (); os_swi2 (OS_SetColour, 1 << 4, -1); #if 0 /*replaces the following, avoiding need to check full-palette bit*/ bbc_gcol (0, 0x80 | 63); bbc_tint (3, 3); #endif if ((error = sprite_put_mask_trans (sprite->file->spritearea, &sid2, NULL, &trans_mat)) != NULL) { ftracef0 ("ERROR\n"); msg = error->errmess; goto finish; } } finish: if (switched_output) sprwindow_swap_output_to_screen (); if (hourglass) visdelay_end (); if (created_sprite) sprite_delete (sprite->file->spritearea, &sid2); menus_ensure_size (&sprite->file->spritearea, 0); sprwindow_invalidate (sprite); /*J R C 8th Dec 1993*/ psprite_set_icon_scale (sprite); /*psprite_recalculate_offsets (sprite->file); Done in Menus.c.*/ for (sprw = sprite->windows; sprw != NULL; sprw = sprw->link) sprwindow_set_work_extent (sprw->window, TRUE); ftracef0 ("reporting error for psprite_rotate()\n"); if (msg != NULL) werr (FALSE, msg); } } void psprite_scale (main_sprite *sprite, double scale_x, double scale_y) /*Do not die on errors - report them and continue. J R C 25th Nov 1993*/ { psprite_info sinfo; int ldx, ldy, dx, dy, nw, nh; sprite_id sid, sid2; char tempname [NAME_LIMIT + 1], realname [NAME_LIMIT + 1], *msg = NULL; main_sprite_window *sprw; sprite_transmat trans_mat; BOOL switched_output = FALSE, created_sprite = FALSE, hourglass = FALSE; os_error *error; ftracef0 ("psprite_scale\n"); ftracef2 ("scaling by (%f, %f)\n", scale_x, scale_y); strcpy (realname, psprite_address (sprite)->name); sprwindow_remove_wastage (sprite); psprite_read_full_info (sprite, &sinfo); dx = 1 << (ldx = bbc_modevar (sinfo.mode, bbc_XEigFactor)); dy = 1 << (ldy = bbc_modevar (sinfo.mode, bbc_YEigFactor)); sinfo.width <<= ldx; sinfo.height <<= ldy; /* size in OS units */ nw = (int) (sinfo.width*scale_x/dx + 0.5); nh = (int) (sinfo.height*scale_y/dy + 0.5); /*in pixels*/ /* disallow zero size sprites */ if (nw == 0 || nh == 0) { msg = msgs_lookup ("PntEA"); goto finish; } sinfo.width >>= ldx; sinfo.height >>= ldy; /*ensure room for copy*/ if (!menus_ensure_size (&sprite->file->spritearea, sinfo.size)) { msg = msgs_lookup ("PntEG"); goto finish; } sid.tag = sprite_id_name; sid.s.name = realname; Temporary_Name (sprite->file->spritearea, tempname); if ((error = sprite_copy (sprite->file->spritearea, &sid, tempname)) != NULL) { msg = error->errmess; goto finish; } created_sprite = TRUE; sid2.tag = sprite_id_name; sid2.s.name = tempname; /*Make sure there is enough room for the scaled sprite*/ if (!menus_ensure_size (&sprite->file->spritearea, psprite_size (MAX (nw, sinfo.width), MAX (nh, sinfo.height), sinfo.mode, sinfo.mask, !sinfo.palette? 0: !sinfo.truepalette? 1: 2) - sinfo.size)) /*Need MAX() because intermediate sprites may be bigger.*/ { msg = msgs_lookup ("PntEG"); goto finish; /*was return; J R C 3rd Mar 1994*/ } visdelay_begin (); hourglass = TRUE; ftracef2 ("psprite_scale: changing x size from %d to %d\n", sinfo.width, nw); if (nw - sinfo.width != 0) if ((error = sprite_change_size (sprite->file->spritearea, &sid, /*rows?*/ FALSE, /*at*/ nw > sinfo.width? sinfo.width: nw, nw - sinfo.width)) != NULL) { msg = error->errmess; goto finish; } ftracef2 ("psprite_scale: changing y size from %d to %d\n", sinfo.height, nh); if (nh - sinfo.height != 0) if ((error = sprite_change_size (sprite->file->spritearea, &sid, /*rows?*/ TRUE, /*at*/ nh > sinfo.height? sinfo.height: nh, nh - sinfo.height)) != NULL) { msg = error->errmess; goto finish; } trans_mat [0] = (int) (scale_x*0x10000); trans_mat [1] = 0; trans_mat [2] = 0; trans_mat [3] = (int) (scale_y*0x10000); trans_mat [4] = 0; trans_mat [5] = 0; sprwindow_swap_output_to_sprite (sprite); switched_output = TRUE; /*Clear the output to colour 0.*/ os_swi2 (OS_SetColour, 1 << 4, 0); #if 0 /*replaces the following, avoiding need to check full-palette bit*/ bbc_gcol (0, 0); /*shurely this was shupposhed to set the background?*/ bbc_tint (0, 0); #endif bbc_clg (); if ((error = sprite_put_trans (sprite->file->spritearea, &sid2, 0, NULL, &trans_mat, NULL)) != NULL) { msg = error->errmess; goto finish; } if (sprwindow_swap_output_to_mask (sprite, TRUE)) { os_swi2 (OS_SetColour, 1 << 4, 0); #if 0 /*replaces the following, avoiding need to check full-palette bit*/ bbc_gcol (0, 0); /*shurely this was shupposhed to set the background?*/ bbc_tint (0, 0); #endif bbc_clg (); os_swi2 (OS_SetColour, 1 << 4, -1); #if 0 /*replaces the following, avoiding need to check full-palette bit*/ bbc_gcol (0, 0x80 | 63); bbc_tint (3, 3); #endif if ((error = sprite_put_mask_trans (sprite->file->spritearea, &sid2, NULL, &trans_mat)) != NULL) { msg = error->errmess; goto finish; } } finish: if (switched_output) sprwindow_swap_output_to_screen (); if (hourglass) visdelay_end (); if (created_sprite) sprite_delete (sprite->file->spritearea, &sid2); menus_ensure_size (&sprite->file->spritearea, 0); sprwindow_invalidate (sprite); /*J R C 8th Dec 1993*/ psprite_set_icon_scale (sprite); /*psprite_recalculate_offsets (sprite->file);*/ for (sprw = sprite->windows; sprw != NULL; sprw = sprw->link) sprwindow_set_work_extent (sprw->window, TRUE); if (msg != NULL) werr (FALSE, msg); } void psprite_shear (main_sprite *sprite, double factor) /*Do not die on errors - report them and continue. J R C 25th Nov 1993*/ { psprite_info sinfo; int ldx, ldy, dx, dy, nw, nh, shift; main_sprite_window *sprw; sprite_id sid, sid2; sprite_transmat trans_mat; char tempname [NAME_LIMIT + 1], realname [NAME_LIMIT + 1], *msg = NULL; float tmp_f; BOOL switched_output = FALSE, hourglass = FALSE, created_sprite = FALSE; os_error *error; ftracef0 ("psprite_shear\n"); ftracef1 ("factor %f\n", factor); strcpy (realname, psprite_address (sprite)->name); sprwindow_remove_wastage (sprite); psprite_read_full_info (sprite, &sinfo); dx = 1 << (ldx = bbc_modevar (sinfo.mode, bbc_XEigFactor)); dy = 1 << (ldy = bbc_modevar (sinfo.mode, bbc_YEigFactor)); sinfo.width <<= ldx; sinfo.height <<= ldy; /* size in OS units */ ftracef2 ("width %d, height %d OS units\n", sinfo.width, sinfo.height); ftracef4 ("ceil ((%f + %f)/%d) = %f\n", (double) sinfo.width, fabs (sinfo.height * factor), dx, ceil (((double) sinfo.width + fabs (sinfo.height*factor))/dx)); tmp_f = (float) ceil (((double) sinfo.width + fabs (sinfo.height*factor))/dx); if (tmp_f > INT_MAX) { /* new width too large to handle so cause error */ msg = msgs_lookup ("PntEM"); goto finish;; } nw = (int) tmp_f; ftracef3 ("ceil (%f/%d) = %f\n", sinfo.height, dy, ceil ((double) sinfo.height/dy)); /* don't need to check for height going out of range */ nh = (int) ceil ((double) sinfo.height/dy); sinfo.width >>= ldx; sinfo.height >>= ldy; /*convert back to pixels*/ /*ensure room for copy*/ if (!menus_ensure_size (&sprite->file->spritearea, sinfo.size)) { msg = msgs_lookup ("PntEG"); goto finish; } sid.tag = sprite_id_name; sid.s.name = realname; Temporary_Name (sprite->file->spritearea, tempname); if ((error = sprite_copy (sprite->file->spritearea, &sid, tempname)) != NULL) { msg = error->errmess; goto finish; } created_sprite = TRUE; sid2.tag = sprite_id_name; sid2.s.name = tempname; /*Make sure there is enough space for the rotated sprite.*/ if (!menus_ensure_size (&sprite->file->spritearea, psprite_size (MAX (nw, sinfo.width), MAX (nh, sinfo.height), sinfo.mode, sinfo.mask, !sinfo.palette? 0: !sinfo.truepalette? 1: 2) - sinfo.size)) /*Need MAX() because intermediate sprites may be bigger.*/ { msg = msgs_lookup ("PntEG"); goto finish; } visdelay_begin (); hourglass = TRUE; ftracef2 ("psprite_shear: changing x size from %d to %d\n", sinfo.width, nw); if ((error = sprite_change_size (sprite->file->spritearea, &sid, /*rows?*/ FALSE, /*at*/ sinfo.width /*shearing can never make the sprite smaller*/, nw - sinfo.width)) != NULL) { msg = error->errmess; goto finish; } ftracef2 ("psprite_shear: changing y size from %d to %d\n", sinfo.height, nh); if ((error = sprite_change_size (sprite->file->spritearea, &sid, /*rows?*/ TRUE, /*at*/ sinfo.height /*shearing can never make the sprite smaller*/, nh - sinfo.height)) != NULL) { msg = error->errmess; goto finish; } shift = (int) ((factor*dy/dx)*sinfo.height); trans_mat [0] = 1*0x10000; trans_mat [1] = 0; trans_mat [2] = (int) (factor*0x10000); trans_mat [3] = 1*0x10000; trans_mat [4] = ((shift < 0? -shift: 0) << ldx)*0x100; trans_mat [5] = 0; sprwindow_swap_output_to_sprite (sprite); switched_output = TRUE; /*Clear the output to colour 0.*/ os_swi2 (OS_SetColour, 1 << 4, 0); #if 0 /*replaces the following, avoiding need to check full-palette bit*/ bbc_gcol (0, 0); /*shurely this was shupposhed to set the background?*/ bbc_tint (0, 0); #endif bbc_clg (); if ((error = sprite_put_trans (sprite->file->spritearea, &sid2, 0, NULL, &trans_mat, NULL)) != NULL) { msg = error->errmess; goto finish; } if (sprwindow_swap_output_to_mask (sprite, TRUE)) { ftracef0 ("Same for mask\n"); os_swi2 (OS_SetColour, 1 << 4, 0); #if 0 /*replaces the following, avoiding need to check full-palette bit*/ bbc_gcol (0, 0); /*shurely this was shupposhed to set the background?*/ bbc_tint (0, 0); #endif bbc_clg (); os_swi2 (OS_SetColour, 1 << 4, -1); #if 0 /*replaces the following, avoiding need to check full-palette bit*/ bbc_gcol (0, 0x80 | 63); bbc_tint (3, 3); #endif if ((error = sprite_put_mask_trans (sprite->file->spritearea, &sid2, NULL, &trans_mat)) != NULL) { msg = error->errmess; goto finish; } } finish: if (switched_output) sprwindow_swap_output_to_screen (); if (hourglass) visdelay_end (); if (created_sprite) sprite_delete (sprite->file->spritearea, &sid2); menus_ensure_size (&sprite->file->spritearea, 0); sprwindow_invalidate (sprite); /*J R C 8th Dec 1993*/ psprite_set_icon_scale (sprite); /*psprite_recalculate_offsets (sprite->file);*/ for (sprw = sprite->windows; sprw != NULL; sprw = sprw->link) sprwindow_set_work_extent (sprw->window, TRUE); if (msg != NULL) werr (FALSE, msg); } /********************************** * Generate/do Create sprite * **********************************/ static void Decode (int *lb_bpp_out, unsigned int *mode_out) { wimp_which_block which_block; wimp_i results [7]; /*only 2 would be needed if function keys couldn't wierdly set multiple icons in the same E S G*/ int x_eig = 0, y_eig = 0, lb_bpp = 0, cols = 0; unsigned int mode; ftracef0 ("Decode\n"); which_block.window = dbox_syshandle (Create); which_block.bit_mask = wimp_ISELECTED | 31 << 16; which_block.bit_set = wimp_ISELECTED | 2 << 16; /*colour E S G is 2*/ wimpt_noerr (wimp_which_icon (&which_block, results)); ftracef1 ("colours icon %d\n", results [0]); switch (results [0]) { case d_Create_Colours_2: lb_bpp = 0; break; case d_Create_Colours_4: lb_bpp = 1; break; case d_Create_Colours_16: lb_bpp = 2; break; case d_Create_Colours_256: lb_bpp = 3; break; case d_Create_Colours_4k: lb_bpp = 4, cols = 1<<12; break; case d_Create_Colours_32k: lb_bpp = 4; cols = 1<<15; break; case d_Create_Colours_64k: lb_bpp = 4; cols = 1<<16; break; case d_Create_Colours_16M: lb_bpp = 5; break; } ftracef1 ("lb_bpp %d\n", lb_bpp); which_block.bit_set = wimp_ISELECTED | 3 << 16; /*x eig E S G is 3*/ wimpt_noerr (wimp_which_icon (&which_block, results)); ftracef1 ("x dpi icon %d\n", results [0]); switch (results [0]) { case d_Create_XEIG_0: x_eig = 0; break; case d_Create_XEIG_1: x_eig = 1; break; case d_Create_XEIG_2: x_eig = 2; break; } ftracef1 ("x_eig %d\n", x_eig); which_block.bit_set = wimp_ISELECTED | 4 << 16; /*y eig E S G is 4*/ wimpt_noerr (wimp_which_icon (&which_block, results)); ftracef1 ("y dpi icon %d\n", results [0]); switch (results [0]) { case d_Create_YEIG_0: y_eig = 0; break; case d_Create_YEIG_1: y_eig = 1; break; case d_Create_YEIG_2: y_eig = 2; break; } ftracef1 ("y_eig %d\n", y_eig); /*So, is this a mode?*/ mode = ~0u; if (lb_bpp <= 3) { if (x_eig == 1 && y_eig == 1) mode = modes_1x1 [lb_bpp]; else if (x_eig == 1 && y_eig == 2) mode = modes_1x2 [lb_bpp]; else if (x_eig == 2 && y_eig == 2) mode = modes_2x2 [lb_bpp]; } if ((mode == ~0u) && (lb_bpp == 4) && (cols != 1<<15)) { /*Special handling of 16bpp.Always create TBGR for now.*/ if (cols == 1<<12) mode = (15 << 27) | (16 << 20) | 0 | y_eig << 6 | x_eig << 4 | 1u; else mode = (10 << 27) | 180u >> y_eig << 14 | 180u >> x_eig << 1 | 1u; ftracef1 ("mode 0x%X\n", mode); } if (mode == ~0u) { mode = lb_bpp + 1 << 27 | 180u >> y_eig << 14 | 180u >> x_eig << 1 | 1u; ftracef1 ("mode 0x%X\n", mode); } else ftracef1 ("mode %d\n", mode); if (mode_out != NULL) *mode_out = mode; if (lb_bpp_out != NULL) *lb_bpp_out = lb_bpp; } /* this function will close the create dbox if it the window handle passed is the same as the source */ extern BOOL psprite_close_createbox (wimp_w w) { ftracef2 ("psprite_close_createbox: closing 0x%x, Source 0x%x\n", w, Source); if (w == Source) { if (Create != NULL) dbox_dispose (&Create); Create = NULL, Source = 0; ftracef0 ("Closed Create box due to sprite filer window closing\n"); return TRUE; } return FALSE; } static void create_create_sprite (dbox d, main_window *window) { char name [NAME_LIMIT + 2]; int width, height, sprite_size, white /*GCOL for white pixels*/, lb_bpp, *new_pal, e; unsigned mode; BOOL want_palette, want_mask, mono; sprite_id sid; main_sprite *sprite; psprite_info info; sprite_area **sarea = &window->data->file.spritearea; wimp_paletteword palette_white; sprite_header *addr; char *msg = NULL; os_error *error; ftracef0 ("create_create_sprite\n"); dbox_getfield (d, d_Create_Name, name, NAME_LIMIT + 1); if (name [0] == '\0') { msg = msgs_lookup ("PntE7"); goto finish; } if (menus_sprite_exists (*sarea, name)) goto finish; width = dbox_getnumeric (d, d_Create_Width); height = dbox_getnumeric (d, d_Create_Height); if (width <= 0 || height <= 0) { msg = msgs_lookup ("PntEA"); goto finish; } Decode (&lb_bpp, &mode); want_palette = lb_bpp <= 3 && /*was mode < 256u JRC 5th Dec 1994*/ !dbox_getnumeric (d, d_Create_Palette_None); mono = want_palette && dbox_getnumeric (d, d_Create_Palette_Mono); want_mask = !dbox_getnumeric (d, d_Create_Mask); #if TRACE ftracef (__FILE__, __LINE__, "Creating Sprite '%s': width=%d height=%d mask=%d palette=%d " "Mode=%d\n", name, width, height, want_mask, want_palette, mode); #endif /* extend sprite area so that creation is guaranteed */ sprite_size = psprite_size (width, height, mode, want_mask, !want_palette? 0: !mono? 1: 2); if (!menus_ensure_size (sarea, sprite_size)) { msg = msgs_lookup ("PntEG"); goto finish; } ftracef0 ("creating sprite\n"); if ((error = sprite_create_rp (*sarea, name, sprite_nopalette, width, height, mode, (sprite_ptr *) &addr)) != NULL) { msg = error->errmess; goto finish; } /*Just checking ...*/ ftracef1 ("new sprite mode is %d\n", addr->mode); if (want_palette) { /*Create the sprite without a palette, then give it one of the right mode. JRC 17 Sept 1991*/ int i, *p; static int N [] = {0xFFFFFF, 0x555555, 0x111111, 0x010101}; /*this is the palette we might give to the sprite*/ new_pal = !mono? psprite_std_palettes [window->data->file.use_current_palette? 0: 1] [lb_bpp]: NULL; if ((error = os_swix4 (OS_SpriteOp, 37 | 0x200 /*create/remove palette*/, (int) *sarea, (int) addr, 1 /*create*/ | (lb_bpp == 3 && mono? 1U << 31: 0))) != NULL) { msg = error->errmess; goto finish; } /*That palette is not the one we want though.*/ p = &addr->mode + 1; if (!mono) { e = ENTRIES (lb_bpp); for (i = 0; i < e; i++) p [2*i] = p [2*i + 1] = new_pal [i]; } else { e = 1 << (1 << lb_bpp); for (i = 0; i < e; i++) p [2*i] = p [2*i + 1] = i*N [lb_bpp] << 8; } #ifdef XTRACE /*Trace the palette ...*/ for (i = 0; i < e; i++) { char mode1, r1, g1, b1; BOOL s1; mode1 = p [2*i]; s1 = (mode1 & 0x80) != 0; if (s1) mode1 &= ~0x80; r1 = p [2*i] >> 8; g1 = p [2*i] >> 16; b1 = p [2*i] >> 24; ftracef (__FILE__, __LINE__, "%-24d(0x%X, 0x%X, 0x%X), mode %d%s\n", i, r1, g1, b1, mode1, s1? "S": ""); } #endif } sid.s.name = name; sid.tag = sprite_id_name; if (want_mask) if ((error = sprite_create_mask (*sarea, &sid)) != NULL) { msg = error->errmess; goto finish; } menus_sprite_new (window, /*hack palette?*/ FALSE); /*psprite_set_brush_translations (&window->data->file); No point - done in menus_sprite_new(). JRC 11 September 1991*/ /*find correct info block */ for (sprite = window->data->file.sprites; sprite->link != NULL; sprite = sprite->link) ; /*if (want_palette) menus_hack_palette (sprite); Now done in menus_sprite_new(). JRC 12 September 1991*/ psprite_read_full_info (sprite, &info); /*JRC 27 May 1991 Make the sprite white (rather than 0-pixels).*/ palette_white.word = (int)0xFFFFFF00; sprwindow_swap_output_to_sprite (sprite); if (want_palette || lb_bpp > 3) { /*If the sprite has a palette or is deep, life is easy.*/ wimpt_noerr (colourtran_setGCOL (palette_white, 1 << 7, 0, &white)); bbc_clg (); } else { /*If not, we have to resort to ...*/ wimpt_noerr (colourtran_return_colourformode (palette_white, mode, (wimp_paletteword *) psprite_std_palettes [window->data->file.use_current_palette? 0: 1] [lb_bpp], &white)); ftracef1 ("giving nearest colour number of %d\n", white); os_swi2 (OS_SetColour, 1 << 4, white); bbc_clg (); } sprwindow_swap_output_to_screen (); /* Having filled with white, find the furthest colour from white and select it */ palette_white.word = 0; wimpt_noerr (colourtran_return_colourformode (palette_white, mode, (wimp_paletteword *) psprite_std_palettes [window->data->file.use_current_palette? 0: 1] [lb_bpp], (int *) &sprite->gcol.colour)); sprite->gcol.alpha = 255; sprite->gcol.ecf = FALSE; /* Auto open sprite window here */ sprwindow_new (sprite); if (main_current_options.tools.show_tools) toolwindow_display (/*at pointer?*/ FALSE); /* force summary window to be updated */ window->data->file.lastwidth = 0; /*JRC 12 June 1991*/ main_set_extent (window); main_force_redraw (window->handle); finish: if (msg != NULL) werr (FALSE, msg); } static void create_event (main_window *window, wimp_i i) { int height = dbox_getnumeric (Create, d_Create_Height), width = dbox_getnumeric (Create, d_Create_Width); wimp_mousestr mouse_str; BOOL adjust; ftracef0 ("create_event\n"); wimpt_noerr (wimp_get_point_info (&mouse_str)); adjust = (mouse_str.bbits & wimp_BRIGHT) != 0; ftracef0 ("create_event\n"); switch (i) { case d_Create_Ok: create_create_sprite (Create, window); ftracef0 ("Tried to create sprite\n"); break; case d_Create_Down: adjust = !adjust; /*fall through*/ case d_Create_Up: if (adjust) { if (height > 1) dbox_setnumeric (Create, d_Create_Height, height - 1); } else dbox_setnumeric (Create, d_Create_Height, height + 1); break; case d_Create_Left: adjust = !adjust; /*fall through*/ case d_Create_Right: if (adjust) { if (width > 1) dbox_setnumeric (Create, d_Create_Width, width - 1); } else dbox_setnumeric (Create, d_Create_Width, width + 1); break; } } static void Create_Cb (dbox d, void *handle) { wimp_i i = dbox_get (d); ftracef1 ("Create_Cb: event on icon %d\n", i); create_event ((main_window *) handle, i); if (i == d_Create_Ok || i == d_Create_Cancel || i == dbox_CLOSE) { dbox_dispose (&Create); Create = NULL, Source = 0; } } static BOOL Grey_Scale (int lb_bpp) { int colour_count = 1 << (1 << lb_bpp), palette [256], i, colour; os_regset swi_regs; os_error *oserror; BOOL incomplete; /*Given that the current mode is 256 colours or less, is it a grey-scale mode?*/ swi_regs.r [0] = 0; swi_regs.r [1] = colour_count | 17 << 24; swi_regs.r [2] = (int) palette; swi_regs.r [3] = 0; swi_regs.r [4] = 7 /*read block of palette entries*/; swi_regs.r [9] = 35 /*PaletteV*/; if ((oserror = os_swix (OS_CallAVector, &swi_regs)) != NULL) { ftracef1 ("error %s\n", oserror->errmess); return FALSE; } incomplete = swi_regs.r [4]; if (!incomplete) { for (i = 0; i < colour_count; i++) if ((palette [i] ^ palette [i] << 8) >> 16 != 0) { ftracef1 ("colour %d not grey\n", i); return FALSE; } } else /*Couldn't read a block of colours - try reading singly.*/ for (i = 0; i < colour_count; i++) { swi_regs.r [0] = i; swi_regs.r [1] = 17; swi_regs.r [4] = 1 /*read palette entry*/; swi_regs.r [9] = 35 /*PaletteV*/; if ((oserror = os_swix (OS_CallAVector, &swi_regs)) != NULL) { ftracef1 ("error %s\n", oserror->errmess); return FALSE; } colour = swi_regs.r [2]; incomplete = swi_regs.r [4]; if (incomplete) { /*Resort to OS_ReadPalette*/ if ((oserror = os_swix3r (OS_ReadPalette, i, 17, 0, NULL, NULL, &colour)) != NULL) { ftracef1 ("error %s\n", oserror->errmess); return FALSE; } } if ((colour ^ colour << 8) >> 16 != 0) { ftracef1 ("colour %d not grey\n", i); return FALSE; } } ftracef0 ("all colours grey\n"); return TRUE; } static BOOL Have4k64k (void) { /*True if the OS can plot 4k and 64k TBGR, else false*/ /*The fallback for unknown sprite types in the kernel is 32bpp, so if asking about 4k & 64k we get back 32bpp as the answer, the kernel has used the fallback since it should be 16bpp*/ return (bbc_modevar (0x79004051u /* 4k TBGR */, bbc_Log2BPP) != 5 && bbc_modevar (0x501680B5u /* 64k TBGR */, bbc_Log2BPP) != 5); } static void Create_Handler (wimp_eventstr *e, void *handle) { int lb_bpp; unsigned mode; BOOL extd_16bpp = Have4k64k(); handle = handle; ftracef0 ("Create_Handler\n"); /*Let the proper handler do its stuff first ...*/ (*Old_Create_Handler) (e, Old_Create_Handle); /*Now we have a look in, in order to update the mode display field. Sneaky! J R C 2nd Nov 1993*/ if (Create != NULL) { /*don't proceed if the window's gone*/ Decode (&lb_bpp, &mode); if (dbox_getnumeric (Create, d_Create_Palette_Colour) || dbox_getnumeric (Create, d_Create_Palette_Mono)) { dbox_fadefield (Create, d_Create_Colours_4k); dbox_fadefield (Create, d_Create_Colours_32k); dbox_fadefield (Create, d_Create_Colours_64k); dbox_fadefield (Create, d_Create_Colours_16M); } else { if (extd_16bpp) dbox_unfadefield (Create, d_Create_Colours_4k); dbox_unfadefield (Create, d_Create_Colours_32k); if (extd_16bpp) dbox_unfadefield (Create, d_Create_Colours_64k); dbox_unfadefield (Create, d_Create_Colours_16M); } if (mode != Mode) { /*This code altered to reflect new-format shallow sprites with palette. JRC 5th Dec 1994*/ if (mode < 256u) dbox_setnumeric (Create, d_Create_Mode, mode), dbox_unfadefield (Create, d_Create_Mode_LabelL), dbox_unfadefield (Create, d_Create_Mode), dbox_unfadefield (Create, d_Create_Mode_LabelR); else /*No corresponding old-style mode.*/ dbox_setfield (Create, d_Create_Mode, ""), dbox_fadefield (Create, d_Create_Mode_LabelL), dbox_fadefield (Create, d_Create_Mode), dbox_fadefield (Create, d_Create_Mode_LabelR); if (lb_bpp <= 3) /*After Black, all shallow sprites can have palettes.*/ dbox_unfadefield (Create, d_Create_Palette_Colour), dbox_unfadefield (Create, d_Create_Palette_Mono); else dbox_fadefield (Create, d_Create_Palette_Colour), dbox_fadefield (Create, d_Create_Palette_Mono); Mode = mode; } } } void psprite_create_show (main_window *window, BOOL auto_open, char *sprite_name) { int width, height, x_eig, y_eig, lb_bpp, ncolour; BOOL grey_scale, full_palette, extd_16bpp = Have4k64k(); wimp_w d_w; ftracef0 ("psprite_create_show\n"); if (Create != NULL) { ftracef0 ("Killing Create box because already open\n"); dbox_dispose (&Create); Create = NULL, Source = 0; } if ((Create = dbox_new ("create")) == NULL) return; /*Intercept events on this dbox.*/ d_w = dbox_syshandle (Create); win_read_eventhandler (d_w, &Old_Create_Handler, &Old_Create_Handle); win_register_event_handler (d_w, Create_Handler, NULL); Source = window->handle; dbox_raw_eventhandler (Create, &help_dboxrawevents, (void *) "PntH7"); width = bbc_modevar (-1, bbc_XWindLimit); height = bbc_modevar (-1, bbc_YWindLimit); if (width == -1 || height == -1) { werr (FALSE, msgs_lookup ("PntEJ")); return; } width++, height++; x_eig = bbc_modevar (-1, bbc_XEigFactor); y_eig = bbc_modevar (-1, bbc_YEigFactor); lb_bpp = bbc_modevar (-1, bbc_Log2BPP); ncolour = bbc_modevar (-1, bbc_NColour); full_palette = (bbc_modevar (-1, bbc_ModeFlags) & 0x80) != 0; grey_scale = lb_bpp <= 3 && Grey_Scale (lb_bpp); ftracef4 ("x_eig %d, y_eig %d, lb_bpp %d, grey_scale %s\n", x_eig, y_eig, lb_bpp, grey_scale? "TRUE": "FALSE"); dbox_setfield (Create, d_Create_Name, sprite_name); dbox_setnumeric (Create, d_Create_Mask, FALSE); dbox_setnumeric (Create, d_Create_Width, width); dbox_setnumeric (Create, d_Create_XEIG_2, x_eig == 2); dbox_setnumeric (Create, d_Create_XEIG_1, x_eig == 1); dbox_setnumeric (Create, d_Create_XEIG_0, x_eig == 0); dbox_setnumeric (Create, d_Create_Height, height); dbox_setnumeric (Create, d_Create_YEIG_2, y_eig == 2); dbox_setnumeric (Create, d_Create_YEIG_1, y_eig == 1); dbox_setnumeric (Create, d_Create_YEIG_0, y_eig == 0); dbox_setnumeric (Create, d_Create_Palette_Colour, lb_bpp <= 3 && !grey_scale); dbox_setnumeric (Create, d_Create_Palette_Mono, lb_bpp <= 3 && grey_scale); dbox_setnumeric (Create, d_Create_Palette_None, lb_bpp > 3); dbox_setnumeric (Create, d_Create_Colours_2, lb_bpp == 0); dbox_setnumeric (Create, d_Create_Colours_4, lb_bpp == 1); dbox_setnumeric (Create, d_Create_Colours_16, lb_bpp == 2); dbox_setnumeric (Create, d_Create_Colours_256, lb_bpp == 3); dbox_setnumeric (Create, d_Create_Colours_4k, lb_bpp == 4 && (ncolour == 4095)); dbox_setnumeric (Create, d_Create_Colours_32k, lb_bpp == 4 && !full_palette); dbox_setnumeric (Create, d_Create_Colours_64k, lb_bpp == 4 && full_palette); dbox_setnumeric (Create, d_Create_Colours_16M, lb_bpp == 5); ftracef1 ("bbc_modevar (6 << 27 | 1, bbc_Log2BPP) %d\n", bbc_modevar (6 << 27 | 1, bbc_Log2BPP)); if (bbc_modevar (6 << 27 | 1, bbc_Log2BPP) == -1) { /*This is not Medusa hardware - shade colours > 256.*/ dbox_fadefield (Create, d_Create_Colours_32k); dbox_fadefield (Create, d_Create_Colours_16M); } if (!extd_16bpp) { /*This OS can't do 4k and 64k.*/ dbox_fadefield (Create, d_Create_Colours_4k); dbox_fadefield (Create, d_Create_Colours_64k); } Decode (&lb_bpp, &Mode); if ((unsigned) Mode < 256u) { /*There is a mode, so we could put a palette on*/ dbox_setnumeric (Create, d_Create_Mode, Mode); dbox_unfadefield (Create, d_Create_Mode_LabelL), dbox_unfadefield (Create, d_Create_Mode), dbox_unfadefield (Create, d_Create_Mode_LabelR), dbox_unfadefield (Create, d_Create_Palette_Colour); dbox_unfadefield (Create, d_Create_Palette_Mono); } else { /*256 colours or less: may still be new-style mode though.*/ dbox_setfield (Create, d_Create_Mode, ""); dbox_fadefield (Create, d_Create_Mode_LabelL), dbox_fadefield (Create, d_Create_Mode), dbox_fadefield (Create, d_Create_Mode_LabelR), dbox_fadefield (Create, d_Create_Palette_Colour); dbox_fadefield (Create, d_Create_Palette_Mono); } if (auto_open == -1) /* open from menu branch */ { BOOL open; dbox_show (Create); open = TRUE; while (open) { wimp_i i = dbox_fillin (Create); ftracef1 ("event on icon %d\n", i); create_event (window, i); if (i == d_Create_Ok) open = dbox_persist (); else if (i == d_Create_Cancel || i == dbox_CLOSE) open = FALSE; } dbox_dispose (&Create); Create = NULL, Source = 0; } else { dbox_showstatic (Create); dbox_eventhandler (Create, &Create_Cb, (void *) window); } } char *psprite_get_colours(int mode) { int ncolour,modeflags; ncolour = bbc_modevar(mode, bbc_NColour); modeflags = bbc_modevar(mode, bbc_ModeFlags); /* Assuming RGB */ char *ncol; switch(ncolour) { case 1: ncol = "2"; break; case 3: ncol = "4"; break; case 15: ncol = "16"; break; case 63: case 255: ncol = "256"; break; case 4095: ncol = "4k"; break; case 65535: if(modeflags & ModeFlag_64k) ncol = "64k"; else ncol = "32k"; break; case 16777215: case -1: ncol = "16M"; break; default: ncol = "?"; break; } return ncol; } transparency_type psprite_transparency_type(main_sprite *spr) { int mode = psprite_address(spr)->mode; if(psprite_hasmask(spr)) { if(mode & 0x80000000) return transparency_type_alphamask; return transparency_type_onoffmask; } int modeflags = bbc_modevar(mode, bbc_ModeFlags); if((modeflags != -1) && (modeflags & ModeFlag_DataFormatSub_Alpha)) return transparency_type_alphachannel; return transparency_type_none; }