Sprite Editor for Sprites Mode 2 (using OR color)

Page 1/3
| 2 | 3

By albs_br

Master (184)

albs_br's picture

26-12-2020, 03:57

Hi guys, maybe I haven't searched well, but I was unable to find an editor for sprites of the MSX2, 9938 VDP.
It can be online or offline, and would be good if it's able to edit the 16 colors RGB.
I could write one in Javascript, but there would be such a waste of time and energy as someone surely made it before.

Thanks

Login or register to post comments

By mzoran

Expert (102)

mzoran's picture

26-12-2020, 10:49

Not sure if it satisfies all you needs but try
https://code.google.com/p/spritesx-ed/

By Bengalack

Master (244)

Bengalack's picture

26-12-2020, 15:28

I never found one. Been looking for a long time for that.

By sd_snatcher

Prophet (3401)

sd_snatcher's picture

26-12-2020, 16:01

Me too.

By albs_br

Master (184)

albs_br's picture

26-12-2020, 20:23

mzoran wrote:

Not sure if it satisfies all you needs but try
https://code.google.com/p/spritesx-ed/

It looks great. The features are exactly what I'm looking for, but it won't work.
Dowloads page returns error: "401: Anonymous caller does not have storage.objects.get access to the Google Cloud Storage object."
Same with source and wiki.

Google searching found nothing, all references for download or code are broken. The author (aorante) is absten from MRC sinc 2016, twitter profile and personal blog deleted.

By Bengalack

Master (244)

Bengalack's picture

26-12-2020, 20:51

albs_br wrote:

It looks great. The features are exactly what I'm looking for, but it won't work.

To the best of my knowledge, it does not preview the OR-color, so it does not help much. I have it, it is part of the Fusion-C package. It is under "tools". It looks like this:

I have never found a way to preview any combined sprites. No way to pair or combine them. AFAIK, it just saves the colorcode with the CC-bit set. Didn't really help me much.

(apologize if it may look like there is a relation between the sprites in the screenshot, it is only because each sprite was based on the previous)

By ro

Scribe (4258)

ro's picture

27-12-2020, 10:05

Have you seen spen5, sprite editor screen 5 by T&E? It comes on thd AGE5 disk.

By ray2day

Hero (598)

ray2day's picture

27-12-2020, 11:30

I alway use this (online) sprite editor;
http://msx.jannone.org/tinysprite/tinysprite.html

I know it handels multi color sprites. Altough I am not sure if it handles muliti line screen 2 sprites..

By Daemos

Paragon (1748)

Daemos's picture

27-12-2020, 11:41

I always edit sprites in Gimp. I save the sprites in bmp files with custom indexed color info. Created a tool to rapidly convert the spritemaps. This saves me a lot of work when working on large animated sprites. or color is sorted out by the tool if you did it right and if you did it wrong it tells you where you screwed up.

//sprite converter for command line use. Trow in a sc5 file and get blocks of sprites for use with SMW or other code
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

