Logo Search packages:      
Sourcecode: jigzo version File versions  Download package

main.cxx

/*
 *  jigzo, an OpenGL jigsaw game
 *  
 *  version 0.6.1
 *
 *  http://www.resorama.com/jigzo/
 *  
 *  Copyright (C) 2005-2008  Maarten de Boer <maarten@resorama.com>
 * 
 *  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.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 *  02110-1301, USA.
 * 
 */

/*
float BG_R = float(0x35)/255.;
float BG_G = float(0x90)/255.;
float BG_B = float(0xbc)/255.;
*/
float BG_R = float(0x99)/255.;
float BG_G = float(0x00)/255.;
float BG_B = float(0x00)/255.;

bool rotateEnabled = false;
bool soundEnabled = false;
bool soundFailed = false;
#define INTROIMGW 420 
#define INTROIMGH 300

#include <cstdio>
#include <cstring>
#include <cmath>
#include <list>
#include <vector>
#include <fstream>
#include <string>
#include <sstream>

#ifdef WIN32
#include <io.h>
#else
// mkdir, dirent
#include <sys/stat.h>
#include <sys/types.h>
#endif
#include <dirent.h>

#include "Screen.hxx"
#include "Sprite.hxx"
#include <SDL.h>

#ifdef ENABLE_SOUND
#include <SDL_mixer.h>
Mix_Chunk *mixChunkConnect = NULL;
Mix_Chunk *mixChunkFinish = NULL;
#endif

#include "Loader.hxx"

int  tolerance = 1;
const char* toleranceString[3] = {
                  "  Easy","Normal","  Hard"};
float toleranceAngle[3] = {4.*M_PI/36.,2.*M_PI/36.,M_PI/36.};
float toleranceLength[3] = {16,8,4};


Rect rotateOptionRect;
Rect soundOptionRect;
Rect toleranceOptionRect;

int INTERPOLATION = GL_NEAREST;

void Assign(Texture& texture,RGBA& rgba,GLint param)
{
      texture.Bind();

      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, param);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, param);

      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rgba.Width(), rgba.Height(),
                               0, GL_RGBA, GL_UNSIGNED_BYTE, rgba.Data());

      texture.rect = Rect(0,0,rgba.Width(),rgba.Height());
}

void SetSound(bool enable)
{
      int audio_rate = 44100;
      Uint16 audio_format = AUDIO_S16;
      int audio_channels = 2;
#ifdef WIN32
      int audio_buffers = 4096;
#else
      int audio_buffers = 1024;
#endif

      if (enable==soundEnabled) return;
      soundEnabled = enable;
#ifdef ENABLE_SOUND
      if (soundEnabled)
      {
            if (Mix_OpenAudio(audio_rate, audio_format, audio_channels, audio_buffers))
            {
                  printf("Unable to open audio... continuing without.\n");
                  soundFailed = true;
            }else{
                  mixChunkConnect= Mix_LoadWAV("sound/connect.wav");
                  mixChunkFinish= Mix_LoadWAV("sound/finish.wav");
            }
      }
      else
      {
            Mix_CloseAudio();
            Mix_FreeChunk(mixChunkConnect);
            Mix_FreeChunk(mixChunkFinish);
            mixChunkConnect = NULL;
            mixChunkFinish = NULL;
      }
}
#endif


using namespace std;

string puzzlename;

Uint32 fadestart = 0;
Uint32 fotofade = 0;
bool fadein = 0;

enum Mode {
      start_intro,
      intro,
      end_intro,
      start_browse,
      browse,
      end_browse,
      start_play,
      play,
      end_play,
      end
};

Mode mode,next_mode,next_next_mode;

Sprite *image = 0;
Sprite *arrow = 0;
Sprite *leave= 0;

Sprite *chars[128];

int mouseX = 0,mouseY = 0;

class PuzzlePieceSprite **grid = 0;
int ncolumns = 0;
int nrows = 0;

GLuint global_gl_texture;

typedef std::list < class PreviewSprite * >PreviewSpriteList;
typedef std::list < class PuzzlePieceSprite * >PuzzlePieceSpriteList;

PreviewSpriteList previews;
PuzzlePieceSpriteList puzzlePieces;
PuzzlePieceSpriteList drawOrder;
PuzzlePieceSprite *grab = 0;

int grabdx,grabdy;
float rotateX,rotateY;
float grabangle;
int lastSingleGroup = 0;

int nextGroup = 0;

float aw, ah;
Texture *texture;

bool drawFoto = 0;
Uint32 prevticks = 0;
float fade = 0.;


void FadeIn(void)
{
      fadestart = SDL_GetTicks();
      fadein = true;
}

void FadeOutTo(Mode _next_mode,Mode _next_next_mode)
{
      fadestart = SDL_GetTicks();
      fadein = false;
      next_mode = _next_mode;
      next_next_mode = _next_next_mode;
}

class PreviewSprite:public Sprite
{
public:
      string name;
      int npieces; // used for sorting
      PreviewSprite(const string & _name):Sprite(), name(_name)
      {}
};

class FolderSprite:public Sprite
{
public:
      int id;
      
      FolderSprite(int i):id(i)
      {
      }
};

vector<FolderSprite*> folders;

class PuzzlePieceSprite:public Sprite
{
public:
      int id;

      int group;
      bool grouped;
      int cx, cy;
      float tx, ty;
      Uint32 fadestart;
      float angle; // -180-180

      PuzzlePieceSprite(int _id):Sprite(), id(_id)
      {
            group = 0;
            grouped = false;
            fadestart = 0;
            angle = 0;
            if (rotateEnabled)
            angle = float(rand()%72)/72.f * 2.f*M_PI;
      }

      void RotatedDraw(void)
      {
            Draw(angle);
      }
};

