my fixed file routines:

Code:
#define close_file(handle) Bfile_CloseFile_OS(handle)
typedef int file;

file make_file(char*name, int size) {
    unsigned char*n = malloc(256*sizeof(unsigned short));
    unsigned short*n2 = malloc(strlen(name)+7*sizeof(char));
    *(sizeof(char)*7+strlen(name)+n+1) = 0x00;
    memcpy(n, "\\\\fls0\\", 7*sizeof(char));
    memcpy(sizeof(char)*7+n, name, strlen(name));
    Bfile_StrToName_ncpy(n2, n, strlen((char*)n));
    free(n);
    name = (char*) n2;
    free(n2);
    Bfile_CreateEntry_OS(n2, 0x1, &size);
    return Bfile_OpenFile_OS(n2, 0x3);
}

void*read_file(file handle, int size, int offset) {
    static char*buf;
   buf = malloc(size);
    Bfile_ReadFile_OS(handle, buf, size, offset);
    return buf;
}

void write_file(file handle, int size, int offset, void*data) {
    char*buffer = malloc(size+offset);
    memcpy(buffer, read_file(handle, offset, 0), offset);
    memcpy(buffer+offset, data, size);
    Bfile_WriteFile_OS(handle, buffer, size+offset);
    free(buffer);
}

int file_exists(char*name) {
    unsigned char*n = malloc(256*sizeof(unsigned short));
    unsigned short*n2 = malloc(strlen(name)+7*sizeof(char));
    *(sizeof(char)*7+strlen(name)+n+1) = 0x00;
    memcpy(n, "\\\\fls0\\", 7*sizeof(char));
    memcpy(sizeof(char)*7+n, name, strlen(name));
    Bfile_StrToName_ncpy(n2, n, strlen((char*)n));
    free(n);
    name = (char*) n2;
    free(n2);
    file exists = Bfile_OpenFile_OS(n2, 0x3);
    close_file(exists);
    return (exists>=0);
}

int strlen(char*a) {
   int c = 0;
   while(*(a+c)) { c++; }
   return c;
}
Ashbad wrote:

Code:
void*read_file(file handle, int size, int offset) {
    static char*buf;
   buf = malloc(size);
    Bfile_ReadFile_OS(handle, buf, size, offset);
    return buf;
}

void write_file(file handle, int size, int offset, void*data) {
    char*buffer = malloc(size+offset);
    memcpy(buffer, read_file(handle, offset, 0), offset);
    memcpy(buffer+offset, data, size);
    Bfile_WriteFile_OS(handle, buffer, size+offset);
    free(buffer);
}

Holy leaky functions, batman! Smile
write_file doesn't free the memory allocated by read_file, and the pointer to the memory isn't saved anywhere to free it later. Does the Bfile_WriteFile_OS function/syscall really require the programmer to rewrite the entire beginning contents of the file even to write a single byte somewhere in the middle of the file? I would think that the syscall would keep track of the current write position like fwrite and write (the POSIX system interface). In fact the prototype looks practically the same as for write:

Code:
ssize_t write(int filed, void *buf, size_t count);

Of course, I could be wrong, and it might be a braindead syscall after all.
christop wrote:

Holy leaky functions, batman! Smile


Yep, I typed them one night at Catherine's request on my iPad in about 5 minutes, so they were bound to be criticized for that Razz


Quote:
Does the Bfile_WriteFile_OS function/syscall really require the programmer to rewrite the entire beginning contents of the file even to write a single byte somewhere in the middle of the file? I would think that the syscall would keep track of the current write position like fwrite and write (the POSIX system interface). In fact the prototype looks practically the same as for write:
Code:
ssize_t write(int filed, void *buf, size_t count);

Of course, I could be wrong, and it might be a braindead syscall after all.


Yep, the syscalls really are that horribly brain-dead, unfortunately Sad
Ashbad wrote:
Quote:
Does the Bfile_WriteFile_OS function/syscall really require the programmer to rewrite the entire beginning contents of the file even to write a single byte somewhere in the middle of the file? I would think that the syscall would keep track of the current write position like fwrite and write (the POSIX system interface). In fact the prototype looks practically the same as for write:
Code:
ssize_t write(int filed, void *buf, size_t count);

