CTP2 Bureau : MakeSprite 0.3
CTP2 Bureau
The Modding
Knowledgebase
WePlayCiv: CtP2 Downloads
WePlayCiv: Call To Power forum
Apolyton Call To Power forums
Civilization Fanatics: Call To Power

MakeSprite 0.3

makespr 0.3 for Civilization: Call to Power 5/21/99

Contents:

1.0 The Distribution
2.0 Using the Utility
2.1 Scripts
2.1.1 Unit Sprite Scripts
2.1.2 Good Sprite Scripts
2.1.3 City Sprite Scripts
2.1.4 Effect Sprite Scripts
2.2 TIFF Folders and the Source Images
3.0 Graphics Format
4.0 File Names
4.1 Graphics File Names: units, goods, cities, effects
4.2 Script File Names
5.0 For the Not-So-Faint-Of-Heart

1.0 - The Distribution

README.TXT
LEGAL.TXT
makespr.exe
Units
1
gu01.txt
Goods
4
gg04.txt
Cities
2
gc002.txt
Effects
21
gx21.txt

2.0 - Using the Utility

This section describes how you might go about using the makespr utility to generate a sprite file (*.SPR file) for use in Call to Power.

To use the utility you'll need:

1.  A collection of TIFF images for the sprite you want to make
2.  A script file describing the sprite, and the images involved.
3.  The makespr.exe utility

Depending on what type of sprite you're making, you'll need different image files.   See each section below for details on how to make each type of sprite.

Here's the usage for the utility:

makespr 0.3: turns a bunch o' tifs into an '.SPR'

Usage: makespr [-u] [-c] [-g] [-x] [sprite id]

  -u     Convert a Unit sprite
  -c     Convert a City sprite
  -g     Convert a Good sprite
  -x     Convert an Effect sprite

 [id]    Must be between 0 and 99.

Copy the makespr.exe to the directory where you have your script file.  The script filename must follow the script file naming convention as detailed below.  In this example, it's a Unit Sprite script file.  The EXE, the script file, and the directory full of images must be in the same directory:

Units
1
gu01.txt
makespr.exe
The name of the directory with the image files is the id number of the sprite you're making, with any leading zeroes removed.  Thus, gu01.txt refers to sprite 01, or 1, the directory must be called "1"

From the command line, issue:

makespr -u 1

and a GU01.SPR will be generated and placed in the same directory as the script file.

2.1 - Scripts

To create a sprite, you need to write a script.  The script describes the attributes of the sprite, and indicates what the makespr utility can expect to find on disk.  Depending on the type of sprite, the script has varying requirements, but some features are common to all.

Scripts are made up of tags and values.  Most tags have a corresponding value, others just signify a block of other tags and values.  Blocks associated with tags have a boolean value for that tag.  That is, 0 or 1, indicating whether the block is supposed to be defined in the script.

2.1.1 - Unit Sprite Scripts

Unit sprites are made up of 5 different animations.  These are:

1.  Move - displayed when the unit is moving
2.  Attack - displayed when the unit attacks another unit, or is attacked by another unit
3.  Idle - displayed periodically while the unit is standing still and doing nothing
4.  Victory/Death - Displayed when the unit wins/loses a battle
5.  Special Action - Displayed for special attacks or things like launch or re-entry from space.

Every Unit MUST have at least one frame (frame zero) of the Move animation.  If you want to make single-frame Unit sprites, this is what you want.  You'll define only frame zero of the Move animation for each of the 5 facings, and you'll be in business.

A Unit can face 8 directions:

      1
   8  |  2
     \|/
  7---+---3
     /|\
   6  |  4
      5

To save memory and disk space, we removed facings 6, 7, and 8, and simply mirror the 2, 3, and 4 facings horizontally to simulate a full 8 facings of graphics using only 5 total facings.  Like this:

      1
   2* |  2
     \|/
  3*--+---3
     /|\
   4* |  4
      5

So, to make graphics for a sprite, you only need to create images for facings 1-5, and the other 3 facings will be generated by the code.  This lightens the graphics burden a little bit as well.  The facings are referred to as 1-5, and they are the directions indicated above.  Some unit animations need the full 5 facings (Move, Attack, Special Action) and some only require 1 facing (Idle, Victory/Death.)

Move - requires 5 facings
Attack - requires 5 facings
Idle - requires 1 facing
Victory/Death - requires 1 facing
Special Action - requires 5 facings

Here's a sample Unit Sprite script, commented heavily.  It's a script for the Cow sprite, which has a Move and a Death animation only.


##############################################################
# This is a sample Unit Sprite script.
##############################################################

0     # this leading zero is required (it can be any number.  A number
      # here is required, but ignored currently