void GrabToFront(void)
{
      std::list < PuzzlePieceSprite * >::iterator it, end;

      for (it = drawOrder.begin(); it != drawOrder.end();) {
            PuzzlePieceSprite *piece = *it;
            it++;
            if (grab != 0 && piece->group == grab->group) {
                  if (piece->fadestart==0) piece->fadestart = SDL_GetTicks();
            }
      }
}

int NextGroup(void)
{
      return nextGroup++;
}

bool Finished(void)
{
      std::list < PuzzlePieceSprite * >::iterator it;
      int g = -1;
      for (it = puzzlePieces.begin(); it != puzzlePieces.end(); it++)
      {
            if (g == -1)
                  g = (*it)->group;
            if (fabs((*it)->angle) > 0.00001)
            {
                  return false;
            }
            if ((*it)->group != g)
            {
                  return false;
            }
      }
      return true;
}

void JoinGroups(int idA, int idB)
{
      if (idA == idB) return;
      std::list < PuzzlePieceSprite * >::iterator it;

      for (it = puzzlePieces.begin(); it != puzzlePieces.end(); it++) {
            if ((*it)->group == idB)
            {
                  (*it)->group = idA;
                  (*it)->grouped = true;
            }
      }
      if (idA <= lastSingleGroup) {
            int idC = NextGroup();
            for (it = puzzlePieces.begin(); it != puzzlePieces.end(); it++) {
                  if ((*it)->group == idA)
                  {
                        (*it)->group = idC;
                        (*it)->grouped = true;
                  }
            }
      }
}

bool GroupNeighbours(int a, int b)
{
      std::list < PuzzlePieceSprite * >::iterator it;

      for (int j = 0; j < nrows; j++) {
            for (int i = 0; i < ncolumns; i++) {
                  if (grid[i + j * ncolumns]->group == a) {
                        if (i != 0 && grid[i - 1 + j * ncolumns]->group == b)
                              return 1;
                        if (i != ncolumns - 1
                                    && grid[i + 1 + j * ncolumns]->group == b)
                              return 1;
                        if (j != 0 && grid[i + (j - 1) * ncolumns]->group == b)
                              return 1;
                        if (j != nrows - 1
                                    && grid[i + (j + 1) * ncolumns]->group == b)
                              return 1;
                  }
            }
      }
      return 0;
}

class PreviewFolder
{
      public:
            string directory;
            int offset;

            PreviewFolder(const string& d,int o):directory(d),offset(o)
            {
            }

            void Read(void);
};

vector<PreviewFolder*> previewfolders;
int currentPreviewFolder = 0;
int nextPreviewFolder = 0;

void FreeImages(void)
{
      delete arrow;
      arrow = 0;
      delete leave;
      leave = 0;
      vector<FolderSprite*>::const_iterator it;
      for (it = folders.begin(); it!= folders.end(); it++)
      {
            delete (*it);
      }
      folders.clear();
}

void FreePreviews(void)
{
      {
            std::list < PreviewSprite * >::iterator it;
            for (it = previews.begin(); it != previews.end(); it++) {
                  delete (*it);
            }
            previews.clear();
      }
      {
            std::vector < PreviewFolder* >::iterator it;
            for (it = previewfolders.begin(); it != previewfolders.end(); it++)
            {
                  delete (*it);
            }
            previewfolders.clear();
      }
      FreeImages();
      delete texture;
      texture = 0;
}

void FreeChars(void)
{
      for (int i = 0; i < 128; i++) {
            if (chars[i])
            {
                  delete chars[i];
                  chars[i] = 0;
            }

            chars[i] = 0;
      }
      std::list < PuzzlePieceSprite * >::iterator it;
      for (it = puzzlePieces.begin(); it != puzzlePieces.end(); it++) {
            PuzzlePieceSprite* crop = *it;
            delete crop;
      }
      puzzlePieces.clear();
      drawOrder.clear();
      FreeImages();
      delete texture;
      texture = 0;
}

void FreePuzzle(void)
{
      std::list < PuzzlePieceSprite * >::iterator it;
      for (it = puzzlePieces.begin(); it != puzzlePieces.end(); it++) {
            PuzzlePieceSprite* crop = *it;
            delete crop;
      }
      puzzlePieces.clear();
      drawOrder.clear();
      delete image;
      image = 0;
      FreeImages();
      delete [] grid;
      grid = 0;
      delete texture;
      texture = 0;
}

class TmpDir
{
public:
      string _path;
      TmpDir()
      {
            stringstream ss;
#ifdef WIN32
            ss << "tmpfiles/";
            _path = ss.str();
            mkdir(_path.c_str());
#else
            ss << "/tmp/jigzo." << getpid() << "/";
            _path = ss.str();
            mkdir(_path.c_str(),0755);
#endif
      }
      ~TmpDir()
      {
            DIR* dir = opendir(_path.c_str());
            struct dirent* dirent;
            while ((dirent = readdir(dir)))
            {
                  string n(dirent->d_name);
                  if (n!="." && n!="..")
                  {
                        n = _path+n;
                        remove(n.c_str());
                  }
            }
            remove(_path.c_str());
            closedir(dir);
      }
      const string& Path() { return _path; }
};

class PuzzleFile
{
public:
      TmpDir tmpdir;
      string jpg;
      string png;
      string thumbJpg;
      string map;

      const string& Jpg(void) { return jpg; }
      const string& Png(void) { return png; }
      const string& ThumbJpg(void) { return thumbJpg; }
      const string& Map(void) { return map; }

