/***************************************************************************
                          sdl.c  -  description
                             -------------------
    begin                : Thu Apr 20 2000
    copyright            : (C) 2000 by Michael Speck
    email                : kulkanie@gmx.net
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "sdl.h"
#include <stdlib.h>
#include <string.h>

/*
    if you are using SDL 1.1.5 keep this defined
*/
// ARB: 21 May 2003: We're using SDL 1.2.6 and it still needs this
#define SDL_1_1_5

extern char *src_dir;
extern int  fast_quit;

DrawRgn dr_src, dr_dst;

/* I kept these '#ifdef USE_ASM' but these functions are not implemented in this version so you should not
define USE_ASM */

// sdl surface //

SDL_Surface* SSur_Load(char *fname, int f)
{
    SDL_Surface *buf;
    SDL_Surface *new_sur;
    char path[strlen(src_dir)+ strlen(fname) + 1];
    sprintf(path, "%s%s", src_dir, fname);
    buf = SDL_LoadBMP(path);
    if (buf == 0) {
        fprintf(stderr, "ERR: ssur_load: file not found: %s\n", path);
        return 0;
    }
    if (f & SDL_SWSURFACE)
        return buf;
    new_sur = SSur_Create(buf->w, buf->h, f);
    SDL_BlitSurface(buf, 0, new_sur, 0);
    SDL_FreeSurface(buf);
    return new_sur;
}

SDL_Surface* SSur_Create(int w, int h, int f)
{
    SDL_Surface *sur;
    SDL_PixelFormat *spf = SDL_GetVideoSurface()->format;
    if ((sur = SDL_CreateRGBSurface(f, w, h, spf->BitsPerPixel, spf->Rmask, spf->Gmask, spf->Bmask, spf->Amask)) == 0) {
        fprintf(stderr, "ERR: ssur_create: not enough memory to create surface...\n");
        exit(1);
    }
/*    if (f & SDL_HWSURFACE && !(sur->flags & SDL_HWSURFACE))
        fprintf(stderr, "unable to create surface (%ix%ix%i) in hardware memory...\n", w, h, spf->BitsPerPixel);*/
    SDL_SetColorKey(sur, SDL_SRCCOLORKEY, 0x0);
    SDL_SetAlpha(sur, 0, 0); // no alpha //
    return sur;
}

int SSur_DisplayFormat(SDL_Surface *sur)
{
    if ((sur = SDL_DisplayFormat(sur)) == 0) {
        fprintf(stderr, "ERR: ssur_displayformat: convertion failed\n");
        return 1;
    }
    return 0;
}

void SSur_Begin(SDL_Surface *sur)
{
    if (SDL_MUSTLOCK(sur))
        SDL_LockSurface(sur);
}

void SSur_End(SDL_Surface *sur)
{
    if (SDL_MUSTLOCK(sur))
        SDL_UnlockSurface(sur);
}

void SSur_Blit(void)
{
#ifdef USE_ASM
    if (dr_src.s->flags & SDL_SRCALPHA) {
        SC_Trp_X(dr_dst.s->pixels, dr_dst.s->w, dr_dst.r.x, dr_dst.r.y, dr_src.s->pixels, dr_src.s->w, dr_src.r.x, dr_src.r.y, dr_src.r.w, dr_src.r.h, 255 - dr_src.s->format->alpha);
    }
    else
        if (dr_src.s->flags & SDL_SRCCOLORKEY)
            SC_Clp(dr_dst.s->pixels, dr_dst.s->w, dr_dst.r.x, dr_dst.r.y, dr_src.s->pixels, dr_src.s->w, dr_src.r.x, dr_src.r.y, dr_src.r.w, dr_src.r.h);
        else
            SC_Opq(dr_dst.s->pixels, dr_dst.s->w, dr_dst.r.x, dr_dst.r.y, dr_src.s->pixels, dr_src.s->w, dr_src.r.x, dr_src.r.y, dr_src.r.w, dr_src.r.h);
#else
#ifdef SDL_1_1_5
    if (dr_src.s->flags & SDL_SRCALPHA)
        SDL_SetAlpha(dr_src.s, SDL_SRCALPHA, 255 - dr_src.s->format->alpha);
#endif
    SDL_BlitSurface(dr_src.s, &dr_src.r, dr_dst.s, &dr_dst.r);
#ifdef SDL_1_1_5
    if (dr_src.s->flags & SDL_SRCALPHA)
        SDL_SetAlpha(dr_src.s, SDL_SRCALPHA, 255 - dr_src.s->format->alpha);
#endif
#endif
}