#
# The UNIT_SPRITE keyword indicates that this is a sprite for units
#
UNIT_SPRITE
{
    # The UNIT_SPRITE_MOVE tag specifies whether this sprite has
    # a Move action.  It has a value of either 0 or 1.  If it's 0,
    # no sprite action definition block is required.  Since it's 1,
    # this block is required.
    #
    UNIT_SPRITE_MOVE    1
    {
        # This is the sprite action definition block.  All sprite
        # actions require this block if the sprite action is defined.
        #
        SPRITE_NUM_FRAMES    11    # number of frames of animation
        SPRITE_FIRST_FRAME    0    # the index of the first frame
        SPRITE_WIDTH         96    # the width of each sprite image
        SPRITE_HEIGHT        72    # the height of each sprite image
        SPRITE_HOT_POINTS          # the hot points (center points) of
                                   # the sprite for each of the 5 facings
            49 54     # facing 1
            43 51     # facing 2
            50 48     # facing 3
            58 38     # facing 4
            74 53     # facing 5
    }

    # The ANIM block is required for each UNIT_SPRITE_* action block
    # that is defined (set to 1, and has a sprite action definition
    # block.)  It describes the animation that will pay, given the
    # sprite frames described in the UNIT_SPRITE_* block.
    #
    ANIM    1
    {
        ANIM_TYPE             1     # what type of animation is this?
                                    # 0 = sequential (play through from
                                    #     the first frame to the last
                                    #     defined frame
                                    # 1 = looped (starts over at the
                                    #     first frame when it's gone
                                    #     through all of the frames
                                    # 2 = back-n-forth (reverses
                                    #     direction of playback when
                                    #     it reaches the last frame,
                                    #     and playes back to the first
                                    #     before reversing direction
                                    #     again.
        ANIM_NUM_FRAMES       10    # How many frames of animation?
        ANIM_PLAYBACK_TIME    1000  # How much time does it take to play
                                    # back the animation (in ms.)  This
                                    # is not currently supported.
        ANIM_DELAY            0     # amount of time to repeat the very
                                    # last frame of the animation before
                                    # continuing (when playing looped
                                    # or Back 'n Forth animations)
        ANIM_FRAME_DATA             # the list of the sprite frames to
            1    2    3    4    5   # to play (must be the same number
            6    7    8    9    10  # as defined in ANIM_NUM_FRAMES)

        #
        # The ANIM_MOVE_DELTAS are nudges applied to each frame of
        # animation which bump the draw location the specified offset.
        # They allow an single static frame to be moved around a fixed
        # location, for instance.
        #
        # There's one per frame of animation as defined in
        # ANIM_NUM_FRAMES
        #
        ANIM_MOVE_DELTAS    1
        {
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0

        }

        #
        # This is a 4 bit transparency value, ranged from 0-15, to be
        # applied to each frame.  This allows the sprite to fade in or
        # out over the course of animation, or whatever transparency
        # might be used for.  0 is invisible, 15 is opaque
        #
        ANIM_TRANSPARENCIES    1
        {
            15    15    15    15    15
            15    15    15    15    15
        }

    }

    #
    # The Attack animation for this sprite.  As you can see, this
    # unit doesn't have an Attack animation, so the tag's value is zero.
    # Because this tag's value is zero, there's no sprite action
    # definition block, and no ANIM {} block associated with this action.
    #
    UNIT_SPRITE_ATTACK    0

    #
    # The Idle animation for this unit.  There's no Idle animation
    # either.
    #
    # If this sprite had an idle animation, the format of the sprite
    # action definition block would be exactly the same as the format
    # of the Move block above
    #
    UNIT_SPRITE_IDLE    0

    #
    # This Unit DOES have a victory/death animation.  For this sprite
    # action definition block, and this one only (Victory) there's
    # an additional flag field immediately following the
    # UNIT_SPRITE_VICTORY tag, and that's UNIT_SPRITE_IS_DEATH, which
    # is set to either 0 (indicating that this animation specifies
    # a Victory animation--an animation to play when this unit wins
    # a battle) or 1 (indicating that this is a death animation, which
    # will play when the unit is killed.)
    #
    UNIT_SPRITE_VICTORY    1
    UNIT_SPRITE_IS_DEATH    1
    {
        SPRITE_NUM_FRAMES     17
        SPRITE_FIRST_FRAME    1
        SPRITE_WIDTH             96
        SPRITE_HEIGHT         72
        SPRITE_HOT_POINT    58 38
    }

    ANIM    1
    {
        ANIM_TYPE             0
        ANIM_NUM_FRAMES       33
        ANIM_PLAYBACK_TIME    3300
        ANIM_DELAY            0
        ANIM_FRAME_DATA
            0    1    2    3    4
            5    5    5    5    5
            6    6    7    7    8
            8    9    9    10    10
            11    11    12    12    13
            13    14    14    15    15
            16    16    0

        ANIM_MOVE_DELTAS    1
        {
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0
            0 0

        }
        ANIM_TRANSPARENCIES    1
        {
            15    15    15    15    15
            15    15    15    15    15
            15    15    15    15    15
            15    15    15    15    15
            15    15    15    15    15
            15    15    15    15    15
            15    15    15
        }

    }

    #
    # This is the Unit Sprite's Work animation (Special Animation)
    # to be used when doing special attacks or special movement.
    #
    # As you can see, it's not defined.
    #
    UNIT_SPRITE_WORK    0

    #
    # Unit Sprite Attributes Section
    #
    #
    # This section specifies a bunch of unit sprite attributes
    #

    #
    # Firepoints
    #
    # This block indicates where on the sprite that ammunition should
    # originate when the unit attacks.  This is currently ignored.
    #
    UNIT_SPRITE_FIREPOINTS    0

    # Work Firepoints
    #
    # This block indicates where on the sprite that the ammunition
    # should originate when the unit special attacks.  This is also
    # currently ignored.
    #
    UNIT_SPRITE_FIREPOINTS_WORK    0

    # UNIT_SPRITE_MOVEOFFSETS
    #
    # These are sprite nudges to be applied when the unit is moving.
    # They are an alternate way of specifying how many pixels in each
    # direction that unit should move.  There's one pair of offsets
    # (x,y) for each facing (1-5).
    #
    # These are not currently used in the engine.
    #
    UNIT_SPRITE_MOVEOFFSETS    1
    {
        0 0
        0 0
        0 0
        0 0
        0 0
    }

    # UNIT_SPRITE_SHIELDPOINTS
    #
    # This tag's block, when defined, allows you specify where the
    # unit's herald shield will appear in the sprite for each of the
    # 5 facings, for each of the 5 actions that the unit will perform.
    #
    # Often a fixed shield position wouldn't always work, as the shield
    # might cover up an important part of the sprite.  This block
    # allows specific points to be used.
    #
    UNIT_SPRITE_SHIELDPOINTS    1
    {
        UNIT_SPRITE_SHIELDPOINTS_MOVE
            82 9
            82 9
            82 9
            82 9
            82 9
        UNIT_SPRITE_SHIELDPOINTS_ATTACK
            48 36
            48 36
            48 36
            48 36
            48 36
        UNIT_SPRITE_SHIELDPOINTS_IDLE
            48 36
            48 36
            48 36
            48 36
            48 36
        UNIT_SPRITE_SHIELDPOINTS_VICTORY
            82 9
            48 36
            48 36
            48 36
            48 36
        UNIT_SPRITE_SHIELDPOINTS_WORK
            48 36
            48 36
            48 36
            48 36
            48 36
    }

}