      PuzzleFile(const string& pzl)
      {
            std::ifstream f(pzl.c_str(), std::ios::binary);
            char tmp[4096];
            int chucklen;
            f.getline(tmp, 256 ,'\n'); // PzlF
            if (string(tmp)!="PzlF") {
                  fprintf(stderr,"%s is not a valid file\n",pzl.c_str());
            }
            f.getline(tmp, 256 ,'\n'); // version
            if (string(tmp)!="0.1") {
                  fprintf(stderr,"%s is not the right version\n",pzl.c_str());
            }
            f.getline(tmp, 256 ,'\n'); // name
            f.getline(tmp, 256 ,'\n'); // URL
            while (!f.eof())
            {
                  f.getline(tmp, 256, '\n'); // filename
                  if (!f.eof())
                  {
                        string filename(tmpdir.Path() + tmp);
                        if (filename.substr(filename.length()-6)=="-t.jpg")
                              thumbJpg = filename;
                        else
                        {
                              string ext = filename.substr(filename.length()-4);
                              if (ext==".png")
                                    png = filename;
                              else if (ext==".jpg")
                                    jpg = filename;
                              else if (ext==".map")
                                    map = filename;
                              else
                                    throw "ERROR PARSING PUZZLE FILE";
                        }

                        std::ofstream of(filename.c_str(), std::ios::binary);
                        f.getline(tmp, 256); // length
                        string s(tmp);
                        stringstream ss(s);
                        ss >> chucklen;
                        int n = chucklen;
                        while (n)
                        {
                              int m = n;
                              if (m>4096) m = 4096;
                              f.read(tmp,m);
                              of.write(tmp,m);
                              n -= m;
                        }
                  }
            }
      }
};

void LoadImages(RGBA& rgba,int nFolders)
{
      int offsetX = 0;
      int offsetY = 0;
      {
            PngLoader pngLoader;
            RGBA arrowRGBA;
            pngLoader.Load("image/arrow.png",arrowRGBA);
            rgba.Paste(arrowRGBA,rgba.Width()-arrowRGBA.Width(),
                                rgba.Height()-arrowRGBA.Height());
            arrow = new Sprite;
            arrow->CreateTextureMap(texture,
                                                            Rect(
                                                                  rgba.Width()-arrowRGBA.Width(),
                                                                  rgba.Height()-arrowRGBA.Height(),
                                                                  arrowRGBA.Width(),
                                                                  arrowRGBA.Height()));
            arrow->Move(Point(mouseX, mouseY));
            offsetX = arrowRGBA.Width();
      }
      {
            PngLoader pngLoader;
            RGBA leaveRGBA;
            pngLoader.Load("image/leave.png",leaveRGBA);
            rgba.Paste(leaveRGBA,rgba.Width()-offsetX-leaveRGBA.Width(),
                                rgba.Height()-offsetY-leaveRGBA.Height());
            leave = new Sprite;
            leave->CreateTextureMap(texture,
                                                            Rect(
                                                                  rgba.Width()-offsetX-leaveRGBA.Width(),
                                                                  rgba.Height()-offsetY-leaveRGBA.Height(),
                                                                  leaveRGBA.Width(),
                                                                  leaveRGBA.Height()));
            leave->Move(Point(1024-4-leave->GetRect().w,768-leave->GetRect().h));
            offsetX += leaveRGBA.Width();
      }
      if (nFolders)
      {
            PngLoader pngLoader;
            RGBA folderRGBA;
            pngLoader.Load("image/folder.png",folderRGBA);
            rgba.Paste(folderRGBA,rgba.Width()-offsetX-folderRGBA.Width(),
                                rgba.Height()-offsetY-folderRGBA.Height());
            for (int i = 0;i<nFolders; i++)
            {
                  FolderSprite* folder = new FolderSprite(i);
                  folder->CreateTextureMap(texture,
                                                            Rect(
                                                                  rgba.Width()-offsetX-folderRGBA.Width(),
                                                                  rgba.Height()-offsetY-folderRGBA.Height(),
                                                                  folderRGBA.Width(),
                                                                  folderRGBA.Height()));
                  folder->Move(Point(4+i*(4+folder->GetRect().w),768-folder->GetRect().h));
                  folders.push_back(folder);
            }
      }
}

struct sort_previews:public binary_function<PreviewSprite*,PreviewSprite*,bool>
{
      bool operator()(PreviewSprite* a,PreviewSprite* b)
      {
            return a->npieces < b->npieces;
      }
};

int CountPieces(const string& map)
{
      int n = 0;
      std::fstream f(map.c_str(), std::ios::in);
      char tmp[256];
      while (!f.eof()) {
            if (f.getline(tmp, 256))
            {
                  string s(tmp);
                  if (s.substr(0, 4) == "crop") { n++; } // old version
                  if (s.substr(0, 5) == "piece") { n++; } // new version
            }
      }
      return n;
}

void RecursePreviewFolder(string dirname)
{
      DIR* dir = opendir(dirname.c_str());
      if (!dir) return;
      int i = 0;
      PreviewFolder* folder = 0;
      struct dirent* dirent;
      vector<string> subdirs;
      while ((dirent = readdir(dir)))
      {
            string n(dirent->d_name);
            if (n!="." && n!=".." && n!="CVS")
            {
                  string::size_type pos = n.rfind(".");
                  if (pos != string::npos && n.substr(pos)==".pzl")
                  {
                        if ((i%12)==0) {
                              folder = new PreviewFolder(dirname,i);
                              previewfolders.push_back(folder);
                        }
                        i++;
                  }
                  else
                  {
                        subdirs.push_back(n);
                  }
            }
      }
      closedir(dir);
      sort(subdirs.begin(), subdirs.end());
      vector<string>::const_iterator it;
      for (it = subdirs.begin(); it != subdirs.end(); it++)
      {
            RecursePreviewFolder(dirname + (*it) + "/");
      }     
}


void ReadPreviewFolders(void)
{
      RecursePreviewFolder("puzzles/");
};