void SSur_AlphaBlit(int alpha)
{
#ifdef USE_ASM
    if (alpha == 127)
        SC_Trp_11(dr_dst.s->pixels, dr_dst.s->w, dr_dst.r.x, dr_dst.r.y, dr_src.s->pixels, dr_src.s->w, dr_src.r.x, dr_src.r.y, dr_src.r.w, dr_src.r.h);
    else
        SC_Trp_X(dr_dst.s->pixels, dr_dst.s->w, dr_dst.r.x, dr_dst.r.y, dr_src.s->pixels, dr_src.s->w, dr_src.r.x, dr_src.r.y, dr_src.r.w, dr_src.r.h, 255 - alpha);
#else
#ifdef SDL_1_1_5
    SDL_SetAlpha(dr_src.s, SDL_SRCALPHA, 255 - alpha);
#else
    SDL_SetAlpha(dr_src.s, SDL_SRCALPHA, alpha);
#endif
    SDL_BlitSurface(dr_src.s, &dr_src.r, dr_dst.s, &dr_dst.r);
    SDL_SetAlpha(dr_src.s, 0, 0);
#endif
}

void SSur_Fill(int c)
{
#ifdef USE_ASM
    SD_Box(dr_dst.s->pixels, dr_dst.s->w, 0, 0, dr_dst.s->w, dr_dst.s->h, c);
#else
    SDL_FillRect(dr_dst.s, &dr_dst.r, SDL_MapRGB(dr_dst.s->format, c >> 16, (c >> 8) & 0xFF, c & 0xFF));
#endif
}

// sdl font //

SFnt* SFnt_Load(char *fname)
{
    SFnt    *fnt = 0;
    FILE    *file = 0;
    char    path[strlen(src_dir)+ strlen(fname) + 1];
    int     i;

    sprintf(path, "%s%s", src_dir, fname);

    fnt = malloc(sizeof(SFnt));
    if (fnt == 0) {
        fprintf(stderr, "ERR: sfnt_load: not enough memory\n");
        exit(1);
    }

    if ((fnt->sur = SSur_Load(fname, SDL_SWSURFACE)) == 0)
        exit(1);
		
    fnt->algn = TA_X_LEFT | TA_Y_TOP;
    fnt->clr = 0x00FFFFFF;
    fnt->lh = fnt->sur->h;
	
    //table
    file = fopen(path, "r");
    fseek(file, -1, SEEK_END);
    fread(&fnt->off, 1, 1, file);
#ifdef DEBUG
    printf("offset: %i\n", fnt->off);
#endif
    fseek(file, -2, SEEK_END);
    fread(&fnt->num, 1, 1, file);
#ifdef DEBUG
    printf("number: %i\n", fnt->num);
#endif
    fseek(file, -2 - fnt->num, SEEK_END);
    fread(fnt->lw, 1, fnt->num, file);
#ifdef DEBUG
    printf("letter width: %i\n", fnt->num);
    for (i = 0; i < fnt->num; i++)
        printf("%i ", fnt->lw[i]);
    printf("\n");
#endif
    fclose(file);

    //letter offsets
    fnt->loff[0] = 0;
    for (i = 1; i < fnt->num; i++)	
        fnt->loff[i] = fnt->loff[i - 1] + fnt->lw[i - 1];
	
    //allowed keys
    memset(fnt->keys, 0, 256);
    for (i = 0; i < fnt->num; i++) {
        fnt->keys[i + fnt->off] = 1;
    }
	
    fnt->lastX = fnt->lastY = fnt->lastW = fnt->lastH = 0;
    return fnt;
}