2.1.2 - Good Sprite Scripts

##############################################################
# Sample Good Sprite Script
##############################################################
#

0 # Required 0 here

#
# The TAG for this sprite is GOOD_SPRITE
#

GOOD_SPRITE
{
 #
 # Goods only have one Action, and that's Idle.
 #
 # This is a single-facing sprite, not a multiple facing one.
 #
 GOOD_SPRITE_IDLE 1
 {
  SPRITE_NUM_FRAMES 16
  SPRITE_FIRST_FRAME 1
  SPRITE_WIDTH 96
  SPRITE_HEIGHT 72
  SPRITE_HOT_POINT 53 47
 }

 #
 # Every Action must have an ANIM block
 #
 ANIM 1
 {
  ANIM_TYPE 1
  ANIM_NUM_FRAMES 32
  ANIM_PLAYBACK_TIME 6400
  ANIM_DELAY 5000
  ANIM_FRAME_DATA
   0 1 2 3 2
   3 2 3 2 3
   4 5 6 7 8
   7 8 7 7 7
   8 7 8 7 8
   9 10 11 12 13
   14 15

  #
  # This block is expanded for illustration purposes
  # it could just as easily be replaced with:
  # ANIM_MOVE_DELTAS 0
  # to achieve the same effect
  #

  ANIM_MOVE_DELTAS 1
  {
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0
   0 0

  }

  ANIM_TRANSPARENCIES 1
  {
   15 15 15 15 15
   15 15 15 15 15
   15 15 15 15 15
   15 15 15 15 15
   15 15 15 15 15
   15 15 15 15 15
   15 15
  }
 }
}

2.1.3 - City Sprite Scripts

##############################################################
# This is a sample City Sprite script.
##############################################################
 

0 # Required 0

#
# For reasons that don't bear explanation, a city is the same
# thing as a unit.  City sprites, however, aren't used like units
# in the game engine.  It's assumed that city sprites (GC*.SPR)
# have only an IDLE action, and nothing else.
#
# So a city sprite's script looks just like a unit sprite's
# script, except that the only action defined is Idle.  Here's
# an example:
#

UNIT_SPRITE
{
 UNIT_SPRITE_MOVE 0

 UNIT_SPRITE_ATTACK 0

 UNIT_SPRITE_IDLE 1
 {
  SPRITE_NUM_FRAMES 1
  SPRITE_FIRST_FRAME 1
  SPRITE_WIDTH  96
  SPRITE_HEIGHT  76
  SPRITE_HOT_POINT 49 54
 }

 ANIM 1
 {
  ANIM_TYPE  1
  ANIM_NUM_FRAMES  1
  ANIM_PLAYBACK_TIME 1000
  ANIM_DELAY  10000
  ANIM_FRAME_DATA
   0

  ANIM_MOVE_DELTAS 0
  ANIM_TRANSPARENCIES 0

 }

 UNIT_SPRITE_VICTORY  0

 UNIT_SPRITE_WORK  0

 UNIT_SPRITE_FIREPOINTS  0

 UNIT_SPRITE_FIREPOINTS_WORK 0

 UNIT_SPRITE_MOVEOFFSETS  0

 UNIT_SPRITE_SHIELDPOINTS 0
}

2.1.4 - Effect Sprite Scripts

##############################################################
# This is a sample Effect Sprite script.
##############################################################