void process(istream& in, string filename, int blockcount, int xoffset, int yoffset, int spritewidth, int massconvert, bool fflag)
{
    

      
    
    
//skip first 7 bytes cause they contain some header bullshit
    in.get();
    in.get();
    in.get();
    in.get();
    in.get();
    in.get();
    in.get();
    
//TODO: add eof read and error if file is somewhat corrupted or incorrect a segmentation fuck out would look ugly. Perhaps read the header and fuck out from there??    
//read all data from file
    vector < vector < int > > bitmap;
    for (int y = 0; y < 192; y++)
    {
        vector < int > line;
        for (int x = 0; x < 128; x++)
            {
                int value = in.get();
                line.push_back(value >> 4);
                line.push_back(value & 0xF);
            }
        bitmap.push_back(line);
    }

    
        int countmassconvert = 0;
        ofstream out;
        ofstream outc;
        int zero = xoffset;
    
while (massconvert != 0)
{    

          //number the next files
        string str = to_string(countmassconvert);
     if (countmassconvert > 0)
     {
        if (countmassconvert != 1)
        {    
        filename.pop_back();         
        }
        filename.append(str); 
     }
        
//file to write to? then create files and make them ready to be opened when needed    
      //generate output filename and properly set its extension      
        string patternoutput = filename;
        patternoutput.append(".tgs.gen");
        string coloroutput = filename;
        coloroutput.append(".tcs.gen");      
 

//open the files for output        
    out.open(patternoutput);
    outc.open(coloroutput); 
   
    
    
    array  colors; //sprite color tables. too largely defined just in case alot of colors are used. Besides with gigabytes of RAM at our disposal nowadays..
    array  patterns; //make huge array here just in case things go wrong
    patterns.fill(0);
    colors.fill(0);
    
    
//fetch as many sprite blocks as given
for (int loop = 0; loop < blockcount; loop++)
{
 
    int bkgcount = 0; //count amount of $FF found in each line.
    bool noorcolor = false; //invalid or color found. output multiple sprites   
    int maxcolors = 0; //determine maxcolors to use with arrays

    
//fetch a 16x16 spriteblock. This one contains 2 sprites  
    
                   
               
  
  //fetch maximum amount of colors for the entire spriteblock
  for (int y = 0; y < 16; y++)
  {
                array  color;
                color.fill(0);
                int orcolor = 0; //the valid or color for the particular line

                
  for (int x = 0; x < 16; x++)
   {
       
        if (bitmap[y + yoffset][x + xoffset] == 15)
        {
            bkgcount++; //count the amount of bkgcolors found
        }
 
//fetch color info do not take action if the color = 0

          //count amount of colors.
           for (int c = 0; c < 16; c++)
           {
            if (color[c] == bitmap[y + yoffset][x + xoffset])
                   {
                    break;
                   }
               if (color[c] == 0 && color[c] != bitmap[y + yoffset][x + xoffset] && bitmap[y + yoffset][x + xoffset] != 0)
               {
                   color[c] = bitmap[y + yoffset][x + xoffset];
                   if (maxcolors < c + 1)
                   {
                   maxcolors = c + 1;
                   }
                   break;
               }
           }      


 //get or color status of sprite and set booleans accordingly 
    if (color[3] != 0)
   {
       noorcolor = true; //sprite contains or color conflicts or too many colors on on line
   }
   //find valid or colors by performing a or operation on the colors 1,2 2,3 1,3 and match the or color. After each or operation one color is bound to come out
   else if (color[2] != 0)
    {

       int bits[3]; //do or operation on all possible color combination and find match
       bits[0] = color[0] | color[1];
        if (bits[0] == color [0] || bits[0] == color[1])
        {
            bits[0] = 0; //result is same as input ignore
        }
       bits[1] = color[1] | color[2];
        if (bits[1] == color [1] || bits[0] == color[2])
        {
            bits[1] = 0; //result is same as input ignore
        }       
       bits[2] = color[0] | color[2];
        if (bits[2] == color [0] || bits[0] == color[2])
        {
            bits[2] = 0; //result is same as input ignore
        }       

       
    //now loop through each color and try to find a match
       for (int b = 0; b < 3; b++)
       {
           
           
           
       for (int c = 0; c < 3; c++)
       {

           if (bits[b] == color[c] && color[c] != 0)
           {  
               goto done;
           }
           
           
           
       }
       
       }
               
     
        noorcolor = true; //this one sets the whole converter in multiple sprite mode for this sprite block
        
        
    }           
           
           
           
           
           
           
           
           
       }
         done:
        int expression; //bullshit expresion to make label work (compiler problems)

  }
  

  if (bkgcount > 255) //this block looks empty skip all data from this block
  {
      goto skipall;
  }
  
  
    
  for (int y = 0; y < 16; y++)
  {
      
               array  color; //increase array size. You know that sprites can have ridicoulus amount of sprite colors a maximum of 16 to be exact
               array  colorbits;
               array  validcolor; //if or color found and present fetch valid colors that are not the or color
//               array  patterns; //sprite pattern data after or color extraction etc. defined at start of entire block loop
               colorbits.fill(0);
               color.fill(0);
               validcolor.fill(0);
               bool badorcolor = false; //invalid or color found tell the user that things are going wrong
               int orcolor = 0; //the valid or color for the particular line

               
               
   for (int x = 0; x < 16; x++)
   {
       

 
//fetch color info do not take action if the color = 0

          //count amount of colors.
           for (int c = 0; c < 16; c++)
           {
            if (color[c] == bitmap[y + yoffset][x + xoffset])
                   {
                    break;
                   }
               if (color[c] == 0 && color[c] != bitmap[y + yoffset][x + xoffset] && bitmap[y + yoffset][x + xoffset] != 0)
               {
                   color[c] = bitmap[y + yoffset][x + xoffset];
                   break;
               }
           }      
        
        
        colorbits[x] = bitmap[y + yoffset][x + xoffset]; //store result in array
       }

    


 //fetch color info and output warnings or info on the or color status  
    if (color[3] != 0)
   {
       cerr << " <---\nWARNING: or color conflict. Your sprite will contain more sprites than the usual 2 per block\n";
    //   noorcolor = true; //sprite contains or color conflicts or too many colors on on line
   }
   //find valid or colors by performing a or operation on the colors 1,2 2,3 1,3 and match the or color. After each or operation one color is bound to come out
   else if (color[2] != 0)
    {

       int bits[3]; //do or operation on all possible color combination and find match
       bits[0] = color[0] | color[1];
        if (bits[0] == color [0] || bits[0] == color[1])
        {
            bits[0] = 0; //result is same as input ignore
        }
       bits[1] = color[1] | color[2];
        if (bits[1] == color [1] || bits[0] == color[2])
        {
            bits[1] = 0; //result is same as input ignore
        }       
       bits[2] = color[0] | color[2];
        if (bits[2] == color [0] || bits[0] == color[2])
        {
            bits[2] = 0; //result is same as input ignore
        }       

       
    //now loop through each color and try to find a match
       for (int b = 0; b < 3; b++)
       {
           
           
           
       for (int c = 0; c < 3; c++)
       {

           if (bits[b] == color[c] && color[c] != 0)
           {

               orcolor = bits[b]; //we now have the valid or color
               
               //get the rest of the colors and put them in a small array
               int validc = 0;
               for (int i = 0; i < 3; i++)
               {
                   if (orcolor != color[i])
                   {
                       validcolor[validc] = color[i];
                       validc++;
                       
                   }
               }
               
               
               
               goto complete;
           }
           
           
           
       }
       
       }
               
        
   //     noorcolor = true; //this one sets the whole converter in multiple sprite mode for this sprite block
        badorcolor = true; //only used for warnings
        
        
        
    }
    
   complete:
   cout << "\n";
    
   //output the patterns  now that we have the correct or colors and thus spritecount or color sprites only
   
if (noorcolor == false)
{
   
  for (int spr = 0; spr < 2; spr++)
  {  
  
      
      //write color table per line
      if (orcolor != 0)
      {           
          colors[y + (16 * spr)] = validcolor[spr];
      }
      else
      {
          colors[y + (16 * spr)] = color[spr];          
      }
      
      
      
      
      int spritepatternline = 0;
  
    for (int i = 0; i < 16; i++)
    {
     
        
        if (orcolor != 0 && orcolor == colorbits[i])
        {
            cerr << "1";
            spritepatternline |= 1 << (15 - i); 
        }
        else if (orcolor != 0 && orcolor != colorbits[i] && colorbits[i] != validcolor[spr])
        {
            cerr << "0";
        }
        else if (orcolor != 0 && orcolor != colorbits[i] && colorbits[i] == validcolor[spr])
        {
            cerr << "1";
            spritepatternline |= 1 << (15 - i);             
        }
        //handle non or color
        else if (orcolor == 0 && colorbits[i] == color[spr] && colorbits[i] != 0)
        {
            cerr << "1";
            spritepatternline |= 1 << (15 - i);             
        }
        else if (orcolor == 0 && colorbits[i] == color[spr] && colorbits[i] == 0)
        {
            cerr << "0";
        }        
        else if (orcolor == 0 && colorbits[i] != color[spr])
        {
            cerr << "0";
        }
        
        

    }
    
    patterns[y + (spr*16)] = spritepatternline; //push created sprite data into memory
    
  }
  
  
  maxcolors = 2; //set maxcolors to 2 for the sprite output loop
  
  
}  //end of or color loop
//no or color was found so use this loop
else 
{
   
  for (int spr = 0; spr < maxcolors; spr++)
  {  

    colors[y + (16 * spr)] = color[spr];   //write colors per line to array    
      int spritepatternline = 0;     
  
    for (int i = 0; i < 16; i++)
    {
    
        if (color[spr] == colorbits[i] && colorbits[i] != 0)
        {
            cerr << "1";
            spritepatternline |= 1 << (15 - i);             
        }
        else
        {
            cerr << "0";
        }

    }
    
       patterns[y + (spr*16)] = spritepatternline; //push created sprite data into memory 
    
    
  }
  
}    
    
  
  
//output warnings to terminal
    if (orcolor != 0)
    {
            cerr << " <-- has valid OR color"; //or color was found and valid
    }
    else if (badorcolor == true)
    {
            cerr << " <-- has INvalid OR color!"; //or color was found and invalid
    }
    
   
   
   
   
  } //end of y loop

  
  
  if (noorcolor == true)
  {
      cerr << "\n\nSpritemode set to multiple sprites for spriteblock because of invalid/impossible color combination\n";
  }
  else
  {
      cerr << "\n\nSpritemode set to OR color mode, all or colors are valid for this pallete\n";
  }

  
  
if (fflag == true)
{
  
//open files for output and give them correct extensions
    
    

    
for (int s = 0; s < maxcolors; s++)
{    
    
    out << ";sprite pattern " << s << "\n\n";
   for (int i = 0 + (s * 16); i < 16 + (s * 16); i++)
   {
       out << "db " << (patterns[i] >> 8) << "\n";
   }
   for (int i = 0 + (s * 16); i < 16 + (s * 16); i++)
   {
       out << "db " << (patterns[i] & 255) << "\n";
   }
   
       out << "\n";       
}
 


 //write color lines
for (int s = 0; s < maxcolors; s++)
{    
       
    outc << ";sprite color lines " << s << "\n\n";   
    for (int i = 0 + (s * 16); i < 16 + (s * 16); i++)
    {
        if (i > 15 && noorcolor == false)
        {
            outc << "db " << colors[i] + 64 << "\n";            
        }
        else
        {
            outc << "db " << colors[i] << "\n";
        }
    }
    
    outc << "\n";
}       
 
} 
 
 
    skipall:
    
    //set new offsets for next part of loop
        xoffset = xoffset + 16;
        if (xoffset - zero >= spritewidth*16)
        {
            if (yoffset > 10*16) //fuck out as we are going out of boundaries
            {
                break;
            }
            yoffset = yoffset + 16;
            xoffset = zero;
        }
  
  
} //end of fetchloop

    yoffset = 0; // reset yoffset number
    massconvert--;
    countmassconvert++;

    zero = zero + (spritewidth*16);
    xoffset = zero;
    
 //close the files
    out.close();
    outc.close();
    
    
    
    cout << "\n"; //just for nice exit can be moved down later


}//end off massconvert
    
    
} //end of entire process






