Login [Register]
Don't have an account? Register now to chat, post, use our tools, and much more.
I'll start us off.

XORSprite and CopySprite
The former XORs a sprite of specified width and height to the screen. Do it twice, and the screen will return to its original state. The latter routine overwrites the data on the screen, but is (potentially) faster because it memcpys each row. Note that these routines expect the sort of data that SourceCoder outputs.


Code:
#define LCD_WIDTH_PX 384
#define LCD_HEIGHT_PX 216
void XORSprite(char* data, int x, int y, int width, int height) {
   char* VRAM = (char*)0xA8000000;
   VRAM += 2*(LCD_WIDTH_PX*y + x);
   for(int j=y; j<y+height; j++) {
      for(int i=x; i<x+width;  i++) {
         *(VRAM++) ^= *(data++);
         *(VRAM++) ^= *(data++);
      }
      VRAM += 2*(LCD_WIDTH_PX-width);
   }
}
void CopySprite(char* data, int x, int y, int width, int height) {
   char* VRAM = (char*)0xA8000000;
   VRAM += 2*(LCD_WIDTH_PX*y + x);
   for(int j=y; j<y+height; j++) {
      memcpy(VRAM,data,2*width);
      VRAM += 2*LCD_WIDTH_PX;
      data += 2*width;
   }
}
How would we copy the data to the screen? What method, I mean.
Once you have data written to the Video RAM (VRAM), the equivalent to iFastCopy is
Code:
      Bdisp_PutDisp_DD();
Until I find a better way to do it, this is how I do non-blocking key input:

Code:
if (PRGM_GetKey()) {
   GetKey(&key);
} else {
   key = 0;
}

It only kind of works, though.
Here's a suggestion from the miniSDK:


Code:
To yield the same function result as PRGM-GETKEY one could use this:

int PRGM_GetKey(){
unsigned char buffer[12];
        KBD_PRGM_GetKey( buffer );
        return ( buffer[1] & 0x0F ) * 10 + ( ( buffer[2]  & 0xF0 )  >> 4 );

}


Edit: On investigation, this is better:


Code:
int GetKey_NonBlock() {
    int key;
    key = PRGM_GetKey();
    if (key == KEY_PRGM_MENU)
        GetKey(&key);
    return key;
}
I assume that's what PRGM_GetKey() is in keyboard.hpp. Here's what I'm doing:

Code:

int lastKey, key;
while(1) {
   lastKey = key;
   key = PRGM_GetKey();
   switch (key) {
      /* ... */
      case KEY_PRGM_MENU:
         GetKey(&key);
         break;
   }
}

Last key is for stuff like my function keys, which shouldn't repeat if you hold down the button.
Based on the first post I think a routine to flip the screen horizontally and vertically would be possible. Am I right?
String concatenation:

Code:
char* concat(char* str1, char* str2) {
   int len1 = 0;
   int len2 = 0;
   for (;str1[len1] != '\0'; len1++);
   for (;str2[len2] != '\0'; len2++);

   char* str3 = (char*)malloc(len1 + len2 + 1);
   int i;
   for (i = 0; i < len1; str3[i] = str1[i], i++);
   for (i = 0; i < len2; str3[len1+i] = str2[i], i++);
   str3[len1 + len2] = 0;
   
   return str3;
}
Depending on the size of the strings, a pair of memcpy()s instead of those two for() loops at the end might be faster, but it's almost definitely a trivial difference. Therefore, I'd call that good enough.
ScoutDavid wrote:
Based on the first post I think a routine to flip the screen horizontally and vertically would be possible. Am I right?
Not only possible, but trivial. If someone wants it, I would be happy to write such a routine. Anywhere, here's a few useful routines:

DrawDialog

Code:
//Draws a DCS SmallWindow-style dialog box.  Can fit in
//text from (x,y)=(4,3) through (x,y)=(8,17)
void drawDialog(char* title) {
   #define DIALOG_WIDTH 256
   #define DIALOG_HEIGHT 152
   #define DIALOG_X 50
   #define DIALOG_Y 39
   fillArea(DIALOG_X,DIALOG_Y,DIALOG_WIDTH,DIALOG_HEIGHT,0x0000FFFF);      //fill with white
   drawLine(DIALOG_X,DIALOG_Y,DIALOG_X+DIALOG_WIDTH,DIALOG_Y,0x00000000);
   drawLine(DIALOG_X,DIALOG_Y,DIALOG_X,DIALOG_Y+DIALOG_HEIGHT,0x00000000);
   drawLine(DIALOG_X+DIALOG_WIDTH,DIALOG_Y+DIALOG_HEIGHT,DIALOG_X+DIALOG_WIDTH,DIALOG_Y,0x00000000);
   drawLine(DIALOG_X+DIALOG_WIDTH,DIALOG_Y+DIALOG_HEIGHT,DIALOG_X,DIALOG_Y+DIALOG_HEIGHT,0x00000000);
   for(int i=DIALOG_Y+1;i<DIALOG_Y+32;i++) {
      drawLine(DIALOG_X+1, i, DIALOG_X+DIALOG_WIDTH-1, i, makeGray((i-DIALOG_Y)/2));
   }
   PrintXY(4, 2, title, 0x20, 7);
   CopySprite(closebutton,DIALOG_X+DIALOG_WIDTH-30,DIALOG_Y+3,27,26);
}


MakeGray