21 # a number is required here.  It can be any number.

#
# An Effect Sprite is much like a good sprite, except that the
# tag EFFECT_SPRITE implies that the script will define
# EFFECT_SPRITE_PLAY and EFFECT_SPRITE_FLASH.  The sprite must
# have an EFFECT_SPRITE_PLAY block, and may optionally have
# an EFFECT_SPRITE_FLASH block.
#
# The *_PLAY block defines the animation for the effect, and
# the *_FLASH block defines a special effect flash that can
# be drawn in the frame as well.  The graphics in the *_FLASH
# block are drawn in an additive mode, rather than a standard
# pixel copy mode, to allow for some lighting effects.
#
# The *_FLASH was originally designed to let us light up the
# terrain around the sprite being drawn.
#

EFFECT_SPRITE
{
 #
 # The Play block is required, and looks much like a normal
 # sprite definition block (See the Unit Sprite Script's
 # Idle block.)
 #
 # Note that an ANIM block is required whenever a sprite
 # action block is defined.
 #
 EFFECT_SPRITE_PLAY      1
 {
  SPRITE_NUM_FRAMES       12
   SPRITE_FIRST_FRAME      1
   SPRITE_WIDTH            96
   SPRITE_HEIGHT           72
   SPRITE_HOT_POINT
   58 58  # facing 1
 }

 ANIM   1
 {
  ANIM_TYPE  0  # 0 = Seq  1 = looped  2 = bnf
   ANIM_NUM_FRAMES         24
   ANIM_PLAYBACK_TIME      4800            # 1 second
   ANIM_DELAY  0  # no delay
   ANIM_FRAME_DATA
   0 1 2 3 4
   5 6 7 8 9
   10 11 0 1 2
   3 4 5 6 7
   8 9 10 11
   ANIM_MOVE_DELTAS        0
   ANIM_TRANSPARENCIES 0
 }

 #
 # Flash is not currently defined for this sprite, but if it were,
 # it would take the form of the EFFECT_SPRITE_PLAY block exactly.
 #
 EFFECT_SPRITE_FLASH  0
}

2.2 - TIFF Folders and the Source Images

When you want to compile a sprite, you place all of the appropriately constructed and appropriately named TIFF images into a folder named by the number of the sprite you want to create.  For instance, if you wanted to make sprite 25, you'd put them all in a folder called '25'

See Section 4.0 of this document for the naming convention for sprite source images.  This naming convention must be observed religiously, or the makespr.exe program won't function.

3.0 - Graphics Format

In general, the source graphics for sprites must be 32 bit TIFF's.  The R, G, and B channels of the image (8 bits each) comprise the graphic to be drawn on the screen.  The alpha channel (A channel, 8 bits) tells makespr.exe what pixels on the image are "on" and should be drawn in the game.  The alpha channel is used as a mask for the image.  Additionally, since the alpha channel is an 8 bit channel, there are 256 gray levels (0..255) that are used to perform alpha blending when the sprite is drawn.  This allows you to make portions of the sprite translucent by providing an alpha value that's less than 255 in the alpha channel of the source image.

Here's an example.  These are all from the same 32 bit TIFF file, GU01MA3.3.TIF:

Here's the RGB image of the cow:

Here's the alpha channel for that image.  Black (0) means no alpha, and white (255) means full alpha.  Gray levels in between apply a fractional alpha.

Also associated with this TIFF is a shadow file, which contains information about the shadow that this sprite casts.  The shadow file is optional.  makespr.exe will look for a shadow file that corresponds to each 32 bit image TIFF that it loads, and it'll use it if it finds it.  Otherwise, shadows are ignored.

The shadow is in a separate file, in this case, GU01MS3.3.TIF:


The shadow image is a 24 bit TIFF (no alpha channel).  makespr.exe looks for black pixels or white pixels.  White pixels mean no shadow, black pixels mean shadow.  This image is 1 bit (black or white, no gray.)

All of these images must be of the size 96x72 pixels.

As makespr.exe processes each sprite, it takes the information in the 32 bit (ARGB) TIFF and the 24 bit (RGB) shadow file (if it exists) and combines them to make each frame of the sprite.

4.0 - File Names:

4.1 Graphics File Names