void ReadPreviews(void)
{
      currentPreviewFolder = nextPreviewFolder;
      ReadPreviewFolders();
      
      texture = new Texture(global_gl_texture);

      previewfolders[currentPreviewFolder]->Read();

}
void PreviewFolder::Read(void)
{
      RGBA rgba(1024,1024);
      JpgLoader jpgLoader;

      DIR* dir = opendir(directory.c_str());
      struct dirent* dirent;
      while ((dirent = readdir(dir)))
      {
            string n(dirent->d_name);
            string::size_type pos = n.rfind(".");
            if (pos != string::npos && n.substr(pos)==".pzl")
            {
                  PuzzleFile puzzlefile(directory+n);
                  PreviewSprite *preview;
                  preview = new PreviewSprite(directory+n);
                  preview->npieces = CountPieces(puzzlefile.Map());
                  previews.push_back(preview);
            }
      }
      closedir(dir);

      previews.sort(sort_previews());

      int x = 0, y = 0, i = 0;
      std::list < PreviewSprite * >::iterator it;
      it = previews.begin();
      
      while (it != previews.end() && i < offset) {
            PreviewSprite* preview = *it;
            delete preview;
            it++;
            i++;
      }
      previews.erase(previews.begin(),it);
      
      i = 0;
      
      while (it != previews.end() && i<12) {
            PreviewSprite* preview = *it;
            PuzzleFile puzzlefile(preview->name);
            jpgLoader.Load(puzzlefile.ThumbJpg(),rgba,x,y);
            preview->CreateTextureMap(texture, Rect(x,y,jpgLoader.width,jpgLoader.height));
            preview->pos = Point(
                                                x+(256-preview->GetRect().w)/2,
                                                y+(240-preview->GetRect().h)/2);
            x += 256;
            if (x==1024)
            {
                  x = 0;
                  y += 240;
            }
            it++;
            i++;
      }
      
      std::list < PreviewSprite * >::iterator itB = it;
      while (it != previews.end())
      {
            PreviewSprite* preview = *it;
            delete preview;
            it++;
      }

      previews.erase(itB,previews.end());

      if (previewfolders.size()>1)
            LoadImages(rgba,previewfolders.size());
      else
            LoadImages(rgba,0);
      
      Assign(*texture,rgba,INTERPOLATION);
}

void ReadChars(void)
{
      for (int i = 0; i < 128; i++) {
            chars[i] = 0;
      }

      string mapDataFilename = "font/charmap.map";

      texture = new Texture(global_gl_texture);

      RGBA rgba(1024,1024);

      PngLoader pngLoader;
      pngLoader.Load("font/charmap.png",rgba);

      JpgLoader jpgLoader;
      jpgLoader.Merge("font/charmap.jpg",rgba);

      Assign(*texture,rgba,GL_LINEAR);

      std::fstream f(mapDataFilename.c_str(), std::ios::in);
      if (!f.is_open()) {
            fprintf(stderr, "Failed to open %s\n", mapDataFilename.c_str());
            exit(-1);
      }
      char tmp[256];
      ncolumns = 0;
      nrows = 0;
      while (!f.eof()) {
            if (f.getline(tmp, 256) && tmp[0] != '#') {
                  string s(tmp);
                  stringstream ss(s);
                  Sprite *p = 0;
                  Rect rect;
                  Point handle;
                  string name;
                  ss >> name;
                  ss >> rect.x;
                  ss >> rect.y;
                  ss >> rect.w;
                  ss >> rect.h;
                  ss >> handle.x;
                  ss >> handle.y;
                  
                  int idInNameOffset = -1;
                  if (name.substr(0, 4) == "crop") // old version
                        idInNameOffset = 4;
                  if (name.substr(0, 5) == "piece") // new version
                        idInNameOffset = 5;

                  if (idInNameOffset!=-1)
                  {
                        PuzzlePieceSprite *crop = 0;
                        stringstream sn(name.substr(idInNameOffset));
                        int id;
                        sn >> id;
                        crop = new PuzzlePieceSprite(id);

                        puzzlePieces.push_back(crop);
                        drawOrder.push_back(crop);
                        ss >> crop->cx;
                        ss >> crop->cy;
                        ss >> crop->tx;
                        ss >> crop->ty;

                        p = crop;
                  } else {
                        char c = strtol(name.c_str(), 0, 16);
                        int i = c;
                        chars[i] = new Sprite;
                        p = chars[i];
                  }
                  if (p)
                  {
                        p->handle = handle;
                        p->CreateTextureMap(texture, rect);
                  }
            }
      }
      std::list < PuzzlePieceSprite * >::iterator it;
      for (it = puzzlePieces.begin(); it != puzzlePieces.end(); it++) {
            PuzzlePieceSprite *pp = *it;
            pp->Move(Point(240 + pp->tx * 2, 220 + pp->ty * 2));
      }

      LoadImages(rgba,0);
      Assign(*texture,rgba,INTERPOLATION);
}

