#include "jfont.h"

static int use_jfont_alpha=0;
static int use_jfont_gradient=0;
static int use_jfont_monochrome=0;
static float jfont_grad_R[4],jfont_grad_G[4],jfont_grad_B[4],jfont_grad_A[4]; //for text gradient - can't be bothered with structs for this...


int enable_jfont_alpha(int x){
    int tmp = use_jfont_alpha;
    use_jfont_alpha=x;
    return(tmp);

}

int enable_jfont_gradient(int x){
    int tmp = use_jfont_gradient;
    use_jfont_gradient=x;
    return(tmp);

}

int enable_jfont_monochrome(int x){
    int tmp = use_jfont_monochrome;
    use_jfont_monochrome=x;
    return(tmp);

}

void set_jfont_gradient(float R0,float G0,float B0,float A0,
                        float R1,float G1,float B1,float A1,
                        float R2,float G2,float B2,float A2,
                        float R3,float G3,float B3,float A3){
    jfont_grad_R[0]=R0;
    jfont_grad_G[0]=G0;
    jfont_grad_B[0]=B0;
    jfont_grad_A[0]=A0;
    
    jfont_grad_R[1]=R1;
    jfont_grad_G[1]=G1;
    jfont_grad_B[1]=B1;
    jfont_grad_A[1]=A1;
    
    jfont_grad_R[2]=R2;
    jfont_grad_G[2]=G2;
    jfont_grad_B[2]=B2;
    jfont_grad_A[2]=A2;
    
    jfont_grad_R[3]=R3;
    jfont_grad_G[3]=G3;
    jfont_grad_B[3]=B3;
    jfont_grad_A[3]=A3;
    
}


static int closest_power_of_2(int x){
    int a;
    for(a=2;a<x;a*=2);
    return(a);
}


void jprintf(JFONT *f, float px, float py, float pz,float scale, char *format, ...) {
    char buf[1000];
    int i;
    float x,y;
    float h;
    va_list ap;

    //get string
    va_start(ap, format);
    uvsprintf(buf, format, ap);
    va_end(ap);
		 
    glEnable(GL_TEXTURE_2D);

      
    glBindTexture(GL_TEXTURE_2D, f->texture);
    
   

    h=f->font_height;
    x=px;
    y=py;
    
    //scale to best fit for font size, need to know current frustum width and height :S 
    /*
    if(scale==-1){
        scale =  ((float)3/SCREEN_H)*h;
    
    }*/
    
    
    
    for (i=0; buf[i]!= 0; i++){
    
    
       // next line
        if(buf[i]==10){
            x=px;
            y-=scale;
            continue;
        }
        
        
        //hack for space (takes up same room as an a "1" :)
        if(buf[i]==32){
            x+=(f->glyph[17].w + f->glyph[17].px)*scale;
            continue;
        }
        
        
        buf[i]-=32;
        if(buf[i]<0)buf[i]=0;
        if(buf[i]>=96)buf[i]=0;
        
        glBegin(GL_QUADS);
          
          if(use_jfont_gradient)glColor4f(jfont_grad_R[0],jfont_grad_G[0],jfont_grad_B[0],jfont_grad_A[0]);
          glTexCoord2f(f->glyph[buf[i]].offx,f->glyph[buf[i]].offy);
          glVertex2f(x + f->glyph[buf[i]].px*scale,y + (1 - f->glyph[buf[i]].py)*scale);
     
          if(use_jfont_gradient)glColor4f(jfont_grad_R[1],jfont_grad_G[1],jfont_grad_B[1],jfont_grad_A[1]);
          glTexCoord2f(f->glyph[buf[i]].offx,f->glyph[buf[i]].offyy);
          glVertex2f(x + f->glyph[buf[i]].px*scale,y + (1 - f->glyph[buf[i]].py - f->glyph[buf[i]].h)*scale);
      
          if(use_jfont_gradient)glColor4f(jfont_grad_R[2],jfont_grad_G[2],jfont_grad_B[2],jfont_grad_A[2]);
          glTexCoord2f(f->glyph[buf[i]].offxx,f->glyph[buf[i]].offyy);
          glVertex2f(x + (f->glyph[buf[i]].w + f->glyph[buf[i]].px)*scale,y + (1 - f->glyph[buf[i]].py - f->glyph[buf[i]].h)*scale);
 
          if(use_jfont_gradient)glColor4f(jfont_grad_R[3],jfont_grad_G[3],jfont_grad_B[3],jfont_grad_A[3]);
          glTexCoord2f(f->glyph[buf[i]].offxx,f->glyph[buf[i]].offy);
          glVertex2f(x + (f->glyph[buf[i]].w + f->glyph[buf[i]].px)*scale,y + (1 - f->glyph[buf[i]].py)*scale);
      
        
        glEnd();
        
        
        
        
        x+=(f->glyph[buf[i]].w + f->glyph[buf[i]].px)*scale;
        
    }
    
}
     
                