Code:
//shade can be between 0 (black) and 31 (white)
//creates a two-byte 5/6/5 color code
int makeGray(int shade) {
   return (((shade<<11)&0x0000F800) | ((shade << 6)&0x000007C0) | ((shade)&0x0000001F));
}


DrawLine

Code:
//Uses the Bresenham line algorithm
void drawLine(int x1, int y1, int x2, int y2, int color) {
    signed char ix;
    signed char iy;
 
    // if x1 == x2 or y1 == y2, then it does not matter what we set here
    int delta_x = (x2 > x1?(ix = 1, x2 - x1):(ix = -1, x1 - x2)) << 1;
    int delta_y = (y2 > y1?(iy = 1, y2 - y1):(iy = -1, y1 - y2)) << 1;
 
   plot(x1, y1, color);
    if (delta_x >= delta_y) {
        int error = delta_y - (delta_x >> 1);        // error may go below zero
        while (x1 != x2) {
            if (error >= 0) {
                if (error || (ix > 0)) {
                    y1 += iy;
                    error -= delta_x;
                }                           // else do nothing
         }                              // else do nothing
            x1 += ix;
            error += delta_y;
            plot(x1, y1, color);
        }
    } else {
        int error = delta_x - (delta_y >> 1);      // error may go below zero
        while (y1 != y2) {
            if (error >= 0) {
                if (error || (iy > 0)) {
                    x1 += ix;
                    error -= delta_y;
                }                           // else do nothing
            }                              // else do nothing
            y1 += iy;
            error += delta_x;
            plot(x1, y1, color);
        }
    }
}


Plot

Code:
//draws a point of color color at (x0, y0)
void plot(int x0, int y0, int color) {
   char* VRAM = (char*)0xA8000000;
   VRAM += 2*(y0*LCD_WIDTH_PX + x0);
   *(VRAM++) = (color&0x0000FF00)>>8;
   *(VRAM++) = (color&0x000000FF);
   return;
}


FillArea

Code:
//fills a rectangular area of (width,height) with upper-left
//corner at (x,y) with color color
void fillArea(int x, int y, int width, int height, int color) {
   //only use lower two bytes of color
   char* VRAM = (char*)0xA8000000;
   VRAM += 2*(LCD_WIDTH_PX*y + x);
   for(int j=y; j<y+height; j++) {
      for(int i=x; i<x+width;  i++) {
         *(VRAM++) = (color&0x0000FF00)>>8;
         *(VRAM++) = (color&0x000000FF);
      }
      VRAM += 2*(LCD_WIDTH_PX-width);
   }
}
We could really put a lot of these into a libfxgc or sorts so that users can easily compile them into the main program. In fact I'd suggest we start just that. My thought would be have sets of statically linkable libs with related routines. One main one for syscalls and helper functions, another for a GUI library, maybe another with Floating point stuff etc. Thoughts?
I think that's an awesome idea. I'm also thinking strongly that if I do indeed make some kind of Doors CS port, that it will have a version of the DCS GUI system, because it would be much much easier on this. Is there a such library that will only link in the routines that the user uses?
I would think GCC would be smart enough to figure that out but I'm not sure one that.
TheStorm wrote:
I would think GCC would be smart enough to figure that out but I'm not sure one that.
To optimize out routines that aren't called from anywhere, you mean? That's a good point, I didn't even think of that. Very Happy I'm so used to working with z80 assembly where you'd have to come up with some sort of mechanism to only include the routines in a linked library that you need.
Does anyone know a routine to copy the contents of VRAM to the actual LCD?
Ashbad wrote:
Does anyone know a routine to copy the contents of VRAM to the actual LCD?
Just call Bdisp_PutDisp_DD();. For example, the code below clears the screen, copies on the Obliterate titlescreen, draws the select-item menu sprite, and copies everything to the screen. The z80 analog is iPutSprite.


Code:
      Bdisp_AllCr_VRAM();
      memcpy(VRAM,oblit_prizm_title,(384*216*2));
      CopySprite(menubullet,264,131+21*menuitem,16,16);
      Bdisp_PutDisp_DD();
This might actually be a better way to do the MakeGray routine:

Code:
//shade can be between 0 (black) and 31 (white)
//creates a two-byte 5/6/5 color code
int makeGray(int shade) {
   return shade * 0x0841;
}

since a multiplication is probably more optimized than a bunch of shifting and masking on the SuperH. If there was a way to optimize this to a 16-bit x 16-bit multiplication, that would be even better (inline assembly?)
Close, but not quite. 31 yields FFDF, for instance, rather than FFFF. Using 0x0842 instead of 0x0841 yields FFFF, which is closer, but of course it doesn't do the intermediate values properly. I suppose that's not bad if it gets decent speed, and I suppose getting the least significant bit of the green wrong is not the total end of the world.
KermMartian wrote:
Close, but not quite. 31 yields FFDF, for instance, rather than FFFF. Using 0x0842 instead of 0x0841 yields FFFF, which is closer, but of course it doesn't do the intermediate values properly. I suppose that's not bad if it gets decent speed, and I suppose getting the least significant bit of the green wrong is not the total end of the world.

I just did exactly what your routine did, so... Razz
calc84maniac wrote:
I just did exactly what your routine did, so... Razz
So you did, and I now see why that wasn't looking right to me, and also why I'm stupid. Of course the LSB of green will always be zero for gray values 0-31. :S
  
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
Page 1 of 12
» All times are GMT - 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