void ReadPuzzle(const string & pzl)
{
      PuzzleFile puzzlefile(pzl);

      texture = new Texture(global_gl_texture);

      RGBA rgba;

      PngLoader pngLoader;
      pngLoader.Load(puzzlefile.Png(),rgba);

      JpgLoader jpgLoader;
      jpgLoader.Merge(puzzlefile.Jpg(),rgba);

      Assign(*texture,rgba,GL_LINEAR);

      std::fstream f(puzzlefile.Map().c_str(), std::ios::in);
      char tmp[256];
      ncolumns = 0;
      nrows = 0;
      while (!f.eof()) {
            if (f.getline(tmp, 256) && tmp[0] != '#') {
                  string s(tmp);
                  stringstream ss(s);
                  Sprite *p = 0;
                  Rect rect;
                  Point handle;
                  string name;
                  ss >> name;
                  ss >> rect.x;
                  ss >> rect.y;
                  ss >> rect.w;
                  ss >> rect.h;
                  ss >> handle.x;
                  ss >> handle.y;

                  int idInNameOffset = -1;
                  if (name.substr(0, 4) == "crop") // old version
                        idInNameOffset = 4;
                  if (name.substr(0, 5) == "piece") // new version
                        idInNameOffset = 5;

                  if (name == "image") {
                        image = new Sprite;
                        p = image;
                  } else if (idInNameOffset!=-1)
                  {
                        PuzzlePieceSprite *crop = 0;
                        stringstream sn(name.substr(idInNameOffset));
                        int id;
                        sn >> id;
                        crop = new PuzzlePieceSprite(id);

                        puzzlePieces.push_back(crop);
                        drawOrder.push_back(crop);
                        ss >> crop->cx;
                        ss >> crop->cy;
                        ss >> crop->tx;
                        ss >> crop->ty;
                        crop->group = NextGroup();
                        lastSingleGroup = crop->group;
                        if (crop->cx >= ncolumns)
                              ncolumns = crop->cx + 1;
                        if (crop->cy >= nrows)
                              nrows = crop->cy + 1;

                        p = crop;
                  }
                  if (p)
                  {
                        p->handle = handle;
                        p->CreateTextureMap(texture, rect);
                  }
            }
      }

      {
            std::list < PuzzlePieceSprite * >::iterator it;
            grid = new PuzzlePieceSprite *[ncolumns * nrows];
            for (it = puzzlePieces.begin(); it != puzzlePieces.end(); it++) {
                  PuzzlePieceSprite *piece = *it;
                  grid[piece->cx + piece->cy * ncolumns] = piece;
            }
      }
      aw = grid[0]->GetRect().w;
      ah = grid[0]->GetRect().h;

      LoadImages(rgba,0);
      Assign(*texture,rgba,INTERPOLATION);
}

Rect DrawString(float x, float y, char *str, float scale)
{
      char *ptr = str;
      float tw = 0;
      while (*ptr) {
            Sprite *s = chars[int (*ptr++)];
            if (s) {
                  Rect r = s->GetRect();
                  r.w = (r.w * scale);
                  tw += r.w;
            }
      }
      x -= tw / 2;
      float minx = x;
      float miny = y,maxy = y;
      ptr = str;
      while (*ptr) {
            Sprite *s = chars[int (*ptr++)];
            if (s) {
                  Rect r = s->GetRect();
                  r.x = x;
                  r.y = y - (s->handle.y * scale);
                  r.w = (r.w * scale);
                  r.h = (r.h * scale);
                  s->Draw(r);
                  x += r.w;
                  if (r.y < miny) miny = r.y;
                  if (r.y + r.h > maxy) maxy = r.y + r.h;
            }
      }
      return Rect(minx,miny,tw,maxy-miny);
}

void Randomize(void)
{
      std::list < PuzzlePieceSprite * >::iterator it;
      int n = nrows * ncolumns;
      std::vector < int >v(n);
      nextGroup = 0;
      for (int i = 0; i < n; i++)
            v[i] = i;
      for (it = puzzlePieces.begin(); it != puzzlePieces.end(); it++) {
            int r = rand() % n;
            int i = v[r];
            v[r] = v[--n];
            (*it)->pos = Point(4 + grid[i]->tx + grid[i]->tx / 5,
                                                 4 + grid[i]->ty + grid[i]->ty / 5);
            (*it)->group = NextGroup();
      }

      drawFoto = 0;
}

void DrawFade(void)
{
      if (fadestart)
      {
            if (fadein)
            {
                  fade = 1.-float(SDL_GetTicks() - fadestart) / 200.;
                  if (fade < 0.) {
                        fadestart = 0;
                        fade=0.;
                  }
            }else{
                  fade= float(SDL_GetTicks() - fadestart) / 200.;
                  if (fade>1.) {
                        fadestart = 0;
                        fade=1.;
                        mode = next_mode;
                        next_mode = next_next_mode;
                  }
            }
      }
      glDisable(GL_TEXTURE_2D);
      glColor4f(BG_R,BG_G,BG_B,fade);
      glRectf(0,0,1024,768);
}