Units:
GU 01 M A 1 . 0 . TIF
Type (Graphics, Units) Number (must be between 00 and 99) Action:
M - move
A - attack
I - idle
V-victory/death
W-specialAttack
Anim or Shadow 
(A or S)
Facing (1-5   Frame #
(0-99)
  Must be TIF
Move:

    GU01MA1.0.TIF
    GU01MS1.0.TIF (optional)

Attack:

    GU01AA1.0.TIF
    GU01AS1.0.TIF (optional)

Idle:

    GU01IA1.0.TIF
    GU01IS1.0.TIF (optional)

Victory/Death:

    GU01VA1.0.TIF
    GU01VS1.0.TIF (optional)

Special Action:

    GU01WA1.0.TIF
    GU01WS1.0.TIF (optional)

Goods:
GG 04 A . 1 . TIF
Type (Graphics, Goods) Number (must be between 00 and 99) Anim or Shadow (A or S)   Frame # (1-99)   Must be TIF

    GG04A.1.TIF
    GG04S.1.TIF (optional)

Cities:
GC 002 A . 1 . TIF
Type (Graphics, Cities) Number (must be between 000 and 999) Anim or Shadow (A or S)   Frame # (1-99)   Must be TIF

    GC002A.1.TIF
    GC002S.1.TIF (optional)

Effects:
GX 21 E A . 1 . TIF
Type (Graphics, fX) Number (must be between 00 and 99) Effect or Flash (E or F) Anim or Shadow (A or S)   Frame # (1-99)   Must be TIF

    GX21EA.1.TIF
    GX21ES.1.TIF (optional)

    GX21FA.1.TIF (optional)

4.2 Script File Names

Units
    GU01.TXT - where the number 01 is valid between 00 and 99.
Goods
    GG01.TXT - where the number 01 is valid between 00 and 99.
Cities
    GC001.TXT - where the number 001 is valid between 000 and 999.
Effects
    GX01.TXT - where the number 01 is valid between 00 and 99.
 

5.0 - For the Not So Faint of Heart


This section describes the data format of the encoded sprites.  This information can be used to create code to interpret, draw, or export sprites in the hands of someone who knows C/C++.

Activision provides no guarantees, and will not be held responsible for any damages that result from the use of this stuff.  It won't compile as it is right here, and is provided only as a framework to work from for those interested in writing code to handle the Civ:CTP sprite format.

Activision also won't provide any sort of tech support for questions regarding this stuff.  You're on your own.

Caveat Emptor.  Have fun.

#pragma once
#ifndef __SPRITEUTILS_H__
#define __SPRITEUTILS_H__

// 16 bit pixels of interest
#define k_CHROMAKEY_PIXEL  0x0000
#define k_SHADOW_PIXEL_565  0xF81F
#define k_SHADOW_PIXEL_555  0x7C1F
#define k_SHADOWBACKGD_PIXEL 0xFFFF
// IDs in the RLE sprite stream
#define k_CHROMAKEY_RUN_ID  0x0A
#define k_COPY_RUN_ID   0x0C
#define k_SHADOW_RUN_ID   0x0E
#define k_FEATHERED_RUN_ID  0x0F

// EOLN mask for tag
#define k_EOLN_ID    0xF0

// Alpha values
#define k_NO_ALPHA   0x00
#define k_ALL_ALPHA   0xFF

// Flag for empty row in sprite table
#define k_EMPTY_TABLE_ENTRY 0xFFFF

void spriteutils_MergeShadowMap(Pixel32 *buf, Pixel32 *shadowBuf, uint16 width, uint16 height);

// Sprite Encoding
void spriteutils_EncodeShadowRun(Pixel32 **inBuf, sint32 *pos, sint32 width, Pixel16 **outBufPtr);
void spriteutils_EncodeCopyRun(Pixel32 **inBuf, sint32 *pos, sint32 width, Pixel16 **outBufPtr);
char spriteutils_EncodeChromakeyRun(Pixel32 **inBuf, sint32 *pos, sint32 width, Pixel16 **outBufPtr);
void spriteutils_EncodeFeatheredRun(Pixel32 **inBuf, sint32 *pos, sint32 width, Pixel16 **outBufPtr);
char spriteutils_EncodeScanline(Pixel32 *scanline, sint32 width, Pixel16 **outBufPtr);
Pixel16 *spriteutils_RGB32ToEncoded(Pixel32 *buf, Pixel32 *shadowBuf, uint16 width, uint16 height);
Pixel16 *spriteutils_RGB32ToEncoded(Pixel32 *buf, uint16 width, uint16 height);

#endif//__SPRITEUTILS_H__
//////////////////////////////////////////////////////////////////////////////

void spriteutils_EncodeShadowRun(Pixel32 **inBuf, sint32 *pos, sint32 width, Pixel16 **outBufPtr)
{
 Pixel16   pix16;
 uint8   alpha;
 sint32   runLen = 0;
 Pixel16   footer=0;
 Pixel16   shadowPixel;

 if (g_is565Format) shadowPixel = k_SHADOW_PIXEL_565;
 else shadowPixel = k_SHADOW_PIXEL_555;

 RGB32Info(**inBuf, &pix16, &alpha);
 while (pix16 == shadowPixel && (*pos < width)) {
  // Increment input buffer
  (*inBuf)++;

  // Increment position counter
  (*pos)++;

  // Increment run length
  runLen++;

  RGB32Info(**inBuf, &pix16, &alpha);
 }

 // Build header/footer ID
 footer = (Pixel16)(k_SHADOW_RUN_ID << 8 | runLen);

 // Set the high nybble of the tag if it's an EOLN condition
 if (*pos >= width) footer |= k_EOLN_ID << 8;
 
 // Append header/footer ID to output buffer
 **outBufPtr = footer;
 (*outBufPtr)++;
}

//////////////////////////////////////////////////////////////////////////////
void spriteutils_EncodeCopyRun(Pixel32 **inBuf, sint32 *pos, sint32 width, Pixel16 **outBufPtr)
{
 Pixel16   pix16;
 uint8   alpha;
 sint32   runLen = 0;
 Pixel16   footer=0;
 Pixel16   *headerPtr;
 Pixel16   shadowPixel;

 if (g_is565Format) {
  shadowPixel = k_SHADOW_PIXEL_565;
 } else {
  shadowPixel = k_SHADOW_PIXEL_555;
 }

 headerPtr = *outBufPtr;
 (*outBufPtr)++;

 RGB32Info(**inBuf, &pix16, &alpha);
 while (pix16 != shadowPixel && alpha == k_ALL_ALPHA && (*pos < width)) {

  // Filter pure-black
  if (pix16 == 0x0000) pix16 = 0x0001;

  // Write pixel to output buffer
  **outBufPtr = pix16;

  // Increment output buffer
  (*outBufPtr)++;
 
  // Increment input buffer
  (*inBuf)++;

  // Increment position counter
  (*pos)++;

  // Increment run length
  runLen++;

  RGB32Info(**inBuf, &pix16, &alpha);
 }
 
 // Build the tag with the ID and length
 footer = (Pixel16) (k_COPY_RUN_ID << 8 | runLen);

 // Set the high nybble of the tag if it's an EOLN condition
 if (*pos >= width) footer |= k_EOLN_ID << 8;

 *headerPtr = footer;
}

//////////////////////////////////////////////////////////////////////////////
char spriteutils_EncodeChromakeyRun(Pixel32 **inBuf, sint32 *pos, sint32 width, Pixel16 **outBufPtr)
{
 Pixel16   pix16;
 uint8   alpha;
 sint32   runLen = 0;
 Pixel16   footer=0;

 RGB32Info(**inBuf, &pix16, &alpha);
 while (pix16 == k_CHROMAKEY_PIXEL && alpha == k_NO_ALPHA && (*pos < width)) {
  // Increment input buffer
  (*inBuf)++;

  // Increment position counter
  (*pos)++;

  // Increment run length
  runLen++;

  RGB32Info(**inBuf, &pix16, &alpha);
 }

 // If it's a full-row transparent run, it's a skipped row
 if (runLen < width) {
  // Build header/footer ID
  footer = (Pixel16)(k_CHROMAKEY_RUN_ID << 8 | runLen);

  // Set the high nybble of the tag if it's an EOLN condition
  if (*pos >= width) footer |= k_EOLN_ID << 8;
 
  // Append header/footer ID to output buffer
  **outBufPtr = footer;
  (*outBufPtr)++;
 } else {
  // return TRUE that it's an empty row
  return TRUE;
 }

 return FALSE;
}

//////////////////////////////////////////////////////////////////////////////
char spriteutils_EncodeChromakeyWshadowRun(Pixel32 **inBuf, sint32 *pos, sint32 width, Pixel16 **outBufPtr)
{
 Pixel16   pix16;
 uint8   alpha;
 sint32   runLen = 0;
 Pixel16   footer=0;

 RGB32Info(**inBuf, &pix16, &alpha);
 while ( ((pix16 == k_CHROMAKEY_PIXEL && alpha == k_NO_ALPHA) ||  (pix16 == k_SHADOWBACKGD_PIXEL))  && (*pos < width) ) {
  // Increment input buffer
  (*inBuf)++;

  // Increment position counter
  (*pos)++;

  // Increment run length
  runLen++;

  RGB32Info(**inBuf, &pix16, &alpha);
 }

 // If it's a full-row transparent run, it's a skipped row
 if (runLen < width) {
  // Build header/footer ID
  footer = (Pixel16)(k_CHROMAKEY_RUN_ID << 8 | runLen);

  // Set the high nybble of the tag if it's an EOLN condition
  if (*pos >= width) footer |= k_EOLN_ID << 8;
 
  // Append header/footer ID to output buffer
  **outBufPtr = footer;
  (*outBufPtr)++;
 } else {
  // return TRUE that it's an empty row
  return TRUE;
 }

 return FALSE;
}

//////////////////////////////////////////////////////////////////////////////
void spriteutils_EncodeFeatheredRun(Pixel32 **inBuf, sint32 *pos, sint32 width, Pixel16 **outBufPtr)
{
 Pixel16   pix16;
 Pixel16   footer=0;
 uint8   alpha;

 RGB32Info(**inBuf, &pix16, &alpha);

 (*inBuf)++;
 (*pos)++;

 footer = (k_FEATHERED_RUN_ID << 8) | alpha;

 // Set the high nybble of the tag if it's an EOLN condition
 if (*pos >= width)
  footer |= k_EOLN_ID << 8;

 // Write leading footer tag
 **outBufPtr = footer;
 (*outBufPtr)++;

 // Write pixel value
 **outBufPtr = pix16;
 (*outBufPtr)++;

}

//////////////////////////////////////////////////////////////////////////////
// this will encode a normal image with shadow merged into it.
char spriteutils_EncodeScanline(Pixel32 *scanline, sint32 width, Pixel16 **outBufPtr)
{
 Pixel16   pix16;
 Pixel32   pix32;
 Pixel32   *scanPtr = scanline;
 uint8   alpha;
 sint32   pos;
 Pixel16   *startPtr;
 BOOL   empty;
 Pixel16   shadowPixel;

 if (g_is565Format) {
  shadowPixel = k_SHADOW_PIXEL_565;
 } else {
  shadowPixel = k_SHADOW_PIXEL_555;
 }
 

 pos = 0;

 // Save starting position of the scanline's data stream
 startPtr = *outBufPtr;

 // EOLN needs to be at both ends

 while (scanPtr < (scanline + width)) {
  pix32 = *scanPtr;
 
  empty = FALSE;

  RGB32Info(pix32, &pix16, &alpha);

  if (pix16 == k_CHROMAKEY_PIXEL   && alpha == k_NO_ALPHA)
  {
   // Whitespace Run
   empty = spriteutils_EncodeChromakeyRun(&scanPtr, &pos, width, outBufPtr);
  }
  else
  if (pix16 == shadowPixel) {
   // Shadow Run
   spriteutils_EncodeShadowRun(&scanPtr, &pos, width, outBufPtr);
  }
  else
  if (alpha != k_NO_ALPHA && alpha != k_ALL_ALPHA) {
   // Feathered pixel
   spriteutils_EncodeFeatheredRun(&scanPtr, &pos, width, outBufPtr);
  }
  else {
   // Jus' a plain ol' pixel.  This is a copy run.
   if (alpha == k_ALL_ALPHA)
    spriteutils_EncodeCopyRun(&scanPtr, &pos, width, outBufPtr);
   else {
    printf("\nError in bitmap data.  Pixel with no associated alpha.\n");
    exit(-1);
   }
  }
 }

 return empty;
}

//////////////////////////////////////////////////////////////////////////////
// this will encode a shadow just like a regular image, taking into account shadow's with white backgrounds
char spriteutils_EncodeScanlineWshadow(Pixel32 *scanline, sint32 width, Pixel16 **outBufPtr)
{
 Pixel16   pix16;
 Pixel32   pix32;
 Pixel32   *scanPtr = scanline;
 uint8   alpha;
 sint32   pos;
 Pixel16   *startPtr;
 BOOL   empty;
 Pixel16   shadowPixel;

 if (g_is565Format) {
  shadowPixel = k_SHADOW_PIXEL_565;
 } else {
  shadowPixel = k_SHADOW_PIXEL_555;
 }
 

 pos = 0;

 // Save starting position of the scanline's data stream
 startPtr = *outBufPtr;

 // EOLN needs to be at both ends

 while (scanPtr < (scanline + width)) {
  pix32 = *scanPtr;
 
  empty = FALSE;

  RGB32Info(pix32, &pix16, &alpha);

  if ( (pix16 == k_CHROMAKEY_PIXEL  && alpha == k_NO_ALPHA) ||  (pix16 == k_SHADOWBACKGD_PIXEL) )
  {
   // Whitespace Run
   empty = spriteutils_EncodeChromakeyWshadowRun(&scanPtr, &pos, width, outBufPtr);
  }
  else
  if (pix16 == shadowPixel) {
   // Shadow Run
   spriteutils_EncodeShadowRun(&scanPtr, &pos, width, outBufPtr);
  }
  else
  if (alpha != k_NO_ALPHA && alpha != k_ALL_ALPHA) {
   // Feathered pixel
   spriteutils_EncodeFeatheredRun(&scanPtr, &pos, width, outBufPtr);
  }
  else {
   // Jus' a plain ol' pixel.  This is a copy run.
   if (alpha == k_ALL_ALPHA)
    spriteutils_EncodeCopyRun(&scanPtr, &pos, width, outBufPtr);
   else {
    printf("\nError in bitmap data.  Pixel with no associated alpha.\n");
    exit(-1);
   }
  }
 }

 return empty;
}

//////////////////////////////////////////////////////////////////////////////
void spriteutils_MergeShadowMap(Pixel32 *buf, Pixel32 *shadowBuf, uint16 width, uint16 height)
{
 Pixel32  *pixPtr, pix;
 Pixel32  *shadowPixPtr, shadowPix;

 // if the upper-left pixel is pure white, assume this is a white background with a black shadow on it
 // otherwise, it's a black background with a pure-magenta shadow on it
 BOOL  whiteBackground = FALSE;
 if ((*shadowBuf & 0x00FFFFFF) == 0x00FFFFFF) {
  whiteBackground = TRUE;
 } else {
  if ((*shadowBuf & 0x00FFFFFF) != 0x00000000) {
   printf("\nShadow file is in invalid format.\n");
   exit(-1);
  }
 }

 for (sint32 j=0; j
  for (sint32 i=0; i
   pixPtr = buf + j*width + i;
   shadowPixPtr = shadowBuf + j*width + i;

   pix = *pixPtr;
   shadowPix = *shadowPixPtr;
   shadowPix = shadowPix & 0x00FFFFFF;

   if (whiteBackground) {
    // See if there's shadow information there
    if (shadowPix != 0x00FFFFFF) {
     // There's a shadow pixel, copy it over to the source image's bitmap
     // only if there's null alpha
     Pixel16  r, g, b, a;

     RGB32Components(pix, &r, &g, &b, &a);

     // check against empty and full alpha
     if (a != 0xFF) {
      *pixPtr = 0x00FF00FF;
     }
    }
   } else {
    // See if there's shadow information there
    if (shadowPix) {
     // There's a shadow pixel, copy it over to the source image's bitmap
     // only if there's null alpha
     Pixel16  r, g, b, a;

     RGB32Components(pix, &r, &g, &b, &a);

     // check against empty and full alpha
     if (a != 0xFF) {
      *pixPtr = shadowPix;
     }
    }
   }
  }
 }
}

//////////////////////////////////////////////////////////////////////////////
// this takes an image and a shadow and makes one image with them
Pixel16 *spriteutils_RGB32ToEncoded(Pixel32 *buf, Pixel32 *shadowBuf, uint16 width, uint16 height)
{
 Pixel32    *srcPixel = buf;
 Pixel16    *outBuf = new Pixel16[(1+height+width*height)*8];
 Pixel16    *returnBuf = NULL;
 uint16    *table = (uint16 *)outBuf;
 Pixel16    *startOfData;
 Pixel16    *dataPtr, *startDataPtr;
 BOOL    empty;
 

 // One solution to the shadow encoding problem is to merge the shadow information sint32o the source bitmap
 if (shadowBuf != NULL)
  spriteutils_MergeShadowMap(buf, shadowBuf, width, height);

 // Write the height of the sprite as the first 16 bits of the table data
 *table++ = (uint16)height;

 startOfData = outBuf + 1 + height;
 dataPtr = startOfData;

 for(sint32 y=0; y
  // Start at the beginning of the scanline
  srcPixel = buf + width * y;

  startDataPtr = dataPtr;

  // Encode runs for this line
  empty = spriteutils_EncodeScanline(srcPixel, width, &dataPtr);
  if (empty) {
   *table++ = k_EMPTY_TABLE_ENTRY;
  } else {
   // Write the line start sint32o the table
   *table++ = startDataPtr - startOfData;
  }
 }

 sint32 resultSize = (dataPtr - outBuf);

 returnBuf = new Pixel16[resultSize];

 memcpy(returnBuf, outBuf, resultSize * sizeof(Pixel16));

 return (Pixel16 *)returnBuf;
}

//////////////////////////////////////////////////////////////////////////////
// this takes any buffer and encodes it as it's own image; Including shadows treated as seperate images
Pixel16 *spriteutils_RGB32ToEncoded(Pixel32 *buf, uint16 width, uint16 height)
{
 Pixel32    *srcPixel = buf;
 Pixel16    *outBuf = new Pixel16[(1+height+width*height)*8];
 Pixel16    *returnBuf = NULL;
 uint16    *table = (uint16 *)outBuf;
 Pixel16    *startOfData;
 Pixel16    *dataPtr, *startDataPtr;
 BOOL    empty;
 

 // Write the height of the sprite as the first 16 bits of the table data
 *table++ = (uint16)height;

 startOfData = outBuf + 1 + height;
 dataPtr = startOfData;

 for(sint32 y=0; y
  // Start at the beginning of the scanline
  srcPixel = buf + width * y;

  startDataPtr = dataPtr;

  // Encode runs for this line
  empty = spriteutils_EncodeScanlineWshadow(srcPixel, width, &dataPtr);
  if (empty) {
   *table++ = k_EMPTY_TABLE_ENTRY;
  } else {
   // Write the line start sint32o the table
   *table++ = startDataPtr - startOfData;
  }
 }

 sint32 resultSize = (dataPtr - outBuf);

 returnBuf = new Pixel16[resultSize];

 memcpy(returnBuf, outBuf, resultSize * sizeof(Pixel16));

 return (Pixel16 *)returnBuf;
}

//////////////////////////////////////////////////////////////////////////////
void spriteutils_CreateQuarterSize(Pixel32 *srcBuf, sint32 srcWidth, sint32 srcHeight, Pixel32 **destBuf, BOOL aa)
{
 sint32  destWidth = srcWidth / 2;
 sint32  destHeight = srcHeight / 2;
 sint32  i,j;
 Pixel32  pixel, pixel1, pixel2, pixel3, pixel4;
 Pixel32  *outBuf;

 outBuf = (Pixel32 *)malloc(destWidth * destHeight * sizeof(Pixel32) );
 
 for (i=0; i
  for (j=0; j
   pixel1 = srcBuf[(i * 2) * srcWidth + (j * 2)];

   if (aa) {
    pixel2 = srcBuf[(i * 2) * srcWidth + (j * 2) + 1];
    pixel3 = srcBuf[((i * 2) + 1) * srcWidth + (j * 2)];
    pixel4 = srcBuf[((i * 2) + 1) * srcWidth + (j * 2) + 1];

    pixel = spriteutils_AveragePixel32(pixel1, pixel2, pixel3, pixel4);
   } else {
    pixel = pixel1;
   }

   outBuf[i*destWidth + j] = pixel;
  }
 }
 
 *destBuf = outBuf;
}

  Administration
This site is currently maintained by: BureauBert (Webmaster)  Maquiladora (Manager)  Legal Notice: Legal Notice Statistics: 70569 unique users since 02.05.2004 (» Site Statistics) Hosted by: WebhostOne
Share this page:  VK Facebook Twitter LiveJournal OK MR Google+ LinkedIn tumblr Pinterest Blogger Digg Evernote