1
/************************************************************************************
3
AstroMenace (Hardcore 3D space shooter with spaceship upgrade possibilities)
4
Copyright © 2006-2012 Michael Kurinnoy, Viewizard
7
AstroMenace is free software: you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation, either version 3 of the License, or
10
(at your option) any later version.
12
AstroMenace 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
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with AstroMenace. If not, see <http://www.gnu.org/licenses/>.
21
Web Site: http://www.viewizard.com/
22
Project: http://sourceforge.net/projects/openastromenace/
23
E-mail: viewizard@viewizard.com
25
*************************************************************************************/
29
#include "../System/System.h"
30
#include "../RendererInterface/RendererInterface.h"
34
extern eDevCaps OpenGL_DevCaps;
36
extern eTexture *StartTexMan;
37
extern int FilteringTexMan;
38
extern int Address_ModeTexMan;
39
extern BYTE ARedTexMan;
40
extern BYTE AGreenTexMan;
41
extern BYTE ABlueTexMan;
44
extern int AFlagTexMan;
45
extern bool AlphaTexMan;
46
void vw_AttachTexture(eTexture* Texture);
47
void vw_DetachTexture(eTexture* Texture);
50
int ReadJPG(BYTE **DIB, eFILE *pFile, int *DWidth, int *DHeight, int *DChanels);
51
int ReadTGA(BYTE **DIB, eFILE *pFile, int *DWidth, int *DHeight, int *DChanels);
52
int ReadPNG(BYTE **DIB, eFILE *pFile, int *DWidth, int *DHeight, int *DChanels);
55
//------------------------------------------------------------------------------------
56
// Освобождение памяти и удаление текстуры
57
//------------------------------------------------------------------------------------
58
void vw_ReleaseTexture(eTexture* Texture)
60
// проверка входящих данных
61
if (Texture == 0) return;
63
// отключаем текстуру от менерджера текстур
64
vw_DetachTexture(Texture);
67
vw_DeleteTexture(Texture->TextureID);
68
if (Texture->Name != 0) {delete [] Texture->Name; Texture->Name = 0;}
69
if (Texture != 0){delete Texture; Texture = 0;}
77
//------------------------------------------------------------------------------------
78
// Переработка размеров... ближайшая, большая четная или степень 2
79
//------------------------------------------------------------------------------------
80
static int power_of_two(int Num)
90
void Resize(BYTE **DIB, eTexture *Texture)
92
// берем размеры к которым нужно "подгонять"
93
int powWidth = power_of_two(Texture->Width);
94
int powHeight = power_of_two(Texture->Height);
96
// нужно ли обрабатывать вообще?
97
if (powWidth==Texture->Width && powHeight==Texture->Height) return;
101
*DIB = new BYTE[powWidth*powHeight*Texture->Bytes]; if (*DIB == 0) return;
103
// делаем все по цвету-прозначности + ставим все прозрачным
105
ColorF[0] = Texture->ARed;
106
ColorF[1] = Texture->AGreen;
107
ColorF[2] = Texture->ABlue;
108
ColorF[3] = 0;//если Texture->Bytes == 4, его возьмем
109
for (int i=0; i<powWidth*powHeight*Texture->Bytes; i+=Texture->Bytes)
111
memcpy(*DIB+i, ColorF, Texture->Bytes);
115
// находим отступ между строчками
116
int stride = Texture->Width * Texture->Bytes;
117
// должен быть приведен к DWORD построчно (чтобы не было проблем с нечетными данными)
118
while((stride % 4) != 0) stride++;
121
// вставляем исходный рисунок
122
for (int y=0; y<Texture->Height; y++)
124
//int st1 = (y*(powWidth))*Texture->Bytes;
125
// чтобы правильно делать без SDL_image
126
int st1 = ((y + (powHeight - Texture->Height))*(powWidth))*Texture->Bytes;
127
int st2 = (y*(stride));
128
memcpy(*DIB+st1, DIBtemp+st2, stride);
131
// меняем значения текстуры
132
Texture->Width = powWidth;
133
Texture->Height = powHeight;
134
// освобождаем память
135
if (DIBtemp != 0){delete [] DIBtemp; DIBtemp = 0;}
148
//------------------------------------------------------------------------------------
149
// Растягивание картинки, нужно устанавливать дополнительно...
150
//------------------------------------------------------------------------------------
151
void ResizeImage(int width, int height, BYTE **DIB, eTexture *Texture)
153
if (width == Texture->Width && height == Texture->Height) return;
155
int i, j, x, y, offset_y, offset_x;
157
// переносим во временный массив данные...
160
dst = new BYTE[width*height*Texture->Bytes]; if (dst == 0) return;
162
// растягиваем исходный массив (или сжимаем)
163
for (j=0; j<height; j++)
165
y = (j * Texture->Height) / height;
166
offset_y = y * Texture->Width;
168
for (i=0; i<width; i++)
170
x = (i * Texture->Width) / width;
171
offset_x = (offset_y + x) * Texture->Bytes;
173
dst[(i+j*width)*Texture->Bytes] = src[(x+y*Texture->Width)*Texture->Bytes];
174
dst[(i+j*width)*Texture->Bytes+1] = src[(x+y*Texture->Width)*Texture->Bytes+1];
175
dst[(i+j*width)*Texture->Bytes+2] = src[(x+y*Texture->Width)*Texture->Bytes+2];
176
if (Texture->Bytes == 4)
177
dst[(i+j*width)*Texture->Bytes+3] = src[(x+y*Texture->Width)*Texture->Bytes+3];
181
// меняем значения текстуры
182
Texture->Width = width;
183
Texture->Height = height;
184
// освобождаем память
185
if (src != 0){delete [] src; src = 0;}
186
// устанавливаем указатель на новый блок памяти
198
//------------------------------------------------------------------------------------
199
// Создание альфа канала
200
//------------------------------------------------------------------------------------
201
void CreateAlpha(BYTE **DIBRESULT, eTexture *Texture, int AlphaFlag)
203
// находим отступ между строчками
204
int stride = Texture->Width * 3;
205
if (Texture->Width != 2 && Texture->Width != 1)
206
while((stride % 4) != 0) stride++;
207
int stride2 = Texture->Width * 4;
208
while((stride2 % 4) != 0) stride2++;
210
// сохраняем во временном указателе
211
BYTE *DIBtemp = *DIBRESULT;
213
DIB = new BYTE[stride2*Texture->Height]; if (DIB == 0) return;
218
// Формируем данные по цветам...
219
BYTE GreyRedC = (BYTE)(((float)Texture->ARed / 255) * 76);
220
BYTE GreyGreenC = (BYTE)(((float)Texture->AGreen / 255) * 150);
221
BYTE GreyBlueC = (BYTE)(((float)Texture->ABlue / 255) * 28);
222
BYTE GreyC = GreyBlueC+GreyGreenC+GreyRedC;
224
for(int j1 = 0; j1 < Texture->Height;j1++)
227
k1 = stride*j1;// делаем правильное смещение при переходе
230
for(int j2 = 0; j2 < Texture->Width;j2++)
232
DIB[k2] = DIBtemp[k1];
233
DIB[k2 + 1] = DIBtemp[k1 + 1];
234
DIB[k2 + 2] = DIBtemp[k1 + 2];
238
case TX_ALPHA_GREYSC:
240
// Формируем данные по цветам...
241
BYTE GreyRed = (BYTE)(((float)DIB[k2+2] / 255) * 76);
242
BYTE GreyGreen = (BYTE)(((float)DIB[k2+1] / 255) * 150);
243
BYTE GreyBlue = (BYTE)(((float)DIB[k2] / 255) * 28);
244
DIB[k2 + 3] = GreyBlue+GreyGreen+GreyRed;
249
if ((Texture->ABlue==DIB[k2])&(Texture->AGreen==DIB[k2+1])&(Texture->ARed==DIB[k2+2])) DIB[k2+3] = 0;//Alpha
250
else DIB[k2 + 3] = 255;
253
case TX_ALPHA_GEQUAL:
255
// Формируем данные по цветам...
256
BYTE GreyRed = (BYTE)(((float)DIB[k2+2] / 255) * 76);
257
BYTE GreyGreen = (BYTE)(((float)DIB[k2+1] / 255) * 150);
258
BYTE GreyBlue = (BYTE)(((float)DIB[k2] / 255) * 28);
259
BYTE Grey = GreyBlue+GreyGreen+GreyRed;
261
if (GreyC >= Grey) DIB[k2+3] = 0;//Alpha
262
else DIB[k2 + 3] = 255;
265
case TX_ALPHA_LEQUAL:
267
// Формируем данные по цветам...
268
BYTE GreyRed = (BYTE)(((float)DIB[k2+2] / 255) * 76);
269
BYTE GreyGreen = (BYTE)(((float)DIB[k2+1] / 255) * 150);
270
BYTE GreyBlue = (BYTE)(((float)DIB[k2] / 255) * 28);
271
BYTE Grey = GreyBlue+GreyGreen+GreyRed;
273
if (GreyC <= Grey) DIB[k2+3] = 0;//Alpha
274
else DIB[k2 + 3] = 255;
279
// Формируем данные по цветам...
280
BYTE GreyRed = (BYTE)(((float)DIB[k2+2] / 255) * 76);
281
BYTE GreyGreen = (BYTE)(((float)DIB[k2+1] / 255) * 150);
282
BYTE GreyBlue = (BYTE)(((float)DIB[k2] / 255) * 28);
283
BYTE Grey = GreyBlue+GreyGreen+GreyRed;
285
if (GreyC > Grey) DIB[k2+3] = 0;//Alpha
286
else DIB[k2 + 3] = 255;
291
// Формируем данные по цветам...
292
BYTE GreyRed = (BYTE)(((float)DIB[k2+2] / 255) * 76);
293
BYTE GreyGreen = (BYTE)(((float)DIB[k2+1] / 255) * 150);
294
BYTE GreyBlue = (BYTE)(((float)DIB[k2] / 255) * 28);
295
BYTE Grey = GreyBlue+GreyGreen+GreyRed;
297
if (GreyC < Grey) DIB[k2+3] = 0;//Alpha
298
else DIB[k2 + 3] = 255;
314
if (DIBtemp != 0){delete [] DIBtemp; DIBtemp = 0;}
323
//------------------------------------------------------------------------------------
324
// Удаляем альфа канал
325
//------------------------------------------------------------------------------------
326
void DeleteAlpha(BYTE **DIBRESULT, eTexture *Texture)
329
// находим отступ между строчками
330
int stride = Texture->Width * 3;
331
while((stride % 4) != 0) stride++;
332
int stride2 = Texture->Width * 4;
333
while((stride2 % 4) != 0) stride2++;
335
// сохраняем во временном указателе
336
BYTE *DIBtemp = *DIBRESULT;
338
DIB = new BYTE[stride*Texture->Height]; if (DIB == 0) return;
343
for(int j1 = 0; j1 < Texture->Height;j1++)
348
for(int j2 = 0; j2 < Texture->Width;j2++)
350
DIB[k1] = DIBtemp[k2];
351
DIB[k1 + 1] = DIBtemp[k2 + 1];
352
DIB[k1 + 2] = DIBtemp[k2 + 2];
359
if (DIBtemp != 0){delete [] DIBtemp; DIBtemp = 0;}
371
//------------------------------------------------------------------------------------
372
// конвертирование в VW2D
373
//------------------------------------------------------------------------------------
374
void vw_ConvertImageToVW2D(const char *SrcName, const char *DestName)
382
int LoadAs = TGA_FILE;
384
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
386
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
387
pFile = vw_fopen(SrcName);
390
fprintf(stderr, "Unable to found %s\n", SrcName);
395
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
396
// Ищем как грузить по расширению
397
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
398
if( vw_TestFileExtension( SrcName, "tga" ) || vw_TestFileExtension( SrcName, "TGA" ))
404
if( vw_TestFileExtension( SrcName, "jpg" ) || vw_TestFileExtension( SrcName, "JPG" ))
410
if( vw_TestFileExtension( SrcName, "png" ) || vw_TestFileExtension( SrcName, "PNG" ))
418
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
420
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
424
ReadTGA(&tmp_image, pFile, &DWidth, &DHeight, &DChanels);
428
ReadJPG(&tmp_image, pFile, &DWidth, &DHeight, &DChanels);
432
ReadPNG(&tmp_image, pFile, &DWidth, &DHeight, &DChanels);
436
fprintf(stderr, "Unable to load %s\n", SrcName);
443
fprintf(stderr, "Unable to load %s\n", SrcName);
447
// все, файл нам больше не нужен
452
// записываем данные на диск
455
FileVW2D = SDL_RWFromFile(DestName, "wb");
456
// если не можем создать файл на запись - уходим
457
if (FileVW2D == NULL)
459
fprintf(stderr, "Can't create %s file on disk.\n", DestName);
463
// маркер файла 4 байта
464
char tmp1[5] = "VW2D";
465
SDL_RWwrite(FileVW2D, tmp1, 4, 1);
467
SDL_RWwrite(FileVW2D, &DWidth, sizeof(int), 1);
468
SDL_RWwrite(FileVW2D, &DHeight, sizeof(int), 1);
469
SDL_RWwrite(FileVW2D, &DChanels, sizeof(int), 1);
470
SDL_RWwrite(FileVW2D, tmp_image, DWidth*DHeight*DChanels, 1);
473
// освобождаем память
474
if (tmp_image != 0){delete [] tmp_image; tmp_image = 0;}
484
//------------------------------------------------------------------------------------
485
// загрузка текстуры из файла и подключение к менеджеру текстур
486
//------------------------------------------------------------------------------------
487
eTexture* vw_LoadTexture(const char *nName, const char *RememberAsName, bool NeedCompression, int LoadAs, int NeedResizeW, int NeedResizeH)
489
// временно, файл текстуры
497
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
499
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
500
pFile = vw_fopen(nName);
503
fprintf(stderr, "Unable to found %s\n", nName);
508
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
509
// Ищем как грузить текстуру по расширению
510
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
511
if (LoadAs == AUTO_FILE)
513
if( vw_TestFileExtension( nName, "tga" ) || vw_TestFileExtension( nName, "TGA" ))
519
if( vw_TestFileExtension( nName, "vw2d" ) || vw_TestFileExtension( nName, "VW2D" ))
525
if( vw_TestFileExtension( nName, "jpg" ) || vw_TestFileExtension( nName, "JPG" ))
531
if( vw_TestFileExtension( nName, "png" ) || vw_TestFileExtension( nName, "PNG" ))
540
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
541
// Загружаем текстуру
542
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
546
ReadTGA(&tmp_image, pFile, &DWidth, &DHeight, &DChanels);
550
ReadJPG(&tmp_image, pFile, &DWidth, &DHeight, &DChanels);
554
ReadPNG(&tmp_image, pFile, &DWidth, &DHeight, &DChanels);
558
// пропускаем заголовок "VW2D"
559
pFile->fseek(4, SEEK_SET);
561
pFile->fread(&DWidth, sizeof(int), 1);
563
pFile->fread(&DHeight, sizeof(int), 1);
564
// считываем кол-во каналов
565
pFile->fread(&DChanels, sizeof(int), 1);
566
// резервируем память
567
tmp_image = new BYTE[DWidth*DHeight*DChanels];
568
// считываем уже готовый к созданию текстуры массив
569
pFile->fread(tmp_image, DWidth*DHeight*DChanels, 1);
579
fprintf(stderr, "Unable to load %s\n", nName);
583
// все, файл нам больше не нужен
588
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
589
// Сохраняем имя текстуры
590
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
591
eTexture *Result = 0;
593
if (RememberAsName == NULL)
595
Result = vw_CreateTextureFromMemory(nName, tmp_image, DWidth, DHeight, DChanels, NeedCompression, NeedResizeW, NeedResizeH);
597
else // иначе, есть имя под которым надо запомнить
599
Result = vw_CreateTextureFromMemory(RememberAsName, tmp_image, DWidth, DHeight, DChanels, NeedCompression, NeedResizeW, NeedResizeH);
603
// освобождаем память
604
if (tmp_image != 0){delete [] tmp_image; tmp_image = 0;}
617
//------------------------------------------------------------------------------------
618
// создание текстуры из памяти
619
//------------------------------------------------------------------------------------
620
eTexture* vw_CreateTextureFromMemory(const char *TextureName, BYTE * DIB, int DWidth, int DHeight, int DChanels, bool NeedCompression, int NeedResizeW, int NeedResizeH)
622
// проверяем в списке, если уже создавали ее - просто возвращаем указатель
623
eTexture *Tmp = StartTexMan;
626
eTexture *Tmp1 = Tmp->Next;
627
if(vw_strcmp(Tmp->Name, TextureName) == 0)
629
printf("Texture already loaded: %s\n", TextureName);
636
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
638
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
639
eTexture *Texture = 0;
640
Texture = new eTexture; if (Texture == 0) return 0;
643
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
644
// Начальные установки текстуры
645
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
646
Texture->ARed = ARedTexMan;
647
Texture->AGreen = AGreenTexMan;
648
Texture->ABlue = ABlueTexMan;
653
Texture->TextureID = 0;
654
Texture->Width = DWidth;
655
Texture->Height = DHeight;
656
Texture->Bytes = DChanels;
658
// временный массив данных
660
tmp_image = new BYTE[DWidth*DHeight*DChanels];
661
memcpy(tmp_image, DIB, DWidth*DHeight*DChanels);
663
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
664
// Сохраняем имя текстуры
665
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
666
Texture->Name = new char[strlen(TextureName)+1]; if (Texture->Name == 0) return 0;
667
strcpy(Texture->Name, TextureName);
670
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
671
// Делаем альфа канал
672
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
673
if (Texture->Bytes == 4)
676
DeleteAlpha(&tmp_image, Texture);
679
if (Texture->Bytes == 3)
682
CreateAlpha(&tmp_image, Texture, AFlagTexMan);
686
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
687
// Растягиваем, если есть запрос
688
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
689
if (NeedResizeW!=0 && NeedResizeH!=0)
690
ResizeImage(NeedResizeW, NeedResizeH, &tmp_image, Texture);
693
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
694
// Сохраняем размеры картинки
695
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
696
Texture->SrcWidth = Texture->Width;
697
Texture->SrcHeight = Texture->Height;
700
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
701
// Делаем подгонку по размерам, с учетом необходимости железа
702
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
703
if (!OpenGL_DevCaps.TextureNPOTSupported) // если не поддерживаем - берем и сами растягиваем до степени двойки
704
Resize(&tmp_image, Texture);
707
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
709
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
710
Texture->TextureID = vw_BuildTexture(tmp_image, Texture->Width, Texture->Height, MipMap, Texture->Bytes, NeedCompression);
711
// устанавливаем параметры
712
vw_SetTextureFiltering(FilteringTexMan);
713
vw_SetTextureAddressMode(Address_ModeTexMan);
715
vw_BindTexture(0, 0);
717
// освобождаем память
718
if (tmp_image != 0){delete [] tmp_image; tmp_image = 0;}
720
// присоединяем текстуру к менеджеру текстур
721
vw_AttachTexture(Texture);
722
printf("Ok ... %s\n", TextureName);