/******** 

 IMPORTANT! - need to add support for using multiple font textures if the
                graphics card in use does not support large enough textures             
 
 For anti-aliasing, need to add variable blending gradient for larger fonts. 
 
 ********/


JFONT *create_jfont(FONT *fnt){
    int font_height = fnt->height;
    int font_width=font_height*4; // assume font width is not going to be more that 4 times the font height
    int n,i,j;
    int minx,miny,maxx,maxy;
    int btex_w,btex_h,btex_ymax;
    int dir,x,y; 
    int mono_or_col;
    JFONT *nfont = (JFONT *)malloc(sizeof(JFONT));
    BITMAP *tmp, *tmp_sub;
    short int tmp_index[96],tmpindex; //for bubble sort
    char s[2];
    
    float EDGEPIX=2; 

    
    text_mode(-1);
    
    
    /* first stage is to get he glynth heights, widths and offsets (by offset I mean that for example _ would have
        a large y offset, while ^ wouldn't) */
        
    tmp = create_bitmap(font_width,font_height);
    
    for(n=0;n<96;n++){
        clear_to_color(tmp,0); //zero bitmap
        
        s[0]=n+32; s[1]=0;  //set up simple string
        textout(tmp,fnt,s,0,0,-1); //can't be bothered to use allegro's internal character drawing funcs :p.
        
        
        for(i=0;i<font_width;i++){
            for(j=0;j<font_height;j++){
                   if(getpixel(tmp,i,j)!=0)goto found_minx;
            }
        } found_minx: minx = i-1;
        
        for(i=font_width-1;i>=0;i--){
            for(j=0;j<font_height;j++){
                   if(getpixel(tmp,i,j)!=0)goto found_maxx;
            }
        } found_maxx: maxx = i+1;
        
        for(j=0;j<font_height;j++){
            for(i=0;i<font_width;i++){
                   if(getpixel(tmp,i,j)!=0)goto found_miny;
            }
        } found_miny: miny = j-1;
    
        for(j=font_height-1;j>=0;j--){
            for(i=0;i<font_width;i++){
                   if(getpixel(tmp,i,j)!=0)goto found_maxy;
            }
        } found_maxy: maxy = j+1;
        
        //avoid any naughties.
        if(minx>maxx)minx=maxx=0;
        if(miny>maxy)miny=maxy=0;
        
        nfont->glyph[n].w=maxx-minx;
        nfont->glyph[n].h=maxy-miny;
        nfont->glyph[n].px=minx;
        nfont->glyph[n].py=miny;
        
        
    
    }
    
    destroy_bitmap(tmp);
    
    /* bubble sort glyphs into descending order of height, 96 passes isn't going to be too 
       slow (especially since this is a loading function */ 
    
    for(n=0;n<96;n++)tmp_index[n]=n;
    
    for(i=0;i<96;i++){ 
        for(n=0;n<95;n++){
            if(nfont->glyph[tmp_index[n]].h  <  nfont->glyph[tmp_index[n+1]].h){
                tmpindex=tmp_index[n];
                tmp_index[n]=tmp_index[n+1];
                tmp_index[n+1]=tmpindex;
            }
    
        }
    }
    
    //set font height to tallest character
    nfont->font_height=nfont->glyph[tmp_index[0]].h; 
    
    //get an texture length, this is the dodgey bit :S.
    btex_w = closest_power_of_2(font_height*9); //9 'cause 9 ~= sqrt(96) or something...
    
    
    
    /* unfortunately I don't know the height of texture until after I've packed it, so
       the best I can do is guess something that should be easily big enough. Note: this is only 
       for the temporary bitmap so it only temporarily wastes memory. */
    btex_h = closest_power_of_2(font_height*20); // should be more than big enough.
    
    tmp = create_bitmap(btex_w,btex_h);
    clear_to_color(tmp,0);
    
    
    //Now for the actual packing:
    
    //dir : 0 = left to right, 1 = right to left
    if(use_jfont_monochrome)mono_or_col=makecol(255,255,255); else mono_or_col = -1;
    x=y=dir=btex_ymax=0;
    for(n=0;n<96;n++){
    
        again:
        
        if(y>=btex_h)break;  //just to be safe
        
        if(!dir){
            if(x+nfont->glyph[tmp_index[n]].w + EDGEPIX <  btex_w){
            while(getpixel(tmp,x+nfont->glyph[tmp_index[n]].w,y- EDGEPIX )&&y<btex_h)y++;
            while(getpixel(tmp,x,y- EDGEPIX )&&y<btex_h)y++;    
                rectfill(tmp,x,y,x + nfont->glyph[tmp_index[n]].w + EDGEPIX, y + nfont->glyph[tmp_index[n]].h + EDGEPIX, makecol(255,0,255));
                s[0]=tmp_index[n]+32;s[1]=0;
                textout(tmp,fnt,s,x-nfont->glyph[tmp_index[n]].px,y-nfont->glyph[tmp_index[n]].py,mono_or_col);
                nfont->glyph[tmp_index[n]].offx=x;
                nfont->glyph[tmp_index[n]].offy=y;
                x+=nfont->glyph[tmp_index[n]].w+1+ EDGEPIX ;
                
                if(y+nfont->glyph[tmp_index[n]].h>btex_ymax)btex_ymax=y+nfont->glyph[tmp_index[n]].h;

            } else {
                dir=1;
                x=btex_w-1;
                y+=nfont->glyph[tmp_index[n]].h;
                goto again;
            }
            
        } else {
            if(x-nfont->glyph[tmp_index[n]].w -1-EDGEPIX >=  0){
                x-=(nfont->glyph[tmp_index[n]].w+1+ EDGEPIX );
                while(getpixel(tmp,x+nfont->glyph[tmp_index[n]].w,y- EDGEPIX )&&y<btex_h)y++;
                while(getpixel(tmp,x,y- EDGEPIX )&&y<btex_h)y++;
                rectfill(tmp,x,y,x + nfont->glyph[tmp_index[n]].w + EDGEPIX , y + nfont->glyph[tmp_index[n]].h + EDGEPIX, makecol(255,0,255));
                s[0]=tmp_index[n]+32;s[1]=0;s[0]=tmp_index[n]+32;s[1]=0;
                textout(tmp,fnt,s,x-nfont->glyph[tmp_index[n]].px,y-nfont->glyph[tmp_index[n]].py,mono_or_col);
                nfont->glyph[tmp_index[n]].offx=x;
                nfont->glyph[tmp_index[n]].offy=y;
                
                if(y+nfont->glyph[tmp_index[n]].h>btex_ymax)btex_ymax=y+nfont->glyph[tmp_index[n]].h;
                
            } else {
                dir=0;
                x=0;
                y+=nfont->glyph[tmp_index[n]].h;
                goto again;
            }       
        
        
        }
        
    
       
    }
    
    
    
    

    
    
    
    
    for(i=0;i<btex_w;i++){
        for(j=0;j<btex_ymax;j++){
            if(getpixel(tmp,i,j)==0)putpixel(tmp,i,j,makecol(255,0,255));
        }
    }
    
    
    //this is for anti-aliasing, still very basic at the moment
    if(use_jfont_alpha){
        unsigned char R,G,B,A;
        int col;
        
        for(i=0;i<btex_w;i++){
            for(j=0;j<btex_ymax;j++){
                col=getpixel(tmp,i,j);
                R=getr(col);
                G=getg(col);
                B=getb(col);
                A=geta(col);
            
                if(R==255&&G==0&&B==255)A=0; else A=255;
                putpixel(tmp,i,j,makeacol32(R,G,B,A));
            }
        }
        
        //use anti-ailasing
        for(i=0;i<btex_w;i++){
            for(j=0;j<btex_ymax;j++){
                col=getpixel(tmp,i,j);
                R=getr(col);
                G=getg(col);
                B=getb(col);
                A=geta(col);
            
                if(A&&(i==0||j==0||i==btex_w-1||j==btex_ymax-1||
                geta(getpixel(tmp,i-1,j))==0||
                geta(getpixel(tmp,i+1,j))==0||
                geta(getpixel(tmp,i,j-1))==0||
                geta(getpixel(tmp,i,j+1))==0))
                putpixel(tmp,i,j,makeacol32(R,G,B,148));
            
            }
        }
        
        
        for(i=0;i<btex_w;i++){
            for(j=0;j<btex_ymax;j++){
                col=getpixel(tmp,i,j);
                R=getr(col);
                G=getg(col);
                B=getb(col);
                A=geta(col);
            
                if(A==255&&(i==0||j==0||i==btex_w-1||j==btex_ymax-1||
                geta(getpixel(tmp,i-1,j-1))==0||
                geta(getpixel(tmp,i+1,j-1))==0||
                geta(getpixel(tmp,i+1,j+1))==0||
                geta(getpixel(tmp,i-1,j+1))==0))
                putpixel(tmp,i,j,makeacol32(R,G,B,196));
            
    
            }
        }
        
        
    }
    
    
    
    
    
    
    
    btex_ymax=closest_power_of_2(btex_ymax);
    
    for(n=0;n<96;n++){ 
    
        nfont->glyph[n].offxx=nfont->glyph[n].offx+nfont->glyph[n].w+1;
        nfont->glyph[n].offyy=nfont->glyph[n].offy+nfont->glyph[n].h+1; 
    
        //Scale to max height
        nfont->glyph[n].w /=nfont->font_height;
        nfont->glyph[n].h /=nfont->font_height;
        nfont->glyph[n].px/=nfont->font_height;
        nfont->glyph[n].py/=nfont->font_height; 
    
        //clamp offset to [0,1]
        nfont->glyph[n].offx/=btex_w;
        nfont->glyph[n].offy/=btex_ymax; 
        nfont->glyph[n].offxx/=btex_w;
        nfont->glyph[n].offyy/=btex_ymax; 
        
        
    }
    
    
    
    tmp_sub = create_sub_bitmap(tmp,0,0,btex_w,btex_ymax);
    allegro_gl_flip_texture(n);
        
    n=allegro_gl_flip_texture(0);
    if(use_jfont_alpha)allegro_gl_use_alpha_channel(TRUE);
    nfont->texture=allegro_gl_make_masked_texture(tmp_sub);
    if(use_jfont_alpha)allegro_gl_use_alpha_channel(FALSE);
    allegro_gl_flip_texture(n);
    
    glBindTexture(GL_TEXTURE_2D, nfont->texture);
    
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
 
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
    
    
    
    save_bitmap("tmpbmp.bmp",tmp_sub,NULL);
    destroy_bitmap(tmp);
    
    return(nfont);
}


void destroy_jfont(JFONT *jfont){
    glDeleteTextures(1,&(jfont->texture));
    free(jfont);
}