SFnt* SFnt_LoadFixed(char *f, int off, int len, int w)
{
    int     i;
    SFnt    *fnt;
    char    path[strlen(src_dir)+ strlen(f) + 1];

    sprintf(path, "%s%s", src_dir, f);

    fnt = malloc(sizeof(SFnt));
    if (fnt == 0) {
        fprintf(stderr, "ERR: sfnt_load: not enough memory\n");
        exit(1);
    }

    if ((fnt->sur = SSur_Load(f, SDL_SWSURFACE)) == 0)
        exit(1);
		
    fnt->algn = TA_X_LEFT | TA_Y_TOP;
    fnt->clr = 0x00FFFFFF;
    fnt->lh = fnt->sur->h;
	
	fnt->off = off;
	fnt->num = len;
	
	for (i = 0; i < len; i++)
	    fnt->lw[i] = w;
	
    //letter offsets
    fnt->loff[0] = 0;
    for (i = 1; i < fnt->num; i++)	
        fnt->loff[i] = fnt->loff[i - 1] + w;
	
    //allowed keys
    memset(fnt->keys, 0, 256);
    for (i = 0; i < fnt->num; i++) {
        fnt->keys[i + fnt->off] = 1;
    }
	
    fnt->lastX = fnt->lastY = fnt->lastW = fnt->lastH = 0;
    return fnt;
}

void SFnt_Free(SFnt *fnt)
{
    if (fnt->sur) SDL_FreeSurface(fnt->sur);
    free(fnt);
}

int SFnt_Write(SFnt *fnt, SDL_Surface *dest, int x, int y, char *str, int alpha)
{
    int	c_abs;
    int len = strlen(str);
    int pix_len = 0;
    int px = x, py = y;
    int i;
    SDL_Surface *spf = SDL_GetVideoSurface();
	
    pix_len = SFnt_TextWidth(fnt, str);
	for (i = 0; i < len; i++)
	    if (!fnt->keys[(int)str[i]])
	        str[i] = ' ';

    //alignment
    if (fnt->algn & TA_X_CENTER)
        px -= pix_len >> 1;
    else
        if (fnt->algn & TA_X_RIGHT)
            px -= pix_len;
    if (fnt->algn & TA_Y_CENTER)
        py -= fnt->lh >> 1;
    else
        if (fnt->algn & TA_Y_BOTTOM)
            py -= fnt->lh;

    fnt->lastX = px; if (fnt->lastX < 0) fnt->lastX = 0;
    fnt->lastY = py; if (fnt->lastY < 0) fnt->lastY = 0;
    fnt->lastW = pix_len; if (fnt->lastX + fnt->lastW >= spf->w) fnt->lastW = spf->w - fnt->lastX;
    fnt->lastH = fnt->lh; if (fnt->lastY + fnt->lastH >= spf->h) fnt->lastH = spf->h - fnt->lastY;

    if (alpha != 0)
        SDL_SetAlpha(fnt->sur, SDL_SRCALPHA, alpha);
    else
        SDL_SetAlpha(fnt->sur, 0, 0);
    for (i = 0; i < len; i++) {
       	c_abs = str[i] - fnt->off;
       	DR_SETDST(dest, px, py, fnt->lw[c_abs], fnt->lh);
       	DR_SETSRC(fnt->sur, fnt->loff[c_abs], 0);
       	SSur_Blit();
        px += fnt->lw[c_abs];
    }
	
    return 0;
}

void SFnt_Begin(SFnt *fnt)
{
    SSur_Begin(fnt->sur);
}

void SFnt_End(SFnt *fnt)
{
    SSur_End(fnt->sur);
}
	
SDL_Rect SFnt_LastRect(SFnt *fnt)
{
    SDL_Rect    rect={fnt->lastX, fnt->lastY, fnt->lastW, fnt->lastH};
    return rect;
}

