1 /************************************************************************
2  *                                                                      *
3  *  FreeSynd - a remake of the classic Bullfrog game "Syndicate".       *
4  *                                                                      *
5  *   Copyright (C) 2010  Benoit Blancard <benblan@users.sourceforge.net>*
6  *                                                                      *
7  *    This program is free software;  you can redistribute it and / or  *
8  *  modify it  under the  terms of the  GNU General  Public License as  *
9  *  published by the Free Software Foundation; either version 2 of the  *
10  *  License, or (at your option) any later version.                     *
11  *                                                                      *
12  *    This program is  distributed in the hope that it will be useful,  *
13  *  but WITHOUT  ANY WARRANTY;  without even  the implied  warranty of  *
14  *  MERCHANTABILITY  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  *
15  *  General Public License for more details.                            *
16  *                                                                      *
17  *    You can view the GNU  General Public License, online, at the GNU  *
18  *  project's  web  site;  see <http://www.gnu.org/licenses/gpl.html>.  *
19  *  The full text of the license is also included in the file COPYING.  *
20  *                                                                      *
21  ************************************************************************/
22 
23 #include "common.h"
24 #include "dirtylist.h"
25 
DirtyList(int screenWidth,int screenHeight)26 DirtyList::DirtyList(int screenWidth, int screenHeight) {
27     size_ = 0;
28     pHead_ = NULL;
29     screenWidth_ = screenWidth;
30     screenHeight_ = screenHeight;
31 }
32 
~DirtyList()33 DirtyList::~DirtyList() {
34     flush();
35 }
36 
createLink(int x,int y,int width,int height)37 DirtyList::Link * DirtyList::createLink(int x, int y, int width, int height) {
38     Link *l = new Link();
39     l->pNext = NULL;
40     l->pPrev = NULL;
41     l->element.x = x;
42     l->element.y = y;
43     l->element.width = width;
44     l->element.height = height;
45 
46     return l;
47 }
48 
addRect(int x,int y,int width,int height)49 void DirtyList::addRect(int x, int y, int width, int height) {
50 
51     if (x >= screenWidth_ || y >= screenHeight_ ) {
52         return;
53     }
54 
55     if (pHead_ == NULL) {
56         // Create new link
57         pHead_ = createLink(x, y, width, height);
58     } else {
59 
60         Link *pCurr = pHead_;
61         do {
62             if (pCurr->element.x <= x && pCurr->element.y <= y &&
63                 (pCurr->element.x + pCurr->element.width) >= (x + width) &&
64                 (pCurr->element.y + pCurr->element.height) >= (y + height)) {
65                 // Current rect is enclosing new rect so don't add new rect
66                 return;
67             } else if (pCurr->element.x > x && pCurr->element.y > y &&
68                 (pCurr->element.x + pCurr->element.width) < (x + width) &&
69                 (pCurr->element.y + pCurr->element.height) < (y + height)) {
70                 // Current rect is enclosed by new rect so remove it from the list
71                 Link *pToRemove = pCurr;
72                 if (pToRemove->pNext != NULL && pToRemove->pPrev != NULL) {
73                     // Current is between 2 links
74                     pToRemove->pPrev->pNext = pToRemove->pNext;
75                     pToRemove->pNext->pPrev = pToRemove->pPrev;
76                     pCurr = pToRemove->pNext;
77                 } else if (pToRemove->pPrev != NULL && pToRemove->pNext == NULL) {
78                     // We are on the last element of the list
79                     pToRemove->pPrev->pNext = NULL;
80                     pCurr = pToRemove->pPrev;
81                 } else if (pToRemove->pPrev == NULL && pToRemove->pNext != NULL) {
82                     // There no previous so we're on the head
83                     pHead_ = pCurr = pToRemove->pNext;
84                     pHead_->pPrev = NULL;
85                 } else {
86                     pCurr = NULL;
87                 }
88 
89                 // Delete current
90                 pToRemove->pNext = NULL;
91                 pToRemove->pPrev = NULL;
92                 delete pToRemove;
93                 size_--;
94             } else if (pCurr->pNext == NULL) {
95                 break;
96             } else {
97                 pCurr = pCurr->pNext;
98             }
99 
100         } while(pCurr != NULL);
101 
102         Link *l = createLink(x, y, width, height);
103         if (pCurr == NULL) {
104             pHead_ = l;
105         } else {
106             pCurr->pNext = l;
107             l->pPrev = pCurr;
108         }
109     }
110     size_++;
111 }
112 
getRectAt(int pos)113 DirtyRect * DirtyList::getRectAt(int pos) {
114     if (pHead_ && pos >= 0 && pos < size_) {
115         int i = 0;
116         Link * l = pHead_;
117         while (i < pos) {
118             l = l->pNext;
119             i++;
120         }
121         return &(l->element);
122     }
123 
124     return NULL;
125 }
126 
flush()127 void DirtyList::flush() {
128     size_ = 0;
129     if (pHead_) {
130         Link *pCurr = pHead_;
131         do {
132             Link *pNext = pCurr->pNext;
133             if (pNext) {
134                 pNext->pPrev = NULL;
135                 pCurr->pNext = NULL;
136             }
137             delete pCurr;
138             pCurr = pNext;
139         } while(pCurr != NULL);
140     }
141     pHead_ = NULL;
142 }
143 
intersectsList(int x,int y,int width,int height)144 bool DirtyList::intersectsList(int x, int y, int width, int height)
145 {
146     if (pHead_) {
147         Link * l = pHead_;
148         while (l) {
149             if ( !((x > l->element.x + l->element.width) ||
150                     (x + width < l->element.x) ||
151                     (y > l->element.y + l->element.height) ||
152                     (y + height < l->element.y)) ) {
153                 return true;
154             }
155 
156 
157             l = l->pNext;
158         }
159     }
160 
161     return false;
162 }
163