int main(int argc, char* argv[])
{ 

    int xoffset = 0; //for bitmap x * y access
    int yoffset = 0;
    int blockcount = 192; //read all blocks by default
    int spritewidth = 16; //maximum width of the spriteblock in full 16x16 blocks
    int massconvert = 1; //massconvert entire spriteblocks
    bool fflag = false; //convert to file? or just show the sprite in the terminal with color warnings and errors
    string filename;
    
  if (argc < 2)
  {
      cerr << "Kickass multiplatform open source even working on ARM machines sprite converter\nUsage:" << argv[0] << " inputfile.sc5 [parameters]\n";
      cerr << "parameters:\n\n-o = offset to start 0 [default]. Empty sprites are not converterd. Will read the entire file.\n-b = amount of blocks to be read. read all blocks [default]\n-w = maximum sprite width 192 [default]\n-f = base filename, no output, only text [default] will automaticly number output files when doing multiconvert.\n-m = mass convert sprites. 1 [default]\n\nPlease note that output files are overwritten without warning!\n\n";
      return 0;
  }

  if (argv[2])
  {
    for (int i = 1; i < argc; i++)
    {
      
      
      
        std::string arg1(argv[i]); 
  
     if (argv[i+1]) //check if this exsists   
     {  
         
      if (arg1.compare("-b") == 0 && atoi(argv[i + 1]) != 0)  
      {
          cerr << "counting " << argv[i + 1] << " spriteblocks\n";
          blockcount = stoi(argv[i + 1]);
      }
      if (arg1.compare("-o") == 0 && atoi(argv[i + 1]) != 0) 
      {
          cerr << "starting from position " << argv[i + 1] << "\n";
            int xarg = stoi(argv[i + 1]);
          blockcount = blockcount - xoffset;
          for (int i = 0; i < xarg; i++)
          {
                    xoffset = xoffset + 16;
                    if (xoffset > 15*16)
                        {
                            yoffset = yoffset + 16;
                            xoffset = 0;
                        }  
          }
          
          
      }
      if (arg1.compare("-w") == 0 && atoi(argv[i + 1]) != 0) 
      {
          cerr << "setting spritewidth to " << argv[i + 1] << "\n";
          spritewidth = stoi(argv[i + 1]);
      }
      if (arg1.compare("-m") == 0 && atoi(argv[i + 1]) != 0) 
      {
          cerr << "massconvert mode enabled: converting " << argv[i + 1] << " sprites\n";
          massconvert = stoi(argv[i + 1]);
      }      
      if (arg1.compare("-f") == 0) 
      {
                            std::string arg2(argv[i + 1]);
          cerr << "outputting to file " << arg2 << "\n";
          filename = arg2;
          fflag = true;
      } 
      
      
      
    }
    }
          
  }

  
  
  ifstream fin;
//  ofstream fout;
//  ofstream fout2;
  fin.open(argv[1]);
    if (!fin)
    {
        cerr << "ERROR: the file you have specified does not exsist!\n";
        return 0;
    }
  
//  fout.open(argv[2]);

  process(fin, filename, blockcount, xoffset, yoffset, spritewidth, massconvert, fflag);

  fin.close();
//  fout.close();

  return 0;
 
  
}

By santiontanon

Paragon (1138)

santiontanon's picture

27-12-2020, 17:14

+1 for editing sprites on GIMP + using a script to convert/process all you need.

This is the most powerful way I have found over the years. Sprite editors/etc. are cute, but nothing beats the flexibility of a full-blown graphic editing software plus the power of scripts to transform your image data in whichever ways you want.

By thegeps

Hero (638)

thegeps's picture

27-12-2020, 22:51

Maybe who already has coded gfx conversion tools could share them (hopefully with some documentation too) so community productivity would increase greatly. It would be really appreciated. I spent a lot of time because the lack of tools. Actually I use Magellan to draw tiles and sprites, and have to manually add data to my sources...

Page 1/3
| 2 | 3