1 /*
2
3 Memonix, Viewizard Game Core ver 2.0
4 Copyright (c) 2001-2006 Michael Kurinnoy, Viewizard Games
5 All Rights Reserved.
6
7 Memonix game source codes available under "dual licensing" model.
8 The licensing options available are:
9
10 * Commercial Licensing. This is the appropriate option if you are creating proprietary
11 applications and you are not prepared to distribute and share the source code of your application.
12 Contact us for pricing at viewizard@viewizard.com
13
14 * Open Source Licensing. This is the appropriate option if you want to share the source code of
15 your application with everyone you distribute it to, and you also want to give them the right to share who uses it.
16 You should have received a copy of the GNU General Public License version 3 with this source codes. If not, see <http://www.gnu.org/licenses/>.
17
18 */
19
20
21 #include "../../Core.h"
22 #include "Texture.h"
23
24
25 extern int FilteringTexMan;
26 extern int Address_ModeTexMan;
27 extern BYTE ARedTexMan;
28 extern BYTE AGreenTexMan;
29 extern BYTE ABlueTexMan;
30
31 extern bool MipMap;
32 extern int AFlagTexMan;
33 extern bool AlphaTexMan;
34 void AttachTexture(eTexture* Texture);
35 void DetachTexture(eTexture* Texture);
36
37
38
39
40
41
42
43 //------------------------------------------------------------------------------------
44 // Освобождение памяти и удаление текстуры
45 //------------------------------------------------------------------------------------
vw_ReleaseTexture(eTexture * Texture)46 void vw_ReleaseTexture(eTexture* Texture)
47 {
48 // проверка входящих данных
49 if (Texture == 0) return;
50
51 // отключаем текстуру от менерджера текстур
52 DetachTexture(Texture);
53
54 // освобождаем память
55 if (Texture->OffsetID != 0) {vw_DeleteTexture(Texture->OffsetID);Texture->OffsetID=0;};
56 if (Texture->Name != 0) {delete [] Texture->Name; Texture->Name = 0;}
57 delete Texture; Texture = 0;
58 }
59
60
61
62
63
64
65 //------------------------------------------------------------------------------------
66 // Переработка размеров... ближайшая, большая четная или степень 2
67 //------------------------------------------------------------------------------------
power_of_two(int Num)68 static int power_of_two(int Num)
69 {
70 int value = 1;
71
72 while (value < Num)
73 {
74 value <<= 1;
75 }
76 return value;
77 }
Resize(BYTE ** DIB,eTexture * Texture)78 void Resize(BYTE **DIB, eTexture *Texture)
79 {
80 // берем размеры к которым нужно "подгонять"
81 int powWidth = power_of_two(Texture->Width);
82 int powHeight = power_of_two(Texture->Height);
83
84 // нужно ли обрабатывать вообще?
85 if (powWidth==Texture->Width && powHeight==Texture->Height) return;
86
87 BYTE *DIBtemp = *DIB;
88 *DIB = 0;
89 *DIB = new BYTE[powWidth*powHeight*Texture->Bytes];
90
91 // делаем все по цвету-прозначности + ставим все прозрачным
92 BYTE ColorF[4];
93 ColorF[0] = Texture->ARed;
94 ColorF[1] = Texture->AGreen;
95 ColorF[2] = Texture->ABlue;
96 ColorF[3] = 0;//если Texture->Bytes == 4, его возьмем
97 for (int i=0; i<powWidth*powHeight*Texture->Bytes; i+=Texture->Bytes)
98 {
99 memcpy(*DIB+i, ColorF, Texture->Bytes);
100 }
101
102
103 // находим отступ между строчками
104 int stride = Texture->Width * Texture->Bytes;
105 // должен быть приведен к DWORD построчно (чтобы не было проблем с нечетными данными)
106 while((stride % 4) != 0) stride++;
107
108
109 // вставляем исходный рисунок
110 for (int y=0; y<Texture->Height; y++)
111 {
112 int st1 = (y*(powWidth))*Texture->Bytes;
113 int st2 = (y*(stride));
114 memcpy(*DIB+st1, DIBtemp+st2, stride);
115 }
116
117
118
119 // меняем значения текстуры
120 Texture->Width = powWidth;
121 Texture->Height = powHeight;
122 // освобождаем память
123 delete [] DIBtemp;
124 }
125
126
127
128
129
130
131
132
133
134
135
136 //------------------------------------------------------------------------------------
137 // Растягивание картинки, нужно устанавливать дополнительно...
138 //------------------------------------------------------------------------------------
ResizeImage(int width,int height,BYTE ** DIB,eTexture * Texture)139 void ResizeImage(int width, int height, BYTE **DIB, eTexture *Texture)
140 {
141 if (width == Texture->Width && height == Texture->Height) return;
142
143 int i, j, x, y, offset_y, offset_x;
144
145 // переносим во временный массив данные...
146 BYTE *src = *DIB;
147 BYTE *dst = 0;
148 dst = new BYTE[width*height*Texture->Bytes];
149 if (dst == 0) return;
150
151 // растягиваем исходный массив (или сжимаем)
152 for (j=0; j<height; j++)
153 {
154 y = (j * Texture->Height) / height;
155 offset_y = y * Texture->Width;
156
157 for (i=0; i<width; i++)
158 {
159 x = (i * Texture->Width) / width;
160 offset_x = (offset_y + x) * Texture->Bytes;
161
162 dst[(i+j*width)*Texture->Bytes] = src[(x+y*Texture->Width)*Texture->Bytes];
163 dst[(i+j*width)*Texture->Bytes+1] = src[(x+y*Texture->Width)*Texture->Bytes+1];
164 dst[(i+j*width)*Texture->Bytes+2] = src[(x+y*Texture->Width)*Texture->Bytes+2];
165 if (Texture->Bytes == 4)
166 dst[(i+j*width)*Texture->Bytes+3] = src[(x+y*Texture->Width)*Texture->Bytes+3];
167 }
168 }
169
170 // меняем значения текстуры
171 Texture->Width = width;
172 Texture->Height = height;
173 // освобождаем память
174 delete [] src;
175 // устанавливаем указатель на новый блок памяти
176 *DIB = dst;
177 }
178
179
180
181
182
183
184
185
186
187 //------------------------------------------------------------------------------------
188 // Создание альфа канала
189 //------------------------------------------------------------------------------------
CreateAlpha(BYTE ** DIBRESULT,eTexture * Texture,int AlphaFlag)190 void CreateAlpha(BYTE **DIBRESULT, eTexture *Texture, int AlphaFlag)
191 {
192 // находим отступ между строчками
193 int stride = Texture->Width * 3;
194 while((stride % 4) != 0) stride++;
195 int stride2 = Texture->Width * 4;
196 while((stride2 % 4) != 0) stride2++;
197
198 // сохраняем во временном указателе
199 BYTE *DIBtemp = *DIBRESULT;
200 BYTE *DIB = new BYTE[stride2*Texture->Height];
201
202 int k1=0;
203 int k2=0;
204
205 // Формируем данные по цветам...
206 BYTE GreyRedC = (BYTE)(((float)Texture->ARed / 255) * 76);
207 BYTE GreyGreenC = (BYTE)(((float)Texture->AGreen / 255) * 150);
208 BYTE GreyBlueC = (BYTE)(((float)Texture->ABlue / 255) * 28);
209 BYTE GreyC = GreyBlueC+GreyGreenC+GreyRedC;
210
211 for(int j1 = 0; j1 < Texture->Height;j1++)
212 {
213
214 k1 = stride*j1;// делаем правильное смещение при переходе
215 k2 = stride2*j1;
216
217 for(int j2 = 0; j2 < Texture->Width;j2++)
218 {
219 DIB[k2] = DIBtemp[k1];
220 DIB[k2 + 1] = DIBtemp[k1 + 1];
221 DIB[k2 + 2] = DIBtemp[k1 + 2];
222
223 switch(AlphaFlag)
224 {
225 case TX_ALPHA_GREYSC:
226 {
227 // Формируем данные по цветам...
228 BYTE GreyRed = (BYTE)(((float)DIB[k2+2] / 255) * 76);
229 BYTE GreyGreen = (BYTE)(((float)DIB[k2+1] / 255) * 150);
230 BYTE GreyBlue = (BYTE)(((float)DIB[k2] / 255) * 28);
231 DIB[k2 + 3] = GreyBlue+GreyGreen+GreyRed;
232 break;
233 }
234 case TX_ALPHA_EQUAL:
235 {
236 if ((Texture->ABlue==DIB[k2])&(Texture->AGreen==DIB[k2+1])&(Texture->ARed==DIB[k2+2])) DIB[k2+3] = 0;//Alpha
237 else DIB[k2 + 3] = 255;
238 break;
239 }
240 case TX_ALPHA_GEQUAL:
241 {
242 // Формируем данные по цветам...
243 BYTE GreyRed = (BYTE)(((float)DIB[k2+2] / 255) * 76);
244 BYTE GreyGreen = (BYTE)(((float)DIB[k2+1] / 255) * 150);
245 BYTE GreyBlue = (BYTE)(((float)DIB[k2] / 255) * 28);
246 BYTE Grey = GreyBlue+GreyGreen+GreyRed;
247
248 if (GreyC >= Grey) DIB[k2+3] = 0;//Alpha
249 else DIB[k2 + 3] = 255;
250 break;
251 }
252 case TX_ALPHA_LEQUAL:
253 {
254 // Формируем данные по цветам...
255 BYTE GreyRed = (BYTE)(((float)DIB[k2+2] / 255) * 76);
256 BYTE GreyGreen = (BYTE)(((float)DIB[k2+1] / 255) * 150);
257 BYTE GreyBlue = (BYTE)(((float)DIB[k2] / 255) * 28);
258 BYTE Grey = GreyBlue+GreyGreen+GreyRed;
259
260 if (GreyC <= Grey) DIB[k2+3] = 0;//Alpha
261 else DIB[k2 + 3] = 255;
262 break;
263 }
264 case TX_ALPHA_GREAT:
265 {
266 // Формируем данные по цветам...
267 BYTE GreyRed = (BYTE)(((float)DIB[k2+2] / 255) * 76);
268 BYTE GreyGreen = (BYTE)(((float)DIB[k2+1] / 255) * 150);
269 BYTE GreyBlue = (BYTE)(((float)DIB[k2] / 255) * 28);
270 BYTE Grey = GreyBlue+GreyGreen+GreyRed;
271
272 if (GreyC > Grey) DIB[k2+3] = 0;//Alpha
273 else DIB[k2 + 3] = 255;
274 break;
275 }
276 case TX_ALPHA_LESS:
277 {
278 // Формируем данные по цветам...
279 BYTE GreyRed = (BYTE)(((float)DIB[k2+2] / 255) * 76);
280 BYTE GreyGreen = (BYTE)(((float)DIB[k2+1] / 255) * 150);
281 BYTE GreyBlue = (BYTE)(((float)DIB[k2] / 255) * 28);
282 BYTE Grey = GreyBlue+GreyGreen+GreyRed;
283
284 if (GreyC < Grey) DIB[k2+3] = 0;//Alpha
285 else DIB[k2 + 3] = 255;
286 break;
287 }
288 default:
289 {
290 DIB[k2 + 3] = 255;
291 break;
292 }
293
294 }
295
296 k2 += 4;
297 k1 += 3;
298 }
299 }
300
301 delete [] DIBtemp;
302 *DIBRESULT = DIB;
303 Texture->Bytes = 4;
304 }
305
306
307
308
309
310 //------------------------------------------------------------------------------------
311 // Удаляем альфа канал
312 //------------------------------------------------------------------------------------
DeleteAlpha(BYTE ** DIBRESULT,eTexture * Texture)313 void DeleteAlpha(BYTE **DIBRESULT, eTexture *Texture)
314 {
315
316 // находим отступ между строчками
317 int stride = Texture->Width * 3;
318 while((stride % 4) != 0) stride++;
319 int stride2 = Texture->Width * 4;
320 while((stride2 % 4) != 0) stride2++;
321
322 // сохраняем во временном указателе
323 BYTE *DIBtemp = *DIBRESULT;
324 BYTE *DIB = new BYTE[stride*Texture->Height];
325
326 int k1=0;
327 int k2=0;
328
329 for(int j1 = 0; j1 < Texture->Height;j1++)
330 {
331 k1 = stride*j1;
332 k2 = stride2*j1;
333
334 for(int j2 = 0; j2 < Texture->Width;j2++)
335 {
336 DIB[k1] = DIBtemp[k2];
337 DIB[k1 + 1] = DIBtemp[k2 + 1];
338 DIB[k1 + 2] = DIBtemp[k2 + 2];
339
340 k2 += 4;
341 k1 += 3;
342 }
343 }
344
345 delete [] DIBtemp;
346 *DIBRESULT = DIB;
347 Texture->Bytes = 3;
348 }
349
350
351
352
353
354
355
356
357
358
359
360
361 //------------------------------------------------------------------------------------
362 // проверка расширения файла
363 //------------------------------------------------------------------------------------
TestFileExtension(const char * name,char * extension)364 inline const char* TestFileExtension(const char *name, char *extension)
365 {
366 if(name==0||extension==0) return 0;
367 int LengthName=(int)strlen(name),LengthString=(int)strlen(extension);
368 if(LengthName<LengthString) return 0;
369 for(int i=LengthName-1;i>=0;i--)
370 if(name[i]=='.')
371 if(!strcmp(&name[i+1],extension)) return &name[i+1];
372 else return 0;
373 return 0;
374 }
375
376
377
378
379
380
381 //------------------------------------------------------------------------------------
382 // загрузка текстуры их файла и подключение к менеджеру текстур
383 //------------------------------------------------------------------------------------
vw_LoadTexture(const char * nName,int LoadAs,int NeedResizeX,int NeedResizeY)384 eTexture* vw_LoadTexture(const char *nName, int LoadAs, int NeedResizeX, int NeedResizeY)
385 {
386 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
387 // Cоздаем объект
388 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
389 eTexture *Texture;
390 Texture = new eTexture;
391
392
393 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
394 // Начальные установки текстуры
395 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
396 Texture->ARed = ARedTexMan;
397 Texture->AGreen = AGreenTexMan;
398 Texture->ABlue = ABlueTexMan;
399 Texture->Prev = 0;
400 Texture->Next = 0;
401 Texture->Num = 0;
402 Texture->Name = 0;
403 Texture->OffsetID = 0;
404 Texture->Filtering = FilteringTexMan;
405 Texture->Address_Mode = Address_ModeTexMan;
406 Texture->Width = 0;
407 Texture->Height = 0;
408 Texture->TexturePrior = 0;
409
410 // временно, файл текстуры
411 eFILE *pFile = 0;
412 // временно, получаем данные текстуры
413 SDL_Surface *image;
414 // временно, файл для работы
415 SDL_RWops *RWFile = 0;
416 // режим генерации текстуры
417 int Mode = 0;
418
419
420 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
421 // Сохраняем имя текстуры
422 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
423 Texture->Name = new char[strlen(nName)+1];
424 strcpy(Texture->Name, nName);
425
426
427 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
428 // Открываем файл
429 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
430 pFile = vw_fopen(Texture->Name);
431 RWFile = SDL_RWFromConstMem(pFile->Data, pFile->RealLength);
432
433
434 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
435 // Ищем как грузить текстуру по расширению
436 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
437 if (LoadAs == AUTO_FILE)
438 {
439 if( TestFileExtension( nName, "tga" ) || TestFileExtension( nName, "TGA" ))
440 LoadAs = TGA_FILE;
441 if( TestFileExtension( nName, "bmp" ) || TestFileExtension( nName, "BMP" ))
442 LoadAs = BMP_FILE;
443 if( TestFileExtension( nName, "jpg" ) || TestFileExtension( nName, "JPG" ))
444 LoadAs = JPG_FILE;
445 }
446
447
448 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
449 // Загружаем текстуру
450 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
451 switch(LoadAs)
452 {
453 case BMP_FILE:
454 image = IMG_LoadBMP_RW(RWFile);
455 break;
456
457 case TGA_FILE:
458 image = IMG_LoadTGA_RW(RWFile);
459 break;
460
461 case JPG_FILE:
462 image = IMG_LoadJPG_RW(RWFile);
463 break;
464
465 default:
466 return 0;
467 break;
468 }
469 if ( image == NULL )
470 {
471 printf("Unable to load %s: %s\n", nName, SDL_GetError());
472 return 0;
473 }
474
475
476
477
478 // ставим правильный порядок цветов для генерации текстуры
479 if (image->format->Rshift == 16 && image->format->Gshift == 8)
480 {
481 // order = BGR; BMP, TGA ...
482 // нужно сделать RGB
483
484 // находим отступ между строчками
485 int stride = image->w * image->format->BytesPerPixel;
486 // должен быть приведен к DWORD построчно (чтобы не было проблем с нечетными данными)
487 while((stride % 4) != 0) stride++;
488
489 BYTE *im_data = (BYTE *)image->pixels;
490 BYTE tmp_data;
491
492 int SM=0;
493 for(int j=0; j<image->h; j++)
494 {
495 for(int i=0; i<image->w; i++)
496 {
497 tmp_data = im_data[SM + i*image->format->BytesPerPixel];
498 im_data[SM + i*image->format->BytesPerPixel] = im_data[SM + i*image->format->BytesPerPixel+2];
499 im_data[SM + i*image->format->BytesPerPixel+2] = tmp_data;
500 }
501 SM += stride;
502 }
503
504 }
505
506
507 // вот теперь все готово, идем дальше
508 Texture->Width = image->w;
509 Texture->Height = image->h;
510 Texture->Bytes = image->format->BytesPerPixel;
511
512 // все, файлы нам больше не нужны
513 SDL_RWclose(RWFile);
514 vw_fclose(pFile);
515
516
517 // находим отступ между строчками
518 int stride = image->w * image->format->BytesPerPixel;
519 // должен быть приведен к DWORD построчно (чтобы не было проблем с нечетными данными)
520 while((stride % 4) != 0) stride++;
521
522 // нам нужно разрушать-создавать этот массив, по этому выносим его отдельно!
523 // иначе будут эксепшены, нельзя освободить память, зарезерв. в длл-ке
524 BYTE *tmp_image;
525 tmp_image = new BYTE[stride*Texture->Height];
526 memcpy(tmp_image, image->pixels, stride*Texture->Height);
527 SDL_FreeSurface(image);
528
529
530
531 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
532 // Делаем альфа канал
533 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
534 if (Texture->Bytes == 4)
535 {
536 if (!AlphaTexMan)
537 DeleteAlpha(&tmp_image, Texture);
538
539 }
540 if (Texture->Bytes == 3)
541 {
542 if (AlphaTexMan)
543 CreateAlpha(&tmp_image, Texture, AFlagTexMan);
544 }
545
546
547 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
548 // Растягиваем, если есть запрос
549 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
550 if (NeedResizeX!=0 && NeedResizeY!=0)
551 ResizeImage(NeedResizeX, NeedResizeY, &tmp_image, Texture);
552
553
554 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
555 // Сохраняем размеры картинки
556 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
557 Texture->SrcWidth = Texture->Width;
558 Texture->SrcHeight = Texture->Height;
559
560
561 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
562 // Делаем подгонку по размерам, с учетом необходимости железа
563 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
564 Resize(&tmp_image, Texture);
565
566
567
568 // нужно перевернуть
569 unsigned int iLineSize = sizeof(unsigned char) * Texture->Width * Texture->Bytes;
570 unsigned char *pLine1 = 0;
571 unsigned char *pLine2 = 0;
572 unsigned char *pTemp = 0;
573 pTemp = new unsigned char[Texture->Width * Texture->Bytes];
574 for (int i=0; i<Texture->Height / 2; i++)
575 {
576 // Set pointers to the lines that should be flipped
577 pLine1 = tmp_image + Texture->Width * Texture->Bytes * i;
578 pLine2 = tmp_image + Texture->Width * Texture->Bytes * (Texture->Height - i - 1);
579 // Copy Line1 into Temp
580 memcpy(pTemp, pLine1, iLineSize);
581 // Copy Line2 into Line1
582 memcpy(pLine1, pLine2, iLineSize);
583 // Copy Temp into into Line2
584 memcpy(pLine2, pTemp, iLineSize);
585 }
586 delete [] pTemp;
587
588
589
590 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
591 // Создаем текстуру
592 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
593 Texture->OffsetID = vw_CreateTexture(tmp_image, Texture->Width, Texture->Height, MipMap, Texture->Bytes);
594
595
596
597
598
599 ////////////////
600 /*
601 // проверка, что имеем...
602 FILE *f = fopen("123.bmp", "wb");
603
604
605 BITMAPINFOHEADER bih;
606 BITMAPFILEHEADER bfh;
607
608 int size = Texture->Width * Texture->Height * Texture->Bytes + sizeof(bfh) + sizeof(bih);
609
610 memset((void*)&bfh, 0, sizeof(bfh));
611 bfh.bfType = 'B'+('M'<<8);
612 bfh.bfSize = size;
613 bfh.bfOffBits = sizeof(bfh) + sizeof(bih);
614
615 memset((void*)&bih, 0, sizeof(bih));
616 bih.biSize = sizeof(bih);
617 bih.biWidth = Texture->Width;
618 bih.biHeight = Texture->Height;
619 bih.biPlanes = 1;
620 bih.biBitCount = (unsigned short)(Texture->Bytes * 8);
621 bih.biCompression = BI_RGB;
622
623
624 fwrite(&bfh, sizeof(bfh), 1, f);
625 fwrite(&bih, sizeof(bih), 1, f);
626 fwrite(tmp_image, Texture->Width * Texture->Height * Texture->Bytes, 1, f);
627
628 */
629 /*
630
631 if (!strcmp("DATA\\MODELS\\EARTHFIGHTER\\sf-illum01.tga", nName))
632 {
633 FILE *f = fopen("123.tga", "wb");
634
635 unsigned char tgaHeader[18];
636 memset(tgaHeader, 0, sizeof(tgaHeader));
637 tgaHeader[2] = 2;
638 tgaHeader[12] = (unsigned char)Texture->Width;
639 tgaHeader[13] = (unsigned char)((unsigned long)Texture->Width >> 8);
640 tgaHeader[14] = (unsigned char)Texture->Height;
641 tgaHeader[15] = (unsigned char)((unsigned long)Texture->Height >> 8);
642 tgaHeader[16] = Texture->Bytes*8;
643
644 int size = Texture->Width * Texture->Height * Texture->Bytes + 18;
645 fwrite(&tgaHeader, 18, 1, f);
646 fwrite(tmp_image, size, 1, f);
647
648
649 fclose(f);
650 }*/
651
652 ////////////////
653
654
655
656 // освобождаем память
657 delete [] tmp_image;
658
659 // присоединяем текстуру к менеджеру текстур
660 AttachTexture(Texture);
661 printf("Ok ... %s\n", Texture->Name);
662 return Texture;
663 }
664
665
666
667
668
669
670
671 //------------------------------------------------------------------------------------
672 // быстрая установка текстуры и ее параметров
673 //------------------------------------------------------------------------------------
vw_SetTextureT(DWORD Stage,eTexture * Tex)674 void vw_SetTextureT(DWORD Stage, eTexture *Tex)
675 {
676 if (Tex == 0) return;
677
678 vw_SetTextureV(Stage, Tex);
679 vw_SetTexFiltering(Stage, Tex->Filtering);
680 vw_SetTexAddressMode(Stage, Tex->Address_Mode);
681 vw_SetTexAlpha(true, 0.1f);
682 }
683