root/trunk/BMP.cpp

Revision 14, 10.9 kB (checked in by sagrer, 4 months ago)

Поковырял код на предмет понять "где что есть". Заодно добавил везде шапку и вбил дополнительно в конфиг проекта те модули, которые вбиты не были - чтобы можно было быстро открыть любой файл через окно менеджера проекта.

Line 
1 ///////////////////////////////////////////////////////////
2 //                        TexGen                         //
3 //          утилита для подготовки текстур рельефа       //
4 //               для игры Проклятые Земли                //
5 //           Copyright (C) 2007-2008 Gipat Group         //
6 //              Распространяется на условиях             //
7 //    Gipat Group's opened EI-editor-utility license     //
8 //                      версии 1.0                       //
9 //                                                       //
10 //                  www.gipatgroup.org                   //
11 ///////////////////////////////////////////////////////////
12
13 //К работе над данным файлом приложили руки, ноги.... короче аффтары:
14 // 1) Снайпер (sniper-rifle@rambler.ru)
15
16 ////////////////////////////////////////////////////////////////////////
17
18 #include <vcl.h>
19 #include "BMP.h"
20 //------------------------------------------------
21 CBitMap::CBitMap(int XSize, int YSize, ColorRGB Clr)
22 //Дефолтный конструктор битмапы. Создаёт картинку XSize*YSize, и заливает её цветом Clr.
23 {
24   H = YSize;
25   W = XSize;
26   DeltaZero=W%4;
27   Inited = true;
28   Buffer = new byte[PicWeight()]; //Создаём в дин. памяти кусок под картинку
29   int Cursor = 0;   //Чтоб не гемориться с формулами, просто сдвигаем курсор на 1.
30   for(int i=0;i<H;i++)
31   {
32     for(int j=0;j<W;j++)
33     {
34       memcpy(Buffer + Cursor++,&Clr.Blue,1);
35       memcpy(Buffer + Cursor++,&Clr.Green,1);
36       memcpy(Buffer + Cursor++,&Clr.Red,1);
37     }
38     Cursor += DeltaZero;
39   }
40 }
41 //------------------------------------------------
42 void CBitMap::Save(AnsiString FName)
43 {
44   if(Inited)
45   {
46 //    FILE *f;
47     int Handler;
48     AnsiString Buf = "BM****####****[SZ][WI][HE]01240000[SI]0000000000000000";
49     int BufSize = PicWeight(), BL = 54,BL1=BL+BufSize, Zero=0;
50     short int A1=1, A2=24,XYPM = 2834;
51
52     Buf.SetLength(BL + BufSize);
53
54
55     memcpy(&Buf[3],&BL1,4);
56     memcpy(&Buf[11],&BL,4);
57     memcpy(&Buf[7],&Zero,4);
58
59     BL = 40;
60     memcpy(&Buf[15],&BL,4);
61     memcpy(&Buf[19],&W,4);
62     memcpy(&Buf[23],&H,4);
63    // BL = 1;
64     memcpy(&Buf[27],&A1,2);
65    // BL = 24;
66     memcpy(&Buf[29],&A2,2);
67     memcpy(&Buf[31],&Zero,4);
68     memcpy(&Buf[35],&BufSize,4);
69     memcpy(&Buf[39],&XYPM,4);
70     memcpy(&Buf[43],&XYPM,4);
71     memcpy(&Buf[47],&Zero,4);
72     memcpy(&Buf[51],&Zero,4);
73
74     memcpy(&Buf[55],Buffer,BufSize);
75   //----------
76     Handler = FileCreate(FName,fmOpenWrite);
77     if(Handler)
78     {
79       FileWrite(Handler,&Buf[1],Buf.Length());
80       FileClose(Handler);
81     }
82 //    f = fopen(FName.c_str(),"w");
83 //    fwrite(&Buf[1],Buf.Length(),1,f);
84 //    fclose(f);
85   }
86 }
87 //---- --------------------------------------------
88 CBitMap::CBitMap(AnsiString FName)
89 {
90   //-------------------------
91   Inited = false;
92   //FILE *f;
93   //f=fopen(FName.c_str(),"r");
94   //fseek(f,0,SEEK_END);
95   int Hnd=FileOpen(FName,fmOpenRead);
96   if(Hnd > 0)
97   {
98     int L = FileSeek(Hnd,0,SEEK_END);
99     int bfOffBits;
100     //fseek(f,0,SEEK_SET);
101     FileSeek(Hnd,0,SEEK_SET);
102     byte *BUF=new byte[L];
103     FileRead(Hnd,BUF,L);
104     FileClose(Hnd);
105     //fread(BUF,L,1,f);
106     //fclose(f);
107     //--------------------------
108     //Загрузили, теперь запихиваем данные в объект класса CBitMap
109     AnsiString TMP="**";
110     memcpy(&TMP[1],BUF,2);
111     if(TMP=="BM")
112     {
113       memcpy(&bfOffBits,BUF+10,4);//Оффсет типа %)
114       memcpy(&W,BUF+18,4);//Width
115       memcpy(&H,BUF+22,4);//Height
116       memcpy(&D,BUF+28,2);//Depth
117       DeltaZero = W%4;//Подбираем кол-во нулей...
118       int PW = PicWeight();//, TEST = L - PW;
119       if(D==24)
120       {
121         int C;
122         memcpy(&C,BUF+30,4);
123         if(C==0) //Compression
124         {
125           memcpy(&RealSize,BUF+34,4);
126
127           Buffer = new byte[PW];
128           memcpy(Buffer,BUF+bfOffBits,PW);
129           Inited = true;
130         }
131         else
132         {
133           ShowMessage("Обнаружено сжатие. Сжатие не поддерживается!");
134         }
135       }
136       else
137       {
138         ShowMessage("Файл не является 24-битным точечным рисунком:\r\n"+FName+"\r\nКласс поддерживает только 24-битные точечные рисунки!");
139       }
140     }
141     else
142     {
143       ShowMessage("Файл не является точечным рисунком:\r\n"+FName+"\r\nПервые 2 байта должны быть равны \"BM\", а остальное я не проверял и не думаю проверять...");
144     }
145     delete [] BUF;
146   }
147   else
148   {
149     ShowMessage("Не удалось открыть файл "+FName+"!");
150   }
151 }
152
153 CBitMap::ColorRGB CBitMap::GetPixel(int X, int Y)
154 {
155   bool Match = (X >= 0)&&(X<W)&&(Y>=0)&&(Y<H)&&Inited;
156   ColorRGB Rez;
157   if(Match)
158   {
159     memcpy(&Rez.Blue, Buffer+Y*(W*3+DeltaZero)+X*3+0,1);
160     memcpy(&Rez.Green,Buffer+Y*(W*3+DeltaZero)+X*3+1,1);
161     memcpy(&Rez.Red,  Buffer+Y*(W*3+DeltaZero)+X*3+2,1);
162   }
163   else
164   {
165     Rez.Red = Rez.Green = Rez.Blue = 0;
166   }
167   return Rez;
168 }
169
170 void CBitMap::SetPixel(int X, int Y, ColorRGB Clr)
171 {
172   bool Match = (X >= 0)&&(X<W)&&(Y>=0)&&(Y<H);
173   if(Match)
174   {
175     memcpy(Buffer+Y*(W*3+DeltaZero)+X*3+0,&Clr.Blue ,1);
176     memcpy(Buffer+Y*(W*3+DeltaZero)+X*3+1,&Clr.Green,1);
177     memcpy(Buffer+Y*(W*3+DeltaZero)+X*3+2,&Clr.Red  ,1);
178   }
179 }
180
181 void CBitMap::Paste(int X, int Y, CBitMap *BMP)
182 {
183   bool Match = (X<W)&&(Y<H)&&(X+BMP->W >= 0)&&(Y+BMP->H >= 0)&&Inited&&(BMP->Inited);
184   if(Match)
185   {
186     // Координаты по оси X
187     int Xdest,Xsrc,Sdest,Ssrc;
188     //Определить, в какую точку 1-й картинки Xdest надо копировать строку
189     Xdest = (X>=0)?X:0;
190     //Определить, с какой точки 2-й картинки Xsrc надо брать информацию
191     Xsrc = (X>=0)?0:-X;
192     //Sdest - это длина строки, которая использована в первой картинке
193     Sdest = W-Xdest;
194     //Ssrc - это длина строки, которая берётся из второй картинки
195     Ssrc = BMP->W - Xsrc;
196     if(Ssrc>Sdest)Ssrc=Sdest;// На случай, если пихаемый кусок больше места для него.
197
198     //Координаты по оси Y
199     int Ydest,Ysrc, Rdest, Rsrc;
200     //Определить, с какой строки "картинки назначения" начинать вставку
201     Ydest = (Y>=0)?Y:0;
202     //С какой строки второй картинки начинать копирование данных
203     Ysrc = (Y>=0)?0:-Y;
204     //Rdest - диапазон строк, свободных для вставки в них
205     Rdest = H-Ydest;
206     //Rsrc - диапазон строк, доступных для чтения оттуда
207     Rsrc = BMP->H - Ysrc;
208     if(Rsrc>Rdest)Rsrc=Rdest;//Опять же, чтоб без переполнений...
209
210     //Сам процесс копирования:
211     byte *TempStr = new byte[Ssrc*3];//Кусок памяти под копируемую строку.
212     for(int i=0;i<Rsrc;i++)
213     {
214       memcpy(TempStr,BMP->Buffer+(Ysrc+i)*(BMP->W*3+BMP->DeltaZero)+Xsrc*3,Ssrc*3); //Это строка номер i
215       memcpy(Buffer+(Ydest+i)*(W*3+DeltaZero)+Xdest*3,TempStr,Ssrc*3);//Кидаем её куда надо...
216     }
217     delete [] TempStr;
218   }
219 }
220
221 void CBitMap::Copy (int X,int Y,CBitMap *BMP)
222 {
223   Paste(-X,-Y,BMP);
224 }
225
226 void CBitMap::Paste(int X,int Y, CBitMap *BMP, CBitMap *Mask, ColorRGB SolidColor)
227 {
228   //Здесь процедура сложнее. Придётся пробежаться по всей картинке, сравнивая попиксельно.
229   for(int xx=0;xx<Width();xx++)
230     for(int yy=0;yy<Height();yy++)
231     {
232       //Проверяем, подходит точка к картинке BMP и на месте ли она у нашей картинки
233       if((xx>=X)&&(yy>=Y)&&(xx-X<BMP->Width())&&(yy-Y<BMP->Height()))
234       {
235         //Сравниваем цвет маски (маска по размеру равна this)
236         if(Mask->GetPixel(xx,yy)==SolidColor)
237         {
238           //Тыкнем сюда таким же пикселем. Тупо, но ничего умнее мне в час ночи в голову не лезет.
239           SetPixel(xx,yy,BMP->GetPixel(xx-X,yy-Y));
240         }
241       }
242     }
243 }
244 //---------------------------------------------------------------------------
245 void CBitMap::Paste(int X,int Y, CBitMap *B1, CBitMap *B2, CBitMap *B3, CTileMask *M)
246 {
247   //B0 = this по умолчанию.
248   if((M->Width() == Width())&&(M->Height() == Height())) //Маска по размеру равна нашему рисунку
249   {
250     ColorRGB Tmp, Rez;
251     int TmpR, TmpG, TmpB;
252     byte *dwTmp = new byte[4];
253     for(int xx=0;xx<Width();xx++)
254       for(int yy=0;yy<Height();yy++)
255       {
256         M->GetPointW(xx,H-yy-1,dwTmp);
257         //1-я картинка
258         Tmp = GetPixel(xx,yy);
259         TmpR = Tmp.Red * dwTmp[0];
260         TmpG = Tmp.Green * dwTmp[0];
261         TmpB = Tmp.Blue * dwTmp[0];
262         //2-я картинка
263         if(B1 != NULL)
264         {
265           Tmp = B1->GetPixel(xx-X,yy-Y);
266           TmpR += Tmp.Red * dwTmp[1];
267           TmpG += Tmp.Green * dwTmp[1];
268           TmpB += Tmp.Blue * dwTmp[1];
269         }
270         //3-я картинка
271         if(B2 != NULL)
272         {
273           Tmp = B2->GetPixel(xx-X,yy-Y);
274           TmpR += Tmp.Red * dwTmp[2];
275           TmpG += Tmp.Green * dwTmp[2];
276           TmpB += Tmp.Blue * dwTmp[2];
277         }
278         //4-я картинка
279         if(B3 != NULL)
280         {
281           Tmp = B3->GetPixel(xx-X,yy-Y);
282           TmpR += Tmp.Red * dwTmp[3];
283           TmpG += Tmp.Green * dwTmp[3];
284           TmpB += Tmp.Blue * dwTmp[3];
285         }
286         Rez.Red = TmpR / 64;
287         Rez.Green = TmpG / 64;
288         Rez.Blue = TmpB / 64;
289
290         SetPixel(xx,yy,Rez);
291       }
292     delete [] dwTmp;
293   }
294 }
295
296 //------------------------------------------------------------------------------
297 void CBitMap::Resize(int wSize, int hSize, bool Smooth)
298 {
299   //Процедура изменит размер изображения, растягивая или сжимая его в нужных пропорциях
300   if(Inited) //Если картинка нормальная
301   {
302     if((wSize>0)&&(hSize>0)) //И заданы не фконец идиоЦкие размеры
303     {
304       CBitMap *Temp = new CBitMap(wSize,hSize,Clr2RGB(0,0,0));
305       ColorRGB C1, C2; // Переменные под цвета пикселей, в случае конфлитных координат
306       float kX, kY;
307       int V1, V2;
308       for(int x=0;x<wSize;x++)
309       {
310         kX = (x)*W*1.0/wSize;
311         for(int y=0;y<hSize;y++)
312         {
313           kY = (y)*H*1.0/hSize;
314           if(Smooth)
315           {
316             C1 = GetPixel(floor(kX), floor(kY));
317             C2 = GetPixel(ceil(kX) , ceil(kY) );
318             V1 = floor((kX-floor(kX))*100);
319             V2 = 100 - V1;
320             Temp->SetPixel(x,y,MergePixel(C1,C2,V1,V2));
321           }
322           else
323           {
324             Temp->SetPixel(x,y,GetPixel(floor(kX), floor(kY)));
325           }
326         }
327       }
328       //Темп сгенерили, теперь присваиваем его нашей картинке
329       delete [] Buffer;
330       W = Temp->W;
331       H = Temp->H;
332       Buffer = new byte[PicWeight()];
333       memcpy(Buffer,Temp->Buffer,PicWeight());
334       delete Temp;
335     }
336   }
337 }
338 //------------------------------------------------------------------------------
339 CBitMap::ColorRGB CBitMap::MergePixel(ColorRGB P1, ColorRGB P2, int V1, int V2)
340 {
341   ColorRGB Rez;
342   Rez.Red   = ((V1/100)*P1.Red   + (V2/100)*P2.Red  );
343   Rez.Green = ((V1/100)*P1.Green + (V2/100)*P2.Green);
344   Rez.Blue  = ((V1/100)*P1.Blue  + (V2/100)*P2.Blue );
345   return Rez;
346 }
347 //------------------------------------------------------------------------------
348 int CBitMap::floor(float X)
349 {
350   return (int)X;
351 }
352 //------------------------------------------------------------------------------
353 int CBitMap::ceil (float X)
354 {
355   int rez=(X-floor(X)<0.001)?floor(X):floor(X+1);//0.001 - константа, эпсилон.
356   return rez;
357 }
Note: See TracBrowser for help on using the browser.