void Display2(void)
{
      /*     if (mode==intro) {
                        static float fr = 0, fg = 0, fb = 0;
                        static int bgT = 0;
                        if (bgT == 0)
                              bgT = SDL_GetTicks();
                        fr += float (SDL_GetTicks() - bgT) / 2000.;
                        fg += float (SDL_GetTicks() - bgT) / 2100.;
                        fb += float (SDL_GetTicks() - bgT) / 2200.;
                        bgT = SDL_GetTicks();
                        if (fr > 2. * M_PI)
                              fr -= 2. * M_PI;
                        if (fg > 2. * M_PI)
                              fg -= 2. * M_PI;
                        if (fb > 2. * M_PI)
                              fb -= 2. * M_PI;
                        
                        BG_R = fabs(sin(fr));
                        BG_G = fabs(sin(fg));
                        BG_B = fabs(sin(fb));
              }
      */
      glClearColor(BG_R,BG_G,BG_B,0.0);
      glClear(GL_COLOR_BUFFER_BIT);
      glEnable(GL_TEXTURE_2D);
      glEnable(GL_BLEND);
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                  
      static int f[6] = {0,8000,20000,30000,4000,50000};
      static int d[6] = {6, 8, 9, 7, 11, 10};

      if (mode == start_intro)
      {
            ReadChars();
            prevticks = SDL_GetTicks();
            mode = intro;
            FadeIn();
            return;
      }
      if (mode == end_intro)
      {
            FreeChars();
            mode = next_mode;
            return;
      }

      if (mode == browse) {

            glColor3f(1,1 , 1);
            {
                  std::list < PreviewSprite * >::iterator it;
                  for (it = previews.begin(); it != previews.end(); it++) {
                        (*it)->Draw();
                  }
            }
            {
                  std::vector < FolderSprite * >::iterator it;
               for (it = folders.begin(); it != folders.end(); it++) {
                        if ((*it)->id == currentPreviewFolder)
                              glColor3f(0.7,0.3 , 0.3);
                        else
                              glColor3f(1,1 , 1);
                        (*it)->Draw();
                  }
            }
            glColor3f(1,1 , 1);
            leave->Draw();
            arrow->Draw();
            return;
      }

      if (mode == intro) {
            {
                  std::list < PuzzlePieceSprite * >::iterator it;
                  int i = 0;
                  Uint32 ticks = SDL_GetTicks();
                  Uint32 dticks = ticks-prevticks;
                  prevticks = ticks;
                  for (it = puzzlePieces.begin(); it != puzzlePieces.end(); it++) {
                        f[i] += dticks*d[i];
                        float ff = M_PI*float(f[i]&65535)/65536.;
                        ff = sin(ff);
                        ff = ff*ff;
                        glColor4f(1,1,1,ff);
                        PuzzlePieceSprite *pp = *it;
                        pp->Move(Point(1024 / 2 + pp->tx - INTROIMGW/3,
                                                      80 + pp->ty 
                        ));
                        (*it)->Draw();
                        i++;
                  }
            }

            static Uint32 mark = 0;
            static int frames = 0;
            static bool strinited = 0;
            static char str[256];

            if (!strinited) {
                  strinited =1 ; strcpy(str,"----");
            }
            frames++;
            if (SDL_GetTicks()-mark>200)
            {
                  sprintf(str,"%f",float(frames)/(float(SDL_GetTicks()-mark)/1000.));
                  mark = SDL_GetTicks();
                  frames = 0;
            }

            glColor3f(0.9, 1, 1);
            DrawString(1024 / 2, 360, "Version 0.6.1", 80.f/256.f);
            glColor3f(1, 0.8, 0.2);
            DrawString(1024 / 2, 398, "http://www.resorama.com/jigzo/", 80.f/256.f);
            glColor3f(0.9, 1, 1);
            DrawString(1024 / 2, 450, "Options:", 92.f/256.f);
            char tmp[256];
            glColor3f(0.5, 0.5, 1);
            sprintf(tmp,"Rotating pieces: %s",rotateEnabled ? " ON" : "OFF");
            rotateOptionRect = DrawString(1024 / 2, 489, tmp, 80.f/256.f);
            glColor3f(0.7, 0.7, 0.8);
            DrawString(1024 / 2, 528, "(Hold Ctrl to rotate)", 80.f/256.f);
            glColor3f(0.5, 0.5, 1);
#ifdef ENABLE_SOUND
            if (soundFailed)
            {
                  sprintf(tmp,"Sound support failed");
            }else{
                  sprintf(tmp,"Sound: %s",soundEnabled ? " ON" : "OFF");
            }
#else
            sprintf(tmp,"Sound support not available");
#endif
            soundOptionRect = DrawString(1024 / 2, 570, tmp, 80.f/256.f);
            sprintf(tmp,"Connection tolerance: %s",
                        toleranceString[tolerance]);
            toleranceOptionRect = DrawString(1024 / 2, 613, tmp, 80.f/256.f);
            glColor3f(1, 0.8, 0.2);
            DrawString(1024 / 2, 680, "Press 'Esc' to quit", 92.f/256.f);
            glColor3f(0.9, 1, 1);
            DrawString(1024 / 2, 720, "SPACE brings bottom-piece to front",80.f/256.f);
            glColor3f(1, 0.8, 0.2);
            DrawString(1024 / 2, 770, "Click or press key to continue", 92.f/256.f);
            glColor3f(1, 1, 1);
            leave->Draw();
            arrow->Draw();
            return;
      }
      if (mode == start_browse)
      {
            ReadPreviews();
            mode = browse;
            FadeIn();
      }
      if (mode == end_browse) {
            FreePreviews();
            mode = next_mode;
            return;
      }
      if (mode == start_play)
      {
            ReadPuzzle(puzzlename);
            Randomize();
            mode = play;
            FadeIn();
            return;
      }
      if (mode == end_play)
      {
            FreePuzzle();
            mode = next_mode;
            return;
      }
      if (mode == play)
      {

            std::list < PuzzlePieceSprite * >::iterator it;
            for (it = drawOrder.begin(); it != drawOrder.end(); it++) {
                  glColor3f(1,1,1);
                  (*it)->RotatedDraw();
            }
            std::list < PuzzlePieceSprite * >tmp;
            for (it = drawOrder.begin(); it != drawOrder.end();) {
                  PuzzlePieceSprite* piece = *it;
                  it++;
                  if (piece->fadestart!=0)
                  {
                        float f= float(SDL_GetTicks() - piece->fadestart) / 300.;
                        if (f>1.) {
                              f=1.;
                              piece->fadestart = 0;
                              drawOrder.remove(piece);
                              tmp.push_back(piece);
                        }
                        glColor4f(1,1,1,f);
                        piece->RotatedDraw();
                  }
            }
            for (it =tmp.begin(); it != tmp.end(); it++) {
                  PuzzlePieceSprite *piece = *it;
                  drawOrder.push_back(piece);
            }

            if (drawFoto) {
                  image->pos = grid[0][0].pos;
                  float f= float(SDL_GetTicks() - fotofade) / 1000.;
                  if (f>1.) f=1.;
                  glColor4f(1, 1, 1, f);
                  image->Draw();
            }
            glColor3f(1, 1, 1);
            leave->Draw();
            arrow->Draw();
      }
}
void Display(void)
{
      Display2();
      DrawFade();
}