Of course, I could be wrong, and it might be a braindead syscall after all.


Yep, the syscalls really are that horribly brain-dead, unfortunately Sad

Interesting. I just read some of the official SDK documentation (found at http://prizmwiki.omnimaga.org/wiki/Tools#Official_Casio_SDK), and here's what it says about Bfile_WriteFile:
Quote:
The Bfile_WriteFile function writes data to a file. The function starts writing data to the file at the position
indicated by the file pointer. After the write operation has been completed, the file pointer is adjusted by the
number of bytes actually written.
...
Return Values
If the function succeeds, this function returns the position indicated by the file pointer. It is greater than or equal to
0.
If the function fails, the return value is an error code. It is a negative value.

So it seems to me that it does keep track of the current file position.

Since (on the Prizm) int is the same size as long (and therefore the same size as size_t and ssize_t), you can almost use this syscall as a drop-in replacement for the standard write syscall. The only difference is the return value. write returns the number of bytes written, whereas Bfile_WriteFile returns the file position. Here's a possible wrapper to get more or less the same functionality as write:

Code:
ssize_t write(int fd, const void *buf, size_t count)
{
    int pos1 = Bfile_WriteFile(fd, NULL, 0); // get the current position
    int pos2 = Bfile_WriteFile(fd, buf, count);
    if (pos2 < 0) {
        // this should also set errno
        return -1;
    }
    return pos2 - pos1;
}

// just for kicks, here's read:
ssize_t read(int fd, const void *buf, size_t count)
{
    int n = Bfile_ReadFile(fd, buf, count);
    // Bfile_ReadFile returns the number of bytes read
    // which is inconsistent with Bfile_WriteFile. Silly Casio!
    if (n < 0) {
        // this should also set errno
        return -1;
    }
    return n;
}

From there it should be fairly straightforward to implement or port a stdio using write and read. Unfortunately, it might be a challenge to implement lseek (on which fseek depends) as the Bfile_SeekFile syscall is limited in how it moves the file position. The documentation isn't even clear on how it does move the file position either (ie, is it absolute or relative to the current position?). It may be necessary to keep track of the file position in stdio in order to properly support lseek/fseek, but this is lame because it violates the Don't Repeat Yourself (DRY) principle.

EDIT: It might not be necessary to keep track of the file position in stdio after all:

Code:
off_t lseek(int fildes, off_t offset, int whence)
{
    switch (whence) {
    case SEEK_SET:
        break;
    case SEEK_CUR:
        offset += Bfile_WriteFile(fd, NULL, 0); // add current offset
        break;
    case SEEK_END:
        offset += Bfile_GetFileSize(fd); // add file size
        break;
    default:
        return -1;
    }
    if (offset < 0) {
        return -1;
    }
    Bfile_SeekFile(fd, offset);
    return offset;
}

(This code does little error checking and assumes that Bfile_SeekFile sets the file position absolutely).
Well, I'm unsure if anyone's shared it yet, but here's the optimized version of Kerm's two sprite routines:


Code:
void CopySprite(const void* datar, int x, int y, int width, int height) {
   color_t*data = (color_t*) datar;
   color_t* VRAM = (color_t*)0xA8000000;
   VRAM += LCD_WIDTH_PX*y + x;
   for(int j=y; j<y+height; j++) {
      for(int i=x; i<x+width; i++) {
         *(VRAM++) = *(data++);
     }
     VRAM += LCD_WIDTH_PX-width;
   }
}

void CopySpriteMasked(const void*datar, int x, int y, int width, int height, int maskcolor) {
   color_t*data = (color_t*) datar;
   color_t* VRAM = (color_t*)0xA8000000;
   VRAM += LCD_WIDTH_PX*y + x;
   for(int j=y; j<y+height; j++) {
      for(int i=x; i<x+width;  i++) {
         if (*(data) != maskcolor) {
            *(VRAM++) = *(data++);
         } else { VRAM++; data++; }
      }
      VRAM += LCD_WIDTH_PX-width;
   }
}


Same as the original, but faster (literally, the only optimization done is moving by halfwords instead of bytes).

And, for a simple routine that clears the screen to any given color, very very fast, here's this that I use (a lot faster than all of the syscalls that do similar or the same):


Code:
void fill_scr(color_t color) {
        unsigned int temp_color = (unsigned int)(color<<16) | color;
   for(int i = 0; i < LCD_WIDTH_PX*LCD_HEIGHT_PX/2; i++) {
      *((int*)0xA8000000+i) = temp_color;
   }
}
Very nice. Is "maskcolor" the same as transparency?
merthsoft wrote:
Very nice. Is "maskcolor" the same as transparency?


Well, don't give me much credit, they're just modifying Kerm's routines Razz and yes, maskcolor is the transparency color.
We need to get these all on the wiki one of these days. Smile Ashbad, speak to me at some point about this if you'd be willing to help me organize them onto it.
KermMartian wrote:
We need to get these all on the wiki one of these days. Smile Ashbad, speak to me at some point about this if you'd be willing to help me organize them onto it.


Okay, sounds good Smile just PM some link to this wiki, and I can start adding my stuff to it.
I think I should publish my routines...
Where is my HDD?...
/me goes to sleep, then 'll think to publish him routines, there are a lot of useful graphics functions!
Eiyeron, that's great! Be sure to do so, and I'll have to give you a wiki link too. Ashbad, check your PMS.
CopySpriteMaskedAlpha: takes the same params as CopySpriteMasked, but with an alpha transparency channel between 0-31.


Code:
void CopySpriteMaskedAlpha(const void*datar, int x, int y, int width, int height, int maskcolor, int alpha) {
   color_t*data = (color_t*) datar;
   color_t* VRAM = (color_t*)0xA8000000;
   VRAM += LCD_WIDTH_PX*y + x;
   alpha %= 32;
   for(int j=y; j<y+height; j++) {
      for(int i=x; i<x+width;  i++) {
         if (*(data) != maskcolor) {
         *(VRAM) = (color_t)((((int)(*data & 0xf81f) * alpha + (int)(*VRAM & 0xf81f) * (32-alpha) + 0x8010) >> 5) & 0xf81f) |
                (color_t)((((int)(*data & 0x07e0) * alpha + (int)(*VRAM & 0x07e0) * (32-alpha) + 0x0400) >> 6) & 0x07e0);
           VRAM++; data++;
         } else { VRAM++; data++; }
      }
      VRAM += LCD_WIDTH_PX-width;
   }
}
Awesome! Sounds like I need to get you to add the ability for SourceCoder to generate this format, or just do it myself.
KermMartian wrote:
Awesome! Sounds like I need to get you to add the ability for SourceCoder to generate this format, or just do it myself.


Well, actually, this routine doesn't take a built-in channel Sad (edit: the whole image is taken as opaque and masked, and then the entire thing is alpha blended at the same level, which is given as a paramter) but because you prompted, I just whipped together a new format (RGBAX 56553, where X, for those few who don't know, is unused by the routine and can be used for something entirely else if wanted -- in this case, it's only 3 bits large per pixel) that uses a new type color_t_rgbax, which is 24 bits large instead of the original 565 color_t which is 16 bits. *Now* there's something to add to SC2.5 Smile


Code:
typedef struct {
   union {
      unsigned int : 24;
      struct {
         unsigned int r : 5;
         unsigned int g : 6;
         unsigned int b : 5;
         unsigned int a : 5;
         unsigned int x : 3;
      };
   };
} color_t_rgbax;

void CopySpriteMasked5655(const void*datar, int x, int y, int width, int height, int maskcolor) {
   color_t_rgbax*data = (color_t*) datar;
   color_t* VRAM = (color_t*)0xA8000000;
   VRAM += LCD_WIDTH_PX*y + x;
   for(int j=y; j<y+height; j++) {
      for(int i=x; i<x+width;  i++) {
         if ((color_t)*(data) != maskcolor) {
         int alpha = *data & 0x0000F8;
         *(VRAM) = (color_t)((((int)((*data>>8) & 0xf81f) * alpha + (int)(*VRAM & 0xf81f) * (32-alpha) + 0x8010) >> 5) & 0xf81f) |
                (color_t)((((int)((*data>>8) & 0x07e0) * alpha + (int)(*VRAM & 0x07e0) * (32-alpha) + 0x0400) >> 6) & 0x07e0);
           VRAM++; data++;
         } else { VRAM++; data++; }
      }
      VRAM += LCD_WIDTH_PX-width;
   }
}


Should work, untested, but only really minor additions made to my original routine.
So, I have looked at compression on GlassOS before, but SDCC just couldn't compile the library I was using. So, the prizm has more memory, so here it is:

Basic Compression Library

It impliments
  • RLE
  • Huffman
  • LZ77
  • SF - Shannon-Fano
  • rice8/8s/16/16s/32/32s

For example, I took a 40320 byte image and compressed and uncompressed on the prizm successfully using huffman compression. The compressed size is 15789 for this particular image, 39% of the actual size! So, how do you compress? Get that archive and build the compressor for your PC. Take your raw image data and save it to a file, such as fun.raw. use ./bfc.exe c huff fun.raw fun.huff to make a compressed image with header data. Remove the first 96 bits of that file as it was added by the bfc.exe and isn't part of the compression. Done! Add that data to your source file (you can use okteta from KDE to convert the binary file to a C array).

On the calculator, you need to malloc a buffer of the same size as the uncompressed data. Use Huffman_Uncompresss(compresseddata, outbuffer, compressedsize, uncompressedsize) to get the data from it, done!

Now, using this for a large background may be useful as you would only have 1 background malloc'd at a time, and you don't have the memory for multiple malloc'd at once. Decompressing isn't lightning fast as a PC as the prizm is under 60 Hz Razz For me, decompressing is about 0.5 sec. for the 40320 image.

I know that the LZ77 method allows for much better compression ratios, but compressing on-calc isn't reasonable as the method is a brute-force compressor and can be slow, but decompression should be fine.
Is there anything that prevents you from using the VRAM or some offset thereof directly for the outbuffer? Can you (or me, of course) add an optional "step" argument to that command so that you can skip M pixels copying an SxT patch to outbuffer, allowing you to copy a patch of S<A, T<=B onto a screen buffer of AxB = (S+M)xB = 384x216 pixels to VRAM?
You can write directly to the VRAM, yes. Just have *out as the start of the VRAM and it will work. The buffer needs to be at max the size of the uncompressed data. However, if you want to do compression on files, such as if you make a game with levels, you can compress them to save on space as speed isn't an issue. Which goes back to the the VRAM. Once you decompress to the VRAM, you have to reserve it or else you must uncompress it again, taking up a lot of time.
What about the step option? Also, did you happen to upload this to the archives anyway, or is it a simple build-from-source with no modifications needed?
Just modify the uncompressor. It simply is a for loop that writes to pointer and inc's it. I didn't upload it as I just gave the url to the source Wink
Here's a function that wraps around the sys calls and stuff for printing little text:

Code:
int PrintMiniFix( int x, int y, const char*Msg, const int flags, const short color, const short bcolor ){
int i = 0, dx;
unsigned short width;
void*p;

   while ( Msg[ i ] ){
      p = GetMiniGlyphPtr( Msg[ i ], &width );
      dx = ( 12 - width ) / 2;
      if ( dx > 0 ) {
         PrintMiniGlyph( x, y, (void*)empty, flags, dx, 0, 0, 0, 0, color, bcolor, 0 );
      }else dx = 0;
      PrintMiniGlyph( x+dx, y, p, flags, width, 0, 0, 0, 0, color, bcolor, 0 );
      if ( width+dx < 12 ){
         PrintMiniGlyph( x+width+dx, y, (void*)empty, flags, 12-width-dx, 0, 0, 0, 0, color, bcolor, 0 );
      }
      x += 12;
      i++;
   }
   return x;
}

Use it like:

Code:
PrintMiniFix(0, 175,
         "Oh look a string at the bottom of the screen.",
         0, COLOR_WHITE, COLOR_BLACK);

Empty is defined as:

Code:
const short empty[18] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
» Goto page Previous  1, 2, 3 ... 5, 6, 7 ... 10, 11, 12  Next
» View previous topic :: View next topic  
Page 6 of 12
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement