Fix renderer so it can render partial characters at borders.

Try to make the code a bit clearer by encapsulating the coordinate transform stuff more clearly.
This commit is contained in:
Stefan `Sec` Zehl 2011-07-17 16:49:14 +02:00
parent f98c33d49b
commit db4d929b2a
1 changed files with 109 additions and 85 deletions

View File

@ -10,133 +10,157 @@ char font_direction = FONT_DIR_LTR;
/* Exported Functions */ /* Exported Functions */
int DoChar(int sx, int sy, int c){ int DoChar(int sx, int sy, int c){
int x=0;
/* how many bytes is it high? */ /* how many bytes is it high? */
char height=(font->u8Height-1)/8+1; char height=(font->u8Height-1)/8+1;
char hoff=(8-(font->u8Height%8))%8;
const uint8_t * data; const uint8_t * data;
int width,preblank=0,postblank=0;
do { /* Get Character data */
/* Does this font provide this character? */
if(c<font->u8FirstChar)
c=font->u8FirstChar+1; // error
if(c>font->u8LastChar && font->charExtra == NULL)
c=font->u8FirstChar+1; // error
if(c>font->u8LastChar && font->charExtra != NULL){
int cc=0;
while( font->charExtra[cc] < c)
cc++;
if(font->charExtra[cc] > c)
c=font->u8FirstChar+1; // error
else
c=font->u8LastChar+cc+1;
};
/* starting offset into character source data */
int toff=0;
if(font->u8Width==0){
for(int y=0;y<c-font->u8FirstChar;y++)
toff+=font->charInfo[y].widthBits;
width=font->charInfo[c-font->u8FirstChar].widthBits;
toff*=height;
data=&font->au8FontTable[toff];
postblank=1;
}else if(font->u8Width==1){ // NEW CODE
// Find offset and length for our character
for(int y=0;y<c-font->u8FirstChar;y++)
toff+=font->charInfo[y].widthBits;
width=font->charInfo[c-font->u8FirstChar].widthBits;
if(font->au8FontTable[toff]>>4 == 15){ // It's a raw character!
preblank = font->au8FontTable[toff+1];
postblank= font->au8FontTable[toff+2];
data=&font->au8FontTable[toff+3];
width=(width-3/height);
}else{
data=pk_decode(&font->au8FontTable[toff],&width);
}
}else{
toff=(c-font->u8FirstChar)*font->u8Width*height;
width=font->u8Width;
data=&font->au8FontTable[toff];
};
}while(0);
/* "real" coordinates. Our physical display is upside down */ /* "real" coordinates. Our physical display is upside down */
int rx=RESX-sx-1; #define xy_(x,yb) ( ( (RESY_B-1) -(yb)) * RESX + \
int ry=RESY-sy-font->u8Height; ( (RESX-1) -( x)) )
/* Does this font provide this character? */ int x=0;
if(c<font->u8FirstChar)
c=font->u8FirstChar+1; // error
if(c>font->u8LastChar && font->charExtra == NULL)
c=font->u8FirstChar+1; // error
if(c>font->u8LastChar && font->charExtra != NULL){
int cc=0;
while( font->charExtra[cc] < c)
cc++;
if(font->charExtra[cc] > c)
c=font->u8FirstChar+1; // error
else
c=font->u8LastChar+cc+1;
};
/* starting offset into character source data */
int toff=0,width,preblank=0,blank=0;
if(font->u8Width==0){
for(int y=0;y<c-font->u8FirstChar;y++)
toff+=font->charInfo[y].widthBits;
width=font->charInfo[c-font->u8FirstChar].widthBits;
toff*=height;
data=&font->au8FontTable[toff];
blank=1;
}else if(font->u8Width==1){ // NEW CODE
// Find offset and length for our character
for(int y=0;y<c-font->u8FirstChar;y++)
toff+=font->charInfo[y].widthBits;
width=font->charInfo[c-font->u8FirstChar].widthBits;
if(font->au8FontTable[toff]>>4 == 15){ // It's a raw character!
preblank = font->au8FontTable[toff+1];
blank= font->au8FontTable[toff+2];
data=&font->au8FontTable[toff+3];
width=(width-3/height);
}else{
data=pk_decode(&font->au8FontTable[toff],&width);
}
}else{
toff=(c-font->u8FirstChar)*font->u8Width*height;
width=font->u8Width;
data=&font->au8FontTable[toff];
};
// boundary sanity checks
if(sx<0 || sy<0 || sx >= RESX || (sy+font->u8Height) >= RESY)
return sx; // nothing printed.
/* raw character data */ /* raw character data */
int byte; int byte;
unsigned char mask; unsigned char mask;
/* print forward or backward? */ /* Our display height is non-integer. Adjust for that. */
int dmul=0; sy+=RESY%8;
if(font_direction==FONT_DIR_RTL){
dmul=1; /* Fonts may not be byte-aligned, shift up so the top matches */
if(sx-(width+preblank+blank)<=0) // sanity check for left side sy-=hoff;
return sx;
} else if (font_direction==FONT_DIR_LTR){
dmul=-1;
if(sx+(width+preblank+blank)>=RESX) // sanity check for right side
return sx;
};
/* break down the position on byte boundaries */ /* break down the position on byte boundaries */
char yidx=ry/8; signed int yidx=sy/8;
char yoff=ry%8; signed int yoff=sy%8;
rx+=dmul*preblank; if(yoff<0) { /* % operator is stupid on negative values */
yoff+=8;
yidx-=1;
};
sx+=preblank;
/* multiple 8-bit-lines */ /* multiple 8-bit-lines */
for(int y=0;y<=height;y++){ for(int y=0;y<=height;y++){
if(yidx+y<0)
continue;
if(yidx+y>=RESY_B)
continue;
// Number of bits we need to do in this line:
int m=yoff+font->u8Height-8*y; int m=yoff+font->u8Height-8*y;
m=yoff+height*8-y*8;
if(m>8)m=8; if(m>8)m=8;
if(m<0)m=0; if(m<0)m=0;
mask=255<<(8-m); mask=255>>(8-m); // Generate bitmask
/* Empty space at top is not to be masked, we consider it
not to be part of the font */
if(y==0){ if(y==0){
mask=mask>>yoff; mask=mask<<(yoff+hoff);
}; }else if(y==1 && yoff+hoff>8){
mask=mask<<(yoff+hoff-8);
};
if(mask==0) // Optimize :-) if(mask==0) // Optimize :-)
break; continue;
if(font_direction==FONT_DIR_LTR) flip(mask);
flip(mask);
for(int m=1;m<=preblank;m++){ /* Optional: empty space to the left */
lcdBuffer[(rx-dmul*(m))+(yidx+y)*RESX]&=~mask; for(int b=1;b<=preblank;b++){
if(sx-b<0)
continue;
if(sx-b>=RESX)
continue;
lcdBuffer[xy_(sx-b,yidx+y)]&=~mask;
}; };
/* Render character */
for(x=0;x<width;x++){ for(x=0;x<width;x++){
unsigned char b1,b2; unsigned char b1,b2;
if(y==0) if(y==0)
b1=0; b1=0;
else else
b1=data[x*height+y-1]; b1=data[x*height+(height-1)-(y-1)];
if(y==height) if(y==height)
b2=0; b2=0;
else else
b2=data[x*height+y]; b2=data[x*height+(height-1)-(y)];
byte= (b1<<(8-yoff)) | (b2>>yoff); byte= (b1>>(8-yoff)) | (b2<<yoff);
if(font_direction==FONT_DIR_LTR) flip(byte);
flip(byte);
lcdBuffer[(rx+dmul*x)+(yidx+y)*RESX]&=~mask; if(sx+x<0)
lcdBuffer[(rx+dmul*x)+(yidx+y)*RESX]|=byte; continue;
if(sx+x>=RESX)
continue;
lcdBuffer[xy_(sx+x,yidx+y)]&=~mask;
lcdBuffer[xy_(sx+x,yidx+y)]|=byte;
}; };
for(int m=0;m<blank;m++){ /* Optional: empty space to the right */
lcdBuffer[(rx+dmul*(x+m))+(yidx+y)*RESX]&=~mask; for(int m=0;m<postblank;m++){
if(sx+x+m<0)
continue;
if(sx+x+m>=RESX)
continue;
lcdBuffer[xy_(sx+x+m,yidx+y)]&=~mask;
}; };
}; };
return sx-dmul*(x+preblank+blank); return sx+(width+postblank);
}; };
#define UTF8 #define UTF8