void MouseMove(int x, int y, bool modifier)
{
      mouseX = x;
      mouseY = y;
      if (arrow)
            arrow->Move(Point(mouseX, mouseY));
      if (mode == intro) {
            return;
      }
      if (mode == browse)
            return;
      if (grab) {
            bool checkFinished = false;
            bool wasConnected = false;
            if (rotateEnabled && modifier)
            {
                  if (drawFoto==0)
                  {
                        float dx = mouseX - rotateX;
                        float dy = mouseY - rotateY;
                        float d;
                        if (fabs(dx) > fabs(dy)) {
                              d = dx;
                              rotateY = mouseY;
                        } else {
                              d = dy;
                              rotateX = mouseX;
                        }
                        d = float(int(d/3))/72.f * 2.f*M_PI;
                        grab->angle = grabangle + d;
                        while (grab->angle > M_PI) grab->angle -= 2.f*M_PI;
                        while (grab->angle < -M_PI) grab->angle += 2.f*M_PI;
                        if (fabs(grab->angle) < 0.00001)
                        {
                                    grab->angle = 0;
                                    checkFinished = true;
                        }
                  }
            }
            else
            {
                  grab->Move(Point(mouseX+grabdx, mouseY+grabdy));
            }
            std::list < PuzzlePieceSprite * >::iterator it;
            for (it = puzzlePieces.begin(); it != puzzlePieces.end(); it++)
            {
                  PuzzlePieceSprite *piece = *it;
                  Polygon grabPolygon(grab->GetRect());
                  Polygon piecePolygon(piece->GetRect());

                  grabPolygon.Rotate(grab->angle);
                  piecePolygon.Rotate(piece->angle);

                  Point d(grabPolygon[0].x - piecePolygon[0].x,grabPolygon[0].y - piecePolygon[0].y);

                  Point solution_d((piece->handle.x - piece->tx) - (grab->handle.x - grab->tx), (piece->handle.y - piece->ty) - (grab->handle.y - grab->ty));

                  if (rotateEnabled) d.Rotate(-grab->angle);

                  if (piece->group != grab->group)
                  {
                        Point dif(d.x - solution_d.x,d.y - solution_d.y);

                        float dangle = piece->angle - grab->angle;

                        while (dangle > M_PI)
                              dangle -= 2.f*M_PI;
                        while (dangle < -M_PI)
                              dangle += 2.f*M_PI;

                        if (dif.Length()<toleranceLength[tolerance] && fabs(dangle) < toleranceAngle[tolerance])
                        {
                              if (GroupNeighbours(grab->group, piece->group))
                              {
                                    JoinGroups(grab->group, piece->group);
                                    checkFinished = true;
                                    wasConnected = true;
                                    GrabToFront();
                              }
                        }
                  }
                  if (piece != grab && piece->group == grab->group)
                  {
                        piece->angle = grab->angle;
                        if (fabs(grab->angle) < 0.00001)
                        {
                              d = solution_d;
                              piece->pos.x = grab->pos.x - d.x;
                              piece->pos.y = grab->pos.y - d.y;
                        } else {
                              grabPolygon = Polygon(grab->GetRect());
                              grabPolygon.Rotate(grab->angle);
                              d = solution_d;
                              d.Rotate(grab->angle);
                              piecePolygon = Polygon(
                                          Rect(
                                                grabPolygon[0].x - d.x,
                                                grabPolygon[0].y - d.y,
                                                piece->GetRect().w,
                                                piece->GetRect().h
                                          ));
                              piecePolygon.Rotate(piecePolygon[0],grab->angle);
                              piecePolygon.Rotate(-grab->angle);
                              piece->pos = piecePolygon[0];
                        }
                  }
            }
            if (checkFinished)
            {
                  if (Finished())
                  {
                        fotofade = SDL_GetTicks();
                        drawFoto = 1;
#ifdef ENABLE_SOUND
                        if (mixChunkFinish)
                              Mix_PlayChannel(-1, mixChunkFinish, 0);
#endif                     
                  }else{
#ifdef ENABLE_SOUND
                        if (wasConnected)
                              if (mixChunkConnect)
                                    Mix_PlayChannel(-1, mixChunkConnect, 0);
#endif                     
                  }
            }
      }
}

bool clickLeave = false;

void MouseClick(void)
{
      if (mode == browse) {
            {
                  std::list < PreviewSprite * >::iterator it;
                  for (it = previews.begin(); it != previews.end(); it++) {
                        PreviewSprite *s = *it;
                        if (arrow->pos.x - arrow->handle.x >= s->pos.x
                                    && arrow->pos.y - arrow->handle.y >= s->pos.y
                                    && arrow->pos.x - arrow->handle.x <=
                                    s->pos.x + s->GetRect().w
                                    && arrow->pos.y - arrow->handle.y <=
                                    s->pos.y + s->GetRect().h) {
                              puzzlename = s->name;
                              FadeOutTo(end_browse,start_play);
                        }
                  }
            }
            {
                  std::vector < FolderSprite* >::iterator it;
                  for (it = folders.begin(); it != folders.end(); it++) {
                        FolderSprite*s = *it;
                        if (arrow->pos.x - arrow->handle.x >= s->pos.x
                                    && arrow->pos.y - arrow->handle.y >= s->pos.y
                                    && arrow->pos.x - arrow->handle.x <=
                                    s->pos.x + s->GetRect().w
                                    && arrow->pos.y - arrow->handle.y <=
                                    s->pos.y + s->GetRect().h) {
                              nextPreviewFolder = s->id;
                              FadeOutTo(end_browse,start_browse);
                        }
                  }
            }
      }
      if (mode == play) {
            std::list < PuzzlePieceSprite * >::iterator it;
            float min_d = 1000.;
            for (it = puzzlePieces.begin(); it != puzzlePieces.end(); it++) {
                  PuzzlePieceSprite *piece = *it;
                  float dx =
                        piece->pos.x + piece->handle.x -
                        arrow->pos.x - arrow->handle.x;
                  float dy =
                        piece->pos.y + piece->handle.y -
                        arrow->pos.y - arrow->handle.y;
                  float d = sqrt(dx*dx+dy*dy);
                  if (dx > -aw / 2 && dx < aw / 2 && dy > -ah / 2 && dy < ah / 2) {
                        if (d<min_d)
                        {
                              grab = piece;
                              grabdx = int(dx + 0.5f);
                              grabdy = int(dy + 0.5f);
                              rotateX = arrow->pos.x - arrow->handle.x;
                              rotateY = arrow->pos.y - arrow->handle.y;
                              grabangle = piece->angle;
                              min_d = d;
                        }
                  }
            }
            GrabToFront();
            if (grab) prevticks = SDL_GetTicks();
      }
      {
            Sprite* s = leave;
            if (arrow->pos.x - arrow->handle.x >= s->pos.x
                        && arrow->pos.y - arrow->handle.y >= s->pos.y
                        && arrow->pos.x - arrow->handle.x <=
                        s->pos.x + s->GetRect().w
                        && arrow->pos.y - arrow->handle.y <=
                        s->pos.y + s->GetRect().h) {
                  clickLeave=true;
            }
      }
      if (mode == intro) {
            Point pt = arrow->pos - arrow->handle;
            if (rotateOptionRect.Contains(pt))
            {
                  rotateEnabled = !rotateEnabled;
            }
            else
            if (soundOptionRect.Contains(pt))
            {
                  SetSound(!soundEnabled);
            }
            else
            if (toleranceOptionRect.Contains(pt))
            {
                  tolerance = (tolerance+1)%3;
            }
            else
            if (!clickLeave)
            {
                  FadeOutTo(end_intro,start_browse);
            }
      }
}