int SFnt_TextWidth(SFnt *fnt, char *str)
{
    unsigned int i;
    int pix_len = 0;
    for (i = 0; i < strlen(str); i++)
        pix_len += fnt->lw[str[i] - fnt->off];
    return pix_len;
}

// sdl //

Sdl sdl;

void Sdl_Init(int f)
{
    sdl.scr = 0;
    if (SDL_Init(f) < 0) {
        fprintf(stderr, "ERR: sdl_init: %s", SDL_GetError());
        exit(1);
    }
    SDL_EnableUNICODE(1);
    atexit(SDL_Quit);
}

void Sdl_Quit()
{
    if (sdl.scr) SDL_FreeSurface(sdl.scr);
}

int	Sdl_SetVideoMode(int w, int h, int d, int f)
{
    const SDL_VideoInfo	*vi = SDL_GetVideoInfo();
    char *ny[2] = {"No", "Yes"};
    SDL_PixelFormat	*fmt;
	
    if (sdl.scr) SDL_FreeSurface(sdl.scr);
    if ((sdl.scr = SDL_SetVideoMode(w, h, d, f)) == 0) {
        fprintf(stderr, "ERR: sdl_setvideomode: %s", SDL_GetError());
        return 1;
    }

#ifdef USE_ASM    	
    //set gfx format
    fmt = sdl.scr->format;
    rMask = fmt->Rmask;
    gMask = fmt->Gmask;
    bMask = fmt->Bmask;
    bpp   = fmt->BitsPerPixel;
    rlShft = fmt->Rshift;
    glShft = fmt->Gshift;
    blShft = fmt->Bshift;
    rrShft = fmt->Rloss;
    grShft = fmt->Gloss;
    brShft = fmt->Bloss;
    Gfx_SetClipRgn(0, 0, w,  h);
#endif

#ifdef DEBUG				
    if (f & SDL_HWSURFACE && !(sdl.scr->flags & SDL_HWSURFACE))
       	fprintf(stderr, "unable to create screen in hardware memory...\n");
    if (f & SDL_DOUBLEBUF && !(sdl.scr->flags & SDL_DOUBLEBUF))
        fprintf(stderr, "unable to create double buffered screen...\n");
    if (f & SDL_FULLSCREEN && !(sdl.scr->flags & SDL_FULLSCREEN))
        fprintf(stderr, "unable to switch to fullscreen...\n");

/*    printf("video mode format:\n");
    printf("Masks: R=%i, G=%i, B=%i\n", fmt->Rmask, fmt->Gmask, fmt->Bmask);
    printf("LShft: R=%i, G=%i, B=%i\n", fmt->Rshift, fmt->Gshift, fmt->Bshift);
    printf("RShft: R=%i, G=%i, B=%i\n", fmt->Rloss, fmt->Gloss, fmt->Bloss);
    printf("BBP: %i\n", fmt->BitsPerPixel);*/
		
    printf("video hardware capabilities:\n");
    printf("Hardware Surfaces: %s\n", ny[vi->hw_available]);
    printf("HW_Blit (CC, A): %s (%s, %s)\n", ny[vi->blit_hw], ny[vi->blit_hw_CC], ny[vi->blit_hw_A]);
    printf("SW_Blit (CC, A): %s (%s, %s)\n", ny[vi->blit_sw], ny[vi->blit_sw_CC], ny[vi->blit_sw_A]);
    printf("HW_Fill: %s\n", ny[vi->blit_fill]);
    printf("Video Memory: %i\n", vi->video_mem);
#endif

    return 0;
}

void Sdl_Update(int x, int y, int w, int h)
{
    SDL_UpdateRect(sdl.scr, x, y, w, h);
}

void Sdl_FullUpdate()
{
    SDL_UpdateRect(sdl.scr, 0, 0, 0 ,0);
}

void Sdl_Dim(int steps, int delay, int trp)
{
    SDL_Surface    *buffer;
    int per_step = trp / steps;
    int i;
#ifndef USE_ASM
    per_step *= 2;
#endif
    if (fast_quit) return;
    buffer = SSur_Create(sdl.scr->w, sdl.scr->h, SDL_SWSURFACE);
    SDL_SetColorKey(buffer, 0, 0);
    DR_SETFULLDST(buffer);
    DR_SETFULLSRC(sdl.scr);
    SSur_Blit();
    for (i = 0; i <= trp; i += per_step) {
#ifdef USE_ASM
        SC_Opq(sdl.scr->pixels, sdl.scr->w, 0, 0,
            buffer->pixels, buffer->w,
            0, 0, sdl.scr->w, sdl.scr->h);
        SD_CBx(sdl.scr->pixels, sdl.scr->w, 0, 0, sdl.scr->w, sdl.scr->h, 0x0, i);
#else
        DR_SETFULLDST(sdl.scr);
        SSur_Fill(0x0);
        DR_SETFULLSRC(buffer);
        SSur_AlphaBlit(i);
#endif
        Sdl_FullUpdate();
        SDL_Delay(delay);
    }
    if (trp == 255) {
        DR_SETFULLDST(sdl.scr);
        SSur_Fill(0x0);
        Sdl_FullUpdate();
    }
    SDL_FreeSurface(buffer);
}

void Sdl_UnDim(int steps, int delay, int trp)
{
    SDL_Surface    *buffer;
    int per_step = trp / steps;
    int i;
#ifndef USE_ASM
    per_step *= 2;
#endif
    if (fast_quit) return;
    buffer = SSur_Create(sdl.scr->w, sdl.scr->h, SDL_SWSURFACE);
    SDL_SetColorKey(buffer, 0, 0);
    DR_SETFULLDST(buffer);
    DR_SETFULLSRC(sdl.scr);
    SSur_Blit();
    for (i = trp; i >= 0; i -= per_step) {
#ifdef USE_ASM
        SC_Opq(sdl.scr->pixels, sdl.scr->w, 0, 0,
            buffer->pixels, buffer->w,
            0, 0, sdl.scr->w, sdl.scr->h);
        SD_CBx(sdl.scr->pixels, sdl.scr->w, 0, 0, sdl.scr->w, sdl.scr->h, 0x0, i);
#else
        DR_SETFULLDST(sdl.scr);
        SSur_Fill(0x0);
        DR_SETFULLSRC(buffer);
        SSur_AlphaBlit(i);
#endif
        Sdl_FullUpdate();
        SDL_Delay(delay);
    }
    DR_SETFULLDST(sdl.scr);
    DR_SETFULLSRC(buffer);
    SSur_Blit();
    Sdl_FullUpdate();
    SDL_FreeSurface(buffer);
}

int Sdl_WaitForKey()
{
    //wait for key
    SDL_Event event;
    while (1) {
        SDL_WaitEvent(&event);
        if (event.type == SDL_QUIT) {
            fast_quit = 1;
            return 0;
        }
        if (event.type == SDL_KEYUP)
            return event.key.keysym.sym;
    }
}

void Sdl_WaitForClick()
{
    //wait for key or button
    SDL_Event event;
    while (1) {
        SDL_WaitEvent(&event);
        if (event.type == SDL_QUIT) {
            fast_quit = 1;
            return;
        }
        if (event.type == SDL_KEYUP || event.type == SDL_MOUSEBUTTONUP)
            return;
    }
}
/*
void Sdl_Begin()
{
    if (SDL_MUSTLOCK(sdl.scr))
        SDL_LockSurface(sdl.scr);
}

void Sdl_End()
{
    if (SDL_MUSTLOCK(sdl.scr))
        SDL_UnlockSurface(sdl.scr);
}

void Sdl_Flip()
{
    SDL_Flip(sdl.scr);
}

void Sdl_SetClipRgn(int x, int y, int w, int h)
{
    SDL_SetClipping(sdl.scr, x, y, x + w, y + h);
}
*/