void usage(void)
{
      printf("jigzo, an OpenGL jigsaw game\n\n");
      printf("version 0.4\n\n");
      printf("http://www.resorama.com/jigzo/\n\n");
      printf
      ("Copyright (C) 2005-2008   Maarten de Boer <maarten@resorama.com>\n\n");
      printf("Usage: jigzo [-h | -w]\n\n");
      printf("  -h   show this usage info\n");
      printf("  -w   window mode (default is fullscreen)\n");
      printf("\n");
      printf
      ("jigzo requires a OpenGL hardware accelaration and runs at 1024x768 only\n\n");
#ifndef ENABLE_SOUND
      printf("Sound support disabled at compilation\n\n");
#endif
      
      exit(0);
}

int main(int argc, char **argv)
{
      time_t t;
      time(&t);
      srand(t);
      try {
            bool fullscreen = true;
            mode = start_intro;

            string argv0(argv[0]);

#ifdef WIN32
            unsigned int slashpos = argv0.rfind("\\");
#else

            unsigned int slashpos = argv0.rfind("/");
#endif

            if (slashpos != string::npos) {
                  string dir = argv0.substr(0, slashpos);
                  chdir(dir.c_str());
            }


            if (argc > 1) {
                  if (argc > 2)
                        usage();
                  if (string(argv[1]) == "-h")
                        usage();
                  if (string(argv[1]) == "-w")
                        fullscreen = false;
            }

            // todo: for non 4/3 resolution, the contents should be
            // repositioned
            int w = 1024;
            int h = 768;
            float ar = float(w)/float(h);
            float glhf = sqrt(1024.f*768.f/ar);
            float glwf = glhf*ar;
            int glw = int(glwf+0.5f);
            int glh = int(glhf+0.5f);
            INTERPOLATION = GL_LINEAR;
            //if (w==glw && h==glh) INTERPOLATION = GL_NEAREST;
            //else INTERPOLATION = GL_LINEAR;

            Screen s(w, h, glw, glh);
            s.DoubleBuffer();
            if (fullscreen)
                  s.FullScreen();
            s.Init();

            glGenTextures(1, &global_gl_texture);

            SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);

            SetSound(true);

            FadeIn();

            SDL_ShowCursor(0);
            int i;
            Uint8 *keys = SDL_GetKeyState(&i);
            SDL_Event event;
            while (mode!=end) {
                  //static Uint32 mark = 0;
                  SDL_Delay(10);
                  while (SDL_PollEvent(&event)) {
                        clickLeave = false;
                        if (event.type == SDL_MOUSEBUTTONDOWN) {
                              MouseClick();
                        }
                        if (event.type == SDL_MOUSEBUTTONUP)
                              grab = 0;
                        if (event.type == SDL_MOUSEMOTION) {
                              MouseMove(event.motion.x, event.motion.y,
                                    keys[SDLK_LCTRL] |
                                    keys[SDLK_RCTRL] |
                                    keys[SDLK_LALT] |
                                    keys[SDLK_RALT]
                              );
                        }
                        if (event.type == SDL_KEYDOWN) {
                              if (keys[SDLK_ESCAPE] || keys['q']) {
                                    clickLeave = true;
                              } else {
                                    if (mode == play )
                                    {
                                          if (keys['f'] || keys[' ']) {
                                                if (drawOrder.front()->fadestart==0)
                                                {
                                                      drawOrder.front()->fadestart=SDL_GetTicks();
                                                }
                                          }
                                    }
                                    if (mode == intro) {
                                          FadeOutTo(end_intro,start_browse);
                                    }
                              }
                        }
                        if (clickLeave)
                        {
                              if (mode == intro)
                                    FadeOutTo(end_intro,end);
                              else if (mode == browse) {
                                    FadeOutTo(end_browse,start_intro);
                              } else {
                                    FadeOutTo(end_play,start_browse);
                              }
                        }
                        if (event.type == SDL_QUIT) {
                              mode = end;
                              break;
                        }
                  }

                  s.Flip();
                  Display();
            }

            s.Exit();

      } catch (LoaderException& e) {
            fprintf(stderr,e.what());
      }

      return 0;
}


Generated by  Doxygen 1.6.0   Back to index