00001
00002
00003
00004
00005
00006
00007
00009
00010 #include "utils.h"
00011 #include "tex_mgmt.h"
00012 #include <cassert>
00013 #include <cstdarg>
00014 #include <set>
00015 #include <math.h>
00016 #include "video.h"
00017 #include "gui.h"
00018 #include <fstream>
00019
00020
00021 using namespace hoa_video::private_video;
00022
00023
00024 namespace hoa_video
00025 {
00026
00027 using namespace std;
00028 using namespace hoa_utils;
00029
00030
00031
00032
00033
00034
00035
00036
00037 void GameVideo::_ConvertImageToGrayscale(const ImageLoadInfo& src, ImageLoadInfo &dst) const
00038 {
00039 if (!dst.width || !dst.height)
00040 return;
00041
00042
00043 uint8* src_pix = static_cast<uint8*>(src.pixels);
00044 uint8* src_end = static_cast<uint8*>(src.pixels) + (src.width * src.height * 4);
00045 uint8* dst_pix = static_cast<uint8*>(dst.pixels);
00046 uint8 value;
00047
00048 for (; src_pix<src_end; src_pix+=4,dst_pix+=4)
00049 {
00050 value = static_cast<uint8>((30 * *(src_pix) + 59 * *(src_pix+1) + 11 * *(src_pix+2))*0.01f);
00051 *dst_pix = *(dst_pix+1) = *(dst_pix+2) = value;
00052 *(dst_pix+3) = *(src_pix+3);
00053 }
00054 }
00055
00056
00057
00058
00059
00060
00061
00062
00063 void GameVideo::_RGBAToRGB (const private_video::ImageLoadInfo& src, private_video::ImageLoadInfo &dst) const
00064 {
00065 if (!dst.width || !dst.height)
00066 return;
00067
00068 uint8* pSrc = static_cast<uint8*>(src.pixels);
00069 uint8* pDst = static_cast<uint8*>(dst.pixels);
00070
00071 int32 iSrc;
00072 int32 iDst;
00073 for (int32 i=0; i<src.height*src.width; i++)
00074 {
00075 iSrc = 4 * i;
00076 iDst = 3 * i;
00077 pDst[iDst] = pSrc[iSrc];
00078 pDst[iDst+1] = pSrc[iSrc+1];
00079 pDst[iDst+2] = pSrc[iSrc+2];
00080 }
00081 }
00082
00083
00084
00085
00086
00087 bool GameVideo::GetImageInfo (const std::string& file_name, uint32 &rows, uint32& cols, uint32& bpp)
00088 {
00089
00090 size_t extpos = file_name.rfind('.');
00091
00092 if(extpos == string::npos)
00093 {
00094 if (VIDEO_DEBUG)
00095 cerr << "VIDEO ERROR: image file extension not specified when calling to GetImageInfo" << endl;
00096 return false;
00097 }
00098
00099 std::string extension = std::string(file_name, extpos, file_name.length() - extpos);
00100
00101 if(extension == ".jpeg" || extension == ".jpg")
00102 return _GetImageInfoJpeg(file_name, rows, cols, bpp);
00103 if(extension == ".png")
00104 return _GetImageInfoPng(file_name, rows, cols, bpp);
00105
00106 if (VIDEO_DEBUG)
00107 cerr << "VIDEO ERROR: image file extension not recognized when calling to GetImageInfo" << endl;
00108
00109 return false;
00110 }
00111
00112
00113
00114
00115
00116 bool GameVideo::_GetImageInfoPng (const std::string& file_name, uint32 &rows, uint32& cols, uint32& bpp)
00117 {
00118 FILE * fp = fopen(file_name.c_str(), "rb");
00119
00120 if(fp == NULL)
00121 return false;
00122
00123 uint8 test_buffer[8];
00124
00125 fread(test_buffer, 1, 8, fp);
00126 if(png_sig_cmp(test_buffer, 0, 8))
00127 {
00128 fclose(fp);
00129 return false;
00130 }
00131
00132 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL);
00133
00134 if(!png_ptr)
00135 {
00136 fclose(fp);
00137 return false;
00138 }
00139
00140 png_infop info_ptr = png_create_info_struct(png_ptr);
00141
00142 if(!info_ptr)
00143 {
00144 png_destroy_read_struct(&png_ptr, NULL, (png_infopp)NULL);
00145 fclose(fp);
00146 return false;
00147 }
00148
00149 if(setjmp(png_jmpbuf(png_ptr)))
00150 {
00151 png_destroy_read_struct(&png_ptr, NULL, (png_infopp)NULL);
00152 fclose(fp);
00153 return false;
00154 }
00155
00156 png_init_io(png_ptr, fp);
00157 png_set_sig_bytes(png_ptr, 8);
00158
00159 png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, NULL);
00160
00161 cols = info_ptr->width;
00162 rows = info_ptr->height;
00163 bpp = info_ptr->channels * 8;
00164
00165 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
00166 fclose (fp);
00167
00168 return true;
00169 }
00170
00171
00172
00173
00174
00175 bool GameVideo::_GetImageInfoJpeg (const std::string& file_name, uint32 &rows, uint32& cols, uint32& bpp)
00176 {
00177 FILE * infile;
00178
00179 if((infile = fopen(file_name.c_str(), "rb")) == NULL)
00180 return false;
00181
00182 jpeg_decompress_struct cinfo;
00183 jpeg_error_mgr jerr;
00184
00185 cinfo.err = jpeg_std_error(&jerr);
00186 jpeg_create_decompress(&cinfo);
00187
00188 jpeg_stdio_src(&cinfo, infile);
00189 jpeg_read_header(&cinfo, TRUE);
00190
00191 cols = cinfo.output_width;
00192 rows = cinfo.output_height;
00193 bpp = cinfo.output_components;
00194
00195 jpeg_destroy_decompress(&cinfo);
00196
00197 fclose(infile);
00198
00199 return true;
00200 }
00201
00202
00203
00204
00205
00206
00207
00208 bool GameVideo::LoadImage(ImageDescriptor &id)
00209 {
00210 if(id._animated)
00211 {
00212
00213 if (!_LoadImage(dynamic_cast<AnimatedImage &>(id)))
00214 {
00215 return false;
00216 }
00217
00218
00219 if (id.IsGrayScale())
00220 {
00221 dynamic_cast<AnimatedImage &>(id).EnableGrayScale();
00222 }
00223 }
00224 else
00225 {
00226
00227 if (!_LoadImage(dynamic_cast<StillImage &>(id)))
00228 {
00229 return false;
00230 }
00231
00232
00233 if (id.IsGrayScale())
00234 {
00235 dynamic_cast<StillImage &>(id).EnableGrayScale();
00236 }
00237 }
00238
00239 return true;
00240 }
00241
00242
00243
00244
00245
00246
00247
00248
00249 bool GameVideo::_LoadImage(AnimatedImage &id)
00250 {
00251 uint32 num_frames = static_cast<uint32>(id._frames.size());
00252
00253 bool success = true;
00254
00255
00256 for(uint32 frame = 0; frame < num_frames; ++frame)
00257 {
00258
00259
00260
00261
00262 bool need_to_load = id._frames[frame].image._elements.empty();
00263
00264 if(need_to_load)
00265 {
00266 success &= _LoadImage(id._frames[frame].image);
00267 }
00268 }
00269
00270 return success;
00271 }
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285 bool GameVideo::_LoadImage(StillImage &id)
00286 {
00287
00288 id._elements.clear();
00289
00290
00291 if(id._filename.empty())
00292 {
00293 ImageElement quad(NULL, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, id._width, id._height, id._color);
00294 id._elements.push_back(quad);
00295 return true;
00296 }
00297
00298
00299
00300 if(_images.find(id._filename) != _images.end())
00301 {
00302 Image *img = _images[id._filename];
00303
00304 if(!img)
00305 {
00306 if(VIDEO_DEBUG)
00307 cerr << "VIDEO ERROR: got a NULL Image from images map in LoadImage()" << endl;
00308 return false;
00309 }
00310
00311 if (img->ref_count == 0)
00312 {
00313
00314
00315 if(!img->texture_sheet->RestoreImage(img))
00316 return false;
00317 }
00318
00319 ++(img->ref_count);
00320
00321 if(id._width == 0.0f)
00322 id._width = (float) img->width;
00323 if(id._height == 0.0f)
00324 id._height = (float) img->height;
00325
00326 ImageElement element(img, 0, 0, 0.0f, 0.0f, 1.0f, 1.0f, id._width, id._height, id._color);
00327 id._elements.push_back(element);
00328
00329 return true;
00330 }
00331
00332
00333 bool success = _LoadImageHelper(id);
00334
00335 if(!success)
00336 {
00337 if(VIDEO_DEBUG)
00338 cerr << "VIDEO ERROR: in LoadImage() failed to load " << id._filename << endl;
00339 return false;
00340 }
00341
00342 return success;
00343 }
00344
00345
00346
00347
00348
00349
00350
00351
00352 bool GameVideo::LoadMultiImageFromNumberElements(std::vector<StillImage> &images, const std::string &file_name, const uint32 rows, const uint32 cols)
00353 {
00354
00355 uint32 image_rows, image_cols, bpp;
00356 GetImageInfo(file_name, image_rows, image_cols, bpp);
00357
00358
00359 if ((image_rows % rows) || (image_cols % cols))
00360 {
00361 if (VIDEO_DEBUG)
00362 cerr << "VIDEO ERROR: loading multi image, the size of the image (file) is not multiple of the size of the images (StillImage)" << endl;
00363 return false;
00364 }
00365
00366
00367 if (images.size()!= rows*cols)
00368 {
00369 images.resize(rows*cols);
00370 }
00371
00372
00373 float width ((float)image_cols / (float)cols);
00374 float height ((float)image_rows / (float)rows);
00375 for (std::vector<StillImage>::iterator it=images.begin(); it<images.end(); ++it)
00376 {
00377 if (it->_height == 0.0f)
00378 it->_height = height;
00379 if (it->_width == 0.0f)
00380 it->_width = width;
00381 }
00382
00383
00384 return _LoadMultiImage (images, file_name, rows, cols);
00385 }
00386
00387
00388
00389
00390
00391
00392 bool GameVideo::LoadMultiImageFromElementsSize(std::vector<StillImage> &images, const std::string &file_name, const uint32 width, const uint32 height)
00393 {
00394
00395 uint32 image_rows, image_cols, bpp;
00396 GetImageInfo(file_name, image_rows, image_cols, bpp);
00397
00398
00399 if ((image_rows % height) || (image_cols % width))
00400 {
00401 if (VIDEO_DEBUG)
00402 cerr << "VIDEO ERROR: loading multi image, the size of the image (file) is not multiple of the size of the images (StillImage)" << endl;
00403 return false;
00404 }
00405
00406 uint32 rows (image_rows / height);
00407 uint32 cols (image_cols / width);
00408
00409
00410
00411 if (images.size() != rows*cols)
00412 {
00413 images.resize(rows*cols);
00414 }
00415
00416
00417 for (std::vector<StillImage>::iterator it=images.begin(); it<images.end(); ++it)
00418 {
00419 if (it->_height == 0.0f)
00420 it->_height = (float)height;
00421 if (it->_width == 0.0f)
00422 it->_width = (float)width;
00423 }
00424
00425
00426 return _LoadMultiImage (images, file_name, rows, cols);
00427 }
00428
00429
00430
00431
00432
00433 bool GameVideo::_LoadMultiImage (std::vector <StillImage>& images, const std::string &file_name, const uint32& rows,
00434 const uint32& cols)
00435 {
00436 std::string tags;
00437 std::string s;
00438 uint32 current_image;
00439 uint32 x, y;
00440
00441 bool need_load = false;
00442
00443
00444 for (x=0; x<rows && !need_load; x++)
00445 {
00446 for (y=0; y<cols && !need_load; y++)
00447 {
00448 tags = "";
00449 DataToString(s,x);
00450 tags += "<X" + s + "_";
00451 DataToString(s,rows);
00452 tags += s + ">";
00453 DataToString(s,y);
00454 tags += "<Y" + s + "_";
00455 DataToString(s,cols);
00456 tags += s + ">";
00457
00458
00459
00460 if(_images.find(file_name+tags) == _images.end())
00461 {
00462 need_load = true;
00463 }
00464 }
00465 }
00466
00467
00468 private_video::MultiImageInfo info;
00469 if (need_load)
00470 {
00471 if(!_LoadRawImage(file_name, info.multi_image))
00472 return false;
00473
00474 info.image.width = info.multi_image.width / cols;
00475 info.image.height = info.multi_image.height / rows;
00476 info.image.pixels = (uint8 *) malloc(info.image.width*info.image.height*4);
00477 }
00478
00479
00480 for (x=0; x<rows; x++)
00481 {
00482 for (y=0; y<cols; y++)
00483 {
00484 DataToString(s,x);
00485 tags = "<X" + s + "_";
00486 DataToString(s,rows);
00487 tags += s + ">";
00488 DataToString(s,y);
00489 tags += "<Y" + s + "_";
00490 DataToString(s,cols);
00491 tags += s + ">";
00492
00493 current_image = x*cols + y;
00494
00495
00496 if(_images.find(file_name+tags) != _images.end())
00497 {
00498 images.at(current_image)._elements.clear();
00499
00500 Image *img = _images[file_name+tags];
00501
00502 if (!img)
00503 {
00504 if(VIDEO_DEBUG)
00505 cerr << "VIDEO ERROR: got a NULL Image from images map in LoadImage()" << endl;
00506
00507 if (info.multi_image.pixels)
00508 free (info.multi_image.pixels);
00509 if (info.image.pixels)
00510 free (info.image.pixels);
00511 return false;
00512 }
00513
00514 if (img->ref_count == 0)
00515 {
00516
00517
00518 if (!img->texture_sheet->RestoreImage(img))
00519 {
00520 if (info.multi_image.pixels)
00521 free (info.multi_image.pixels);
00522 if (info.image.pixels)
00523 free (info.image.pixels);
00524 return false;
00525 }
00526 }
00527
00528 ++(img->ref_count);
00529
00530 ImageElement element(img, 0, 0, 0.0f, 0.0f, 1.0f, 1.0f,
00531 images.at(current_image)._width, images.at(current_image)._height, images.at(current_image)._color);
00532 images.at(current_image)._elements.push_back(element);
00533 }
00534 else
00535 {
00536 images.at(current_image)._filename = file_name;
00537 images.at(current_image)._animated = false;
00538
00539 for (int32 i=0; i<info.image.height; i++)
00540 {
00541 memcpy ((uint8*)info.image.pixels+4*info.image.width*i, (uint8*)info.multi_image.pixels+(((x*info.multi_image.height/rows)+i)*info.multi_image.width+y*info.multi_image.width/cols)*4, 4*info.image.width);
00542 }
00543
00544
00545 Image *new_image = new Image(file_name, tags, info.image.width, info.image.height, false);
00546
00547
00548 TexSheet *sheet = _InsertImageInTexSheet(new_image, info.image, images.at(current_image)._is_static);
00549
00550 if (!sheet)
00551 {
00552
00553
00554
00555 if(VIDEO_DEBUG)
00556 cerr << "VIDEO_DEBUG: GameVideo::_InsertImageInTexSheet() returned NULL!" << endl;
00557
00558 if (info.multi_image.pixels)
00559 free (info.multi_image.pixels);
00560 if (info.image.pixels)
00561 free (info.image.pixels);
00562 return false;
00563 }
00564
00565 new_image->ref_count = 1;
00566
00567
00568 _images[file_name + tags] = new_image;
00569
00570
00571 ImageElement element(new_image, 0, 0, 0.0f, 0.0f, 1.0f, 1.0f, images.at(current_image)._width, images.at(current_image)._height, images.at(current_image)._color);
00572 images.at(current_image)._elements.push_back(element);
00573 }
00574
00575
00576 if (images.at(current_image)._grayscale)
00577 {
00578 images.at(current_image).EnableGrayScale();
00579 }
00580 }
00581 }
00582
00583
00584 if (info.multi_image.pixels)
00585 free (info.multi_image.pixels);
00586 if (info.image.pixels)
00587 free (info.image.pixels);
00588
00589 return true;
00590 }
00591
00592
00593
00594
00595
00596
00597 bool GameVideo::LoadAnimatedImageFromNumberElements(AnimatedImage &id, const std::string &filename, const uint32 rows, const uint32 cols)
00598 {
00599
00600 if (id.GetNumFrames() != rows*cols)
00601 {
00602 if (VIDEO_DEBUG)
00603 cerr << "VIDEO ERROR: The animated image don't have enough frames to hold the data" << endl;
00604 return false;
00605 }
00606
00607
00608 std::vector <StillImage> v;
00609 for (uint32 frame=0; frame<id.GetNumFrames(); ++frame)
00610 {
00611 v.push_back(id.GetFrame(frame));
00612 }
00613
00614
00615 bool success = LoadMultiImageFromNumberElements(v, filename, rows, cols);
00616
00617
00618 if (success == true) {
00619 for (uint32 i = 0; i < v.size(); i++) {
00620 id._frames[i].image = v[i];
00621 }
00622 }
00623
00624 return success;
00625 }
00626
00627
00628 bool GameVideo::LoadAnimatedImageFromElementsSize(AnimatedImage &image, const std::string &file_name, const uint32 rows, const uint32 cols)
00629 {
00630 return false;
00631 }
00632
00633
00634
00635
00636
00637
00638
00639 bool GameVideo::_LoadImageHelper(StillImage &id)
00640 {
00641 bool is_static = id._is_static;
00642
00643 id._elements.clear();
00644
00645 private_video::ImageLoadInfo load_info;
00646
00647 if(!_LoadRawImage(id._filename, load_info))
00648 {
00649 if(VIDEO_DEBUG)
00650 cerr << "VIDEO ERROR: _LoadRawPixelData() failed in _LoadImageHelper()" << endl;
00651 return false;
00652 }
00653
00654
00655 Image *new_image = new Image(id._filename, "", load_info.width, load_info.height, false);
00656
00657
00658 TexSheet *sheet = _InsertImageInTexSheet(new_image, load_info, is_static);
00659
00660 if(!sheet)
00661 {
00662
00663
00664
00665 if(VIDEO_DEBUG)
00666 cerr << "VIDEO_DEBUG: GameVideo::_InsertImageInTexSheet() returned NULL!" << endl;
00667
00668 delete new_image;
00669 free (load_info.pixels);
00670 return false;
00671 }
00672
00673 new_image->ref_count = 1;
00674
00675
00676 _images[id._filename] = new_image;
00677
00678
00679 if(id._width == 0.0f)
00680 id._width = (float) load_info.width;
00681
00682 if(id._height == 0.0f)
00683 id._height = (float) load_info.height;
00684
00685 ImageElement element(new_image, 0, 0, 0.0f, 0.0f, 1.0f, 1.0f, id._width, id._height, id._color);
00686 id._elements.push_back(element);
00687
00688
00689 if (load_info.pixels)
00690 free (load_info.pixels);
00691
00692 return true;
00693 }
00694
00695
00696
00697
00698
00699
00700
00701
00702 bool GameVideo::_LoadRawImage(const std::string & filename, private_video::ImageLoadInfo & load_info)
00703 {
00704
00705 size_t extpos = filename.rfind('.');
00706
00707 if(extpos == string::npos)
00708 return false;
00709
00710 std::string extension = std::string(filename, extpos, filename.length() - extpos);
00711
00712 if(extension == ".jpeg" || extension == ".jpg")
00713 return _LoadRawImageJpeg(filename, load_info);
00714 if(extension == ".png")
00715 return _LoadRawImagePng(filename, load_info);
00716
00717 return false;
00718 }
00719
00720
00721
00722
00723
00724
00725
00726
00727 bool GameVideo::_LoadRawImagePng(const std::string &filename, hoa_video::private_video::ImageLoadInfo &load_info)
00728 {
00729 FILE * fp = fopen(filename.c_str(), "rb");
00730
00731 if(fp == NULL)
00732 return false;
00733
00734 uint8 test_buffer[8];
00735
00736 fread(test_buffer, 1, 8, fp);
00737 if(png_sig_cmp(test_buffer, 0, 8))
00738 {
00739 fclose(fp);
00740 return false;
00741 }
00742
00743 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL);
00744
00745 if(!png_ptr)
00746 {
00747 fclose(fp);
00748 return false;
00749 }
00750
00751 png_infop info_ptr = png_create_info_struct(png_ptr);
00752
00753 if(!info_ptr)
00754 {
00755 png_destroy_read_struct(&png_ptr, NULL, (png_infopp)NULL);
00756 fclose(fp);
00757 return false;
00758 }
00759
00760 if(setjmp(png_jmpbuf(png_ptr)))
00761 {
00762 png_destroy_read_struct(&png_ptr, NULL, (png_infopp)NULL);
00763 fclose(fp);
00764 return false;
00765 }
00766
00767 png_init_io(png_ptr, fp);
00768 png_set_sig_bytes(png_ptr, 8);
00769 png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, NULL);
00770
00771 uint8** row_pointers = png_get_rows(png_ptr, info_ptr);
00772
00773 load_info.width = info_ptr->width;
00774 load_info.height = info_ptr->height;
00775 load_info.pixels = malloc (info_ptr->width * info_ptr->height * 4);
00776
00777 uint32 bpp = info_ptr->channels;
00778
00779 uint8* img_pixel;
00780 uint8* dst_pixel;
00781
00782 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
00783 {
00784 png_color c;
00785 for(uint32 y = 0; y < info_ptr->height; y++)
00786 {
00787 for(uint32 x = 0; x < info_ptr->width; x++)
00788 {
00789 img_pixel = row_pointers[y] + (x * bpp);
00790 dst_pixel = ((uint8 *)load_info.pixels) + ((y * info_ptr->width) + x) * 4;
00791 c = info_ptr->palette[img_pixel[0]];
00792
00793 dst_pixel[0] = c.red;
00794 dst_pixel[1] = c.green;
00795 dst_pixel[2] = c.blue;
00796 dst_pixel[3] = 0xFF;
00797 }
00798 }
00799 }
00800 else if (bpp == 1)
00801 {
00802 for(uint32 y = 0; y < info_ptr->height; y++)
00803 {
00804 for(uint32 x = 0; x < info_ptr->width; x++)
00805 {
00806 img_pixel = row_pointers[y] + (x * bpp);
00807 dst_pixel = ((uint8 *)load_info.pixels) + ((y * info_ptr->width) + x) * 4;
00808 dst_pixel[0] = img_pixel[0];
00809 dst_pixel[1] = img_pixel[0];
00810 dst_pixel[2] = img_pixel[0];
00811 dst_pixel[3] = 0xFF;
00812 }
00813 }
00814 }
00815 else if (bpp == 3)
00816 {
00817 for(uint32 y = 0; y < info_ptr->height; y++)
00818 {
00819 for(uint32 x = 0; x < info_ptr->width; x++)
00820 {
00821 img_pixel = row_pointers[y] + (x * bpp);
00822 dst_pixel = ((uint8 *)load_info.pixels) + ((y * info_ptr->width) + x) * 4;
00823 dst_pixel[0] = img_pixel[0];
00824 dst_pixel[1] = img_pixel[1];
00825 dst_pixel[2] = img_pixel[2];
00826 dst_pixel[3] = 0xFF;
00827 }
00828 }
00829 }
00830 else if (bpp == 4)
00831 {
00832 for(uint32 y = 0; y < info_ptr->height; y++)
00833 {
00834 for(uint32 x = 0; x < info_ptr->width; x++)
00835 {
00836 img_pixel = row_pointers[y] + (x * bpp);
00837 dst_pixel = ((uint8 *)load_info.pixels) + ((y * info_ptr->width) + x) * 4;
00838 dst_pixel[0] = img_pixel[0];
00839 dst_pixel[1] = img_pixel[1];
00840 dst_pixel[2] = img_pixel[2];
00841 dst_pixel[3] = img_pixel[3];
00842 }
00843 }
00844 }
00845 else
00846 {
00847 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
00848 fclose (fp);
00849 if (VIDEO_DEBUG)
00850 cerr << "Game Video: Fail in loading Png file (bytes per pixel not supported)" << endl;
00851 return false;
00852 }
00853
00854 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
00855
00856 fclose(fp);
00857
00858 return true;
00859 }
00860
00861
00862
00863
00864
00865
00866
00867
00868 bool GameVideo::_LoadRawImageJpeg(const std::string &filename, hoa_video::private_video::ImageLoadInfo &load_info)
00869 {
00870 FILE * infile;
00871 uint8** buffer;
00872
00873 if((infile = fopen(filename.c_str(), "rb")) == NULL)
00874 return false;
00875
00876 jpeg_decompress_struct cinfo;
00877 jpeg_error_mgr jerr;
00878
00879 cinfo.err = jpeg_std_error(&jerr);
00880 jpeg_create_decompress(&cinfo);
00881
00882 jpeg_stdio_src(&cinfo, infile);
00883 jpeg_read_header(&cinfo, TRUE);
00884
00885 jpeg_start_decompress(&cinfo);
00886
00887 JDIMENSION row_stride = cinfo.output_width * cinfo.output_components;
00888
00889 buffer = (*cinfo.mem->alloc_sarray)
00890 ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
00891
00892 load_info.width = cinfo.output_width;
00893 load_info.height = cinfo.output_height;
00894 load_info.pixels = malloc (cinfo.output_width * cinfo.output_height * 4);
00895
00896 uint32 bpp = cinfo.output_components;
00897
00898 uint8* img_pixel;
00899 uint8* dst_pixel;
00900
00901 if (bpp == 3)
00902 {
00903 for(uint32 y = 0; y < cinfo.output_height; y++)
00904 {
00905 jpeg_read_scanlines(&cinfo, buffer, 1);
00906
00907 for(uint32 x = 0; x < cinfo.output_width; x++)
00908 {
00909 img_pixel = buffer[0] + (x * bpp);
00910 dst_pixel = ((uint8 *)load_info.pixels) + ((y * cinfo.output_width) + x) * 4;
00911
00912 dst_pixel[0] = img_pixel[0];
00913 dst_pixel[1] = img_pixel[1];
00914 dst_pixel[2] = img_pixel[2];
00915 dst_pixel[3] = 0xFF;
00916 }
00917 }
00918
00919 }
00920 else if (bpp == 4)
00921 {
00922 for(uint32 y = 0; y < cinfo.output_height; y++)
00923 {
00924 jpeg_read_scanlines(&cinfo, buffer, 1);
00925
00926 for(uint32 x = 0; x < cinfo.output_width; x++)
00927 {
00928 img_pixel = buffer[0] + (x * bpp);
00929 dst_pixel = ((uint8 *)load_info.pixels) + ((y * cinfo.output_width) + x) * 4;
00930
00931 dst_pixel[0] = img_pixel[0];
00932 dst_pixel[1] = img_pixel[1];
00933 dst_pixel[2] = img_pixel[2];
00934 dst_pixel[3] = img_pixel[3];
00935 }
00936 }
00937 }
00938 else
00939 {
00940 jpeg_finish_decompress(&cinfo);
00941 jpeg_destroy_decompress(&cinfo);
00942 fclose(infile);
00943 if (VIDEO_DEBUG)
00944 cerr << "Game Video: Fail in loading Png file (bytes per pixel not supported)" << endl;
00945 return false;
00946 }
00947
00948 jpeg_finish_decompress(&cinfo);
00949 jpeg_destroy_decompress(&cinfo);
00950
00951 fclose(infile);
00952
00953 return true;
00954 }
00955
00956
00957
00958
00959
00960
00961
00962
00963 bool GameVideo::_SavePng (const std::string& file_name, hoa_video::private_video::ImageLoadInfo &info) const
00964 {
00965 FILE * fp = fopen(file_name.c_str(), "wb");
00966
00967 if(fp == NULL)
00968 return false;
00969
00970 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
00971 (png_voidp)NULL, NULL, NULL);
00972
00973 if(!png_ptr)
00974 {
00975 fclose(fp);
00976 return false;
00977 }
00978
00979 png_infop info_ptr = png_create_info_struct(png_ptr);
00980
00981 if(!info_ptr)
00982 {
00983 png_destroy_write_struct(&png_ptr, NULL);
00984 fclose(fp);
00985 return false;
00986 }
00987
00988 if(setjmp(png_jmpbuf(png_ptr)))
00989 {
00990 png_destroy_write_struct(&png_ptr, &info_ptr);
00991 fclose(fp);
00992 return false;
00993 }
00994
00995 png_init_io(png_ptr, fp);
00996
00997 png_set_IHDR (png_ptr, info_ptr, info.width, info.height, 8, PNG_COLOR_TYPE_RGB_ALPHA,
00998 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
00999
01000 png_byte** row_pointers = new png_byte* [info.height];
01001 int32 bytes_per_row = info.width * 4;
01002 for (int32 i=0; i<info.height; i++)
01003 {
01004 row_pointers[i] = (png_byte*)info.pixels + bytes_per_row * i;
01005 }
01006 png_set_rows(png_ptr, info_ptr, row_pointers);
01007
01008 png_write_png (png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
01009
01010 png_write_image(png_ptr, row_pointers);
01011
01012 png_write_end(png_ptr, info_ptr);
01013
01014 png_destroy_write_struct (&png_ptr, &info_ptr);
01015
01016 delete[] row_pointers;
01017
01018 return true;
01019 }
01020
01021
01022
01023
01024
01025
01026
01027
01028 bool GameVideo::_SaveJpeg (const std::string& file_name, hoa_video::private_video::ImageLoadInfo &info) const
01029 {
01030 FILE * outfile;
01031 if((outfile = fopen(file_name.c_str(), "wb")) == NULL)
01032 {
01033 if (VIDEO_DEBUG)
01034 cerr << "Game Video: could not save '" << file_name.c_str() << "'" << endl;
01035 return false;
01036 }
01037
01038 jpeg_compress_struct cinfo;
01039 jpeg_error_mgr jerr;
01040
01041 cinfo.err = jpeg_std_error(&jerr);
01042 jpeg_create_compress(&cinfo);
01043
01044 cinfo.in_color_space = JCS_RGB;
01045 cinfo.image_width = info.width;
01046 cinfo.image_height = info.height;
01047 cinfo.input_components = 3;
01048 jpeg_set_defaults (&cinfo);
01049
01050 jpeg_stdio_dest(&cinfo, outfile);
01051
01052 jpeg_start_compress (&cinfo, TRUE);
01053
01054 JSAMPROW row_pointer;
01055 uint32 row_stride = info.width * 3;
01056
01057
01058 while (cinfo.next_scanline < cinfo.image_height)
01059 {
01060 row_pointer = (uint8*)info.pixels + cinfo.next_scanline * row_stride;
01061 jpeg_write_scanlines(&cinfo, &row_pointer, 1);
01062 }
01063
01064 jpeg_finish_compress(&cinfo);
01065 jpeg_destroy_compress(&cinfo);
01066
01067 fclose(outfile);
01068
01069 return true;
01070 }
01071
01072
01073
01074
01075
01076
01077
01078
01079 bool GameVideo::SaveImage (const std::string &file_name, const std::vector<StillImage*> &image,
01080 const uint32 rows, const uint32 columns) const
01081 {
01082 enum eLoadType
01083 {
01084 NONE = 0,
01085 JPEG = 1,
01086 PNG = 2
01087 } type (NONE);
01088
01089
01090 size_t extpos = file_name.rfind('.');
01091
01092 if(extpos == string::npos)
01093 return false;
01094
01095 std::string extension = std::string(file_name, extpos, file_name.length() - extpos);
01096
01097 if(extension == ".jpeg" || extension == ".jpg")
01098 type = JPEG;
01099 if(extension == ".png")
01100 type = PNG;
01101
01102 if (type == NONE)
01103 {
01104 if (VIDEO_DEBUG)
01105 cerr << "Game Video: Don't know which format to use for storage of an image" << endl;
01106 return false;
01107 }
01108
01109
01110 if (image.empty())
01111 {
01112 if (VIDEO_DEBUG)
01113 cerr << "Game Video: Attempt to store no image" << endl;
01114 return false;
01115 }
01116
01117
01118 if (image.size() != rows*columns)
01119 {
01120 if (VIDEO_DEBUG)
01121 cerr << "Game Video: Can't store " << image.size() << " in " << rows << " rows and " << columns << " columns" << endl;
01122 return false;
01123 }
01124
01125
01126 for (uint32 i=0 ; i<image.size(); i++)
01127 {
01128 if (image[i]->_elements.size() != 1)
01129 {
01130 if (VIDEO_DEBUG)
01131 cerr << "Game Video: one of the images didn't have 1 ImageElement" << endl;
01132 return false;
01133 }
01134 }
01135
01136
01137 int32 width = image[0]->_elements[0].image->width;
01138 int32 height = image[0]->_elements[0].image->height;
01139 for (uint32 i = 0; i < image.size(); i++)
01140 {
01141 if (!image[i]->_elements[0].image || image[i]->_elements[0].image->width != width ||
01142 image[i]->_elements[0].image->height != height)
01143 {
01144 if (VIDEO_DEBUG)
01145 cerr << "Game Video: not all the images where of the same size" << endl;
01146 return false;
01147 }
01148 }
01149
01150
01151 hoa_video::private_video::ImageLoadInfo info;
01152 info.height = rows*height;
01153 info.width = columns*width;
01154 info.pixels = malloc (info.width * info.height * 4);
01155
01156 hoa_video::private_video::Image* img;
01157 GLuint ID;
01158 hoa_video::private_video::ImageLoadInfo texture;
01159
01160
01161
01162 img = const_cast<Image*>(image[0]->_elements[0].image);
01163 ID = img->texture_sheet->tex_ID;
01164 texture.width = img->texture_sheet->width;
01165 texture.height = img->texture_sheet->height;
01166 texture.pixels = malloc (texture.width * texture.height * 4);
01167 VideoManager->_BindTexture(ID);
01168 glGetTexImage (GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture.pixels);
01169
01170 uint32 i=0;
01171 for (uint32 x=0; x<rows; x++)
01172 {
01173 for (uint32 y=0; y<columns; y++)
01174 {
01175 img = const_cast<Image*>(image[i]->_elements[0].image);
01176 if (ID != img->texture_sheet->tex_ID)
01177 {
01178
01179 VideoManager->_BindTexture(img->texture_sheet->tex_ID);
01180 ID = img->texture_sheet->tex_ID;
01181
01182
01183 if (texture.height * texture.width < img->texture_sheet->height * img->texture_sheet->width * 4)
01184 {
01185 free (texture.pixels);
01186 texture.width = img->texture_sheet->width;
01187 texture.height = img->texture_sheet->height;
01188 texture.pixels = malloc (texture.width * texture.height * 4);
01189 }
01190 glGetTexImage (GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture.pixels);
01191 }
01192
01193
01194 uint32 copy_bytes = width * 4;
01195 uint32 dst_offset = x*height*width*columns*4 + y*width*4;
01196 uint32 dst_bytes = width*columns*4;
01197 uint32 src_bytes = texture.width * 4;
01198 uint32 src_offset = img->y * texture.width * 4 + img->x * 4;
01199 for (int32 j = 0; j < height; j++)
01200 {
01201 memcpy ((uint8*)info.pixels+j*dst_bytes+dst_offset, (uint8*)texture.pixels+j*src_bytes+src_offset, copy_bytes);
01202 }
01203
01204 i++;
01205 }
01206 }
01207
01208
01209 if (type == JPEG)
01210 {
01211 _RGBAToRGB (info, info);
01212 _SaveJpeg (file_name, info);
01213 }
01214 else
01215 {
01216 _SavePng (file_name, info);
01217 }
01218
01219 if (info.pixels)
01220 free (info.pixels);
01221
01222 if (texture.pixels)
01223 free (texture.pixels);
01224
01225 return true;
01226 }
01227
01228
01229
01230
01231
01232
01233
01234
01235 bool GameVideo::SaveImage (const std::string &file_name, const AnimatedImage &image) const
01236 {
01237 int32 frame_count = dynamic_cast<const AnimatedImage &>(image).GetNumFrames();
01238 std::vector <StillImage*> frames;
01239 frames.reserve (frame_count);
01240
01241 for (int32 frame=0; frame<frame_count; frame++)
01242 {
01243 frames.push_back(dynamic_cast<const AnimatedImage &>(image).GetFrame(frame));
01244 }
01245
01246 return SaveImage (file_name, frames, 1, frame_count);
01247 }
01248
01249
01250
01251
01252
01253
01254
01255
01256 bool GameVideo::SaveImage (const std::string &file_name, const StillImage &image) const
01257 {
01258 enum eLoadType
01259 {
01260 NONE = 0,
01261 JPEG = 1,
01262 PNG = 2
01263 } type (NONE);
01264
01265
01266 size_t extpos = file_name.rfind('.');
01267
01268 if(extpos == string::npos)
01269 return false;
01270
01271 std::string extension = std::string(file_name, extpos, file_name.length() - extpos);
01272
01273 if(extension == ".jpeg" || extension == ".jpg")
01274 type = JPEG;
01275 if(extension == ".png")
01276 type = PNG;
01277
01278 if (type == NONE)
01279 {
01280 if (VIDEO_DEBUG)
01281 cerr << "Game Video: Don't know which format to use for storage of an image" << endl;
01282 return false;
01283 }
01284
01285
01286 if (image._elements.empty())
01287 {
01288 if (VIDEO_DEBUG)
01289 cerr << "Game Video: Attempt to store empty image" << endl;
01290 return false;
01291 }
01292
01293
01294 if (image._elements.size() > 1)
01295 {
01296 if (VIDEO_DEBUG)
01297 cerr << "Game Video: Compound images can't be stored yet" << endl;
01298 return false;
01299 }
01300
01301 hoa_video::private_video::ImageLoadInfo buffer;
01302 hoa_video::private_video::Image* img = const_cast<Image*>(image._elements[0].image);
01303
01304 _GetBufferFromImage (buffer, img);
01305
01306 if (type == JPEG)
01307 {
01308 _RGBAToRGB (buffer, buffer);
01309 _SaveJpeg (file_name, buffer);
01310 }
01311 else
01312 {
01313 _SavePng (file_name, buffer);
01314 }
01315
01316 return true;
01317 }
01318
01319
01320
01321
01322
01323
01324
01325
01326 void GameVideo::_GetBufferFromTexture (hoa_video::private_video::ImageLoadInfo& buffer,
01327 hoa_video::private_video::TexSheet* texture) const
01328 {
01329 if (buffer.pixels)
01330 free (buffer.pixels);
01331 buffer.pixels = NULL;
01332
01333
01334 buffer.height = texture->height;
01335 buffer.width = texture->width;
01336 buffer.pixels = malloc (buffer.height * buffer.width * 4);
01337 VideoManager->_BindTexture(texture->tex_ID);
01338 glGetTexImage (GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer.pixels);
01339 }
01340
01341
01342
01343
01344
01345
01346
01347
01348 void GameVideo::_GetBufferFromImage (hoa_video::private_video::ImageLoadInfo& buffer,
01349 hoa_video::private_video::Image* img) const
01350 {
01351
01352 _GetBufferFromTexture (buffer, img->texture_sheet);
01353
01354
01355 if (buffer.height > img->height || buffer.width > img->width)
01356 {
01357 hoa_video::private_video::ImageLoadInfo info;
01358 info.width = img->width;
01359 info.height = img->height;
01360 info.pixels = malloc (img->width * img->height * 4);
01361 uint32 dst_bytes = info.width * 4;
01362 uint32 src_bytes = buffer.width * 4;
01363 uint32 src_offset = img->y * buffer.width * 4 + img->x * 4;
01364 for (int32 i=0; i<info.height; i++)
01365 {
01366 memcpy ((uint8*)info.pixels+i*dst_bytes, (uint8*)buffer.pixels+i*src_bytes+src_offset, dst_bytes);
01367 }
01368
01369 if (buffer.pixels)
01370 free (buffer.pixels);
01371
01372 buffer.pixels = info.pixels;
01373 buffer.height = info.height;
01374 buffer.width = info.width;
01375 }
01376 }
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394 StillImage GameVideo::TilesToObject (std::vector<StillImage> &tiles, std::vector< std::vector<uint32> > indices)
01395 {
01396 StillImage id;
01397
01398
01399
01400 int32 w, h;
01401 w = (int32) indices[0].size();
01402 h = (int32) indices.size();
01403
01404 float tile_width = tiles[0]._width;
01405 float tile_height = tiles[0]._height;
01406
01407 id._width = (float) w * tile_width;
01408 id._height = (float) h * tile_height;
01409
01410 id._is_static = tiles[0]._is_static;
01411
01412 for(int32 y = 0; y < h; ++y)
01413 {
01414 for(int32 x = 0; x < w; ++x)
01415 {
01416
01417
01418 float x_offset = x * tile_width;
01419 float y_offset = y * tile_height;
01420
01421 if(!id.AddImage(tiles[indices[y][x]], x_offset, y_offset))
01422 {
01423 if(VIDEO_DEBUG)
01424 {
01425 cerr << "VIDEO ERROR: failed to AddImage in TilesToObject()!" << endl;
01426 }
01427 }
01428 }
01429 }
01430
01431 return id;
01432 }
01433
01434
01435
01436
01437
01438
01439
01440
01441
01442
01443
01444
01445
01446
01447 TexSheet *GameVideo::_InsertImageInTexSheet(Image *image, private_video::ImageLoadInfo & load_info, bool is_static)
01448 {
01449
01450
01451
01452 if(load_info.width > 512 || load_info.height > 512)
01453 {
01454 int32 round_width = RoundUpPow2(load_info.width);
01455 int32 round_height = RoundUpPow2(load_info.height);
01456 TexSheet *sheet = _CreateTexSheet(round_width, round_height, VIDEO_TEXSHEET_ANY, false);
01457
01458
01459 if(!sheet)
01460 {
01461 if(VIDEO_DEBUG)
01462 cerr << "VIDEO ERROR: _CreateTexSheet() returned NULL in _InsertImageInTexSheet()!" << endl;
01463 return NULL;
01464 }
01465
01466 if(sheet->AddImage(image, load_info))
01467 return sheet;
01468 else
01469 {
01470 if(VIDEO_DEBUG)
01471 cerr << "VIDEO ERROR: AddImage() returned false for inserting large image!" << endl;
01472 return NULL;
01473 }
01474 }
01475
01476
01477
01478
01479 TexSheetType type;
01480
01481 if(load_info.width == 32 && load_info.height == 32)
01482 type = VIDEO_TEXSHEET_32x32;
01483 else if(load_info.width == 32 && load_info.height == 64)
01484 type = VIDEO_TEXSHEET_32x64;
01485 else if(load_info.width == 64 && load_info.height == 64)
01486 type = VIDEO_TEXSHEET_64x64;
01487 else
01488 type = VIDEO_TEXSHEET_ANY;
01489
01490
01491
01492
01493 size_t num_tex_sheets = _tex_sheets.size();
01494
01495 for(uint32 iSheet = 0; iSheet < num_tex_sheets; ++iSheet)
01496 {
01497 TexSheet *sheet = _tex_sheets[iSheet];
01498 if(!sheet)
01499 {
01500 if(VIDEO_DEBUG)
01501 cerr << "VIDEO ERROR: _texSheets[iSheet] was NULL in _InsertImageInTexSheet()!" << endl;
01502 return NULL;
01503 }
01504
01505 if(sheet->type == type && sheet->is_static == is_static)
01506 {
01507 if(sheet->AddImage(image, load_info))
01508 {
01509
01510 return sheet;
01511 }
01512 }
01513 }
01514
01515
01516
01517 TexSheet *sheet = _CreateTexSheet(512, 512, type, is_static);
01518 if(!sheet)
01519 {
01520
01521
01522 if(VIDEO_DEBUG)
01523 {
01524 cerr << "VIDEO ERROR: Failed to create new texture sheet in _InsertImageInTexSheet!" << endl;
01525 }
01526
01527 return NULL;
01528 }
01529
01530
01531
01532 if(sheet->AddImage(image, load_info))
01533 {
01534 return sheet;
01535 }
01536
01537 return NULL;
01538 }
01539
01540
01541
01542
01543
01544
01545
01546
01547
01548
01549
01550
01551 TexSheet *GameVideo::_CreateTexSheet
01552 (
01553 int32 width,
01554 int32 height,
01555 TexSheetType type,
01556 bool is_static
01557 )
01558 {
01559
01560
01561 if(!IsPowerOfTwo(width) || !IsPowerOfTwo(height))
01562 {
01563 if(VIDEO_DEBUG)
01564 cerr << "VIDEO ERROR: non pow2 width and/or height passed to _CreateTexSheet!" << endl;
01565
01566 return NULL;
01567 }
01568
01569 if(type <= VIDEO_TEXSHEET_INVALID || type >= VIDEO_TEXSHEET_TOTAL)
01570 {
01571 if(VIDEO_DEBUG)
01572 cerr << "VIDEO ERROR: Invalid TexSheetType passed to _CreateTexSheet()!" << endl;
01573
01574 return NULL;
01575 }
01576
01577 GLuint tex_ID = _CreateBlankGLTexture(width, height);
01578
01579
01580
01581 TexSheet *sheet = new TexSheet(width, height, tex_ID, type, is_static);
01582 _tex_sheets.push_back(sheet);
01583
01584 return sheet;
01585 }
01586
01587
01588
01589
01590
01591
01592
01593
01594 TexSheet::TexSheet(int32 w, int32 h, GLuint tex_ID_, TexSheetType type_, bool is_static_)
01595 {
01596 width = w;
01597 height = h;
01598 tex_ID = tex_ID_;
01599 type = type_;
01600 is_static = is_static_;
01601 loaded = true;
01602
01603 if(type == VIDEO_TEXSHEET_32x32)
01604 tex_mem_manager = new FixedTexMemMgr(this, 32, 32);
01605 else if(type == VIDEO_TEXSHEET_32x64)
01606 tex_mem_manager = new FixedTexMemMgr(this, 32, 64);
01607 else if(type == VIDEO_TEXSHEET_64x64)
01608 tex_mem_manager = new FixedTexMemMgr(this, 64, 64);
01609 else
01610 tex_mem_manager = new VariableTexMemMgr(this);
01611 }
01612
01613
01614
01615
01616
01617
01618
01619
01620 TexSheet::~TexSheet()
01621 {
01622
01623 delete tex_mem_manager;
01624
01625 if(!VideoManager)
01626 {
01627 if(VIDEO_DEBUG)
01628 {
01629 cerr << "VIDEO ERROR: GameVideo::GetReference() returned NULL in TexSheet destructor!" << endl;
01630 }
01631 }
01632
01633
01634 VideoManager->_DeleteTexture(tex_ID);
01635 }
01636
01637
01638
01639
01640
01641
01642
01643
01644 VariableTexMemMgr::VariableTexMemMgr(TexSheet *sheet)
01645 {
01646 _tex_sheet = sheet;
01647 _sheet_width = sheet->width / 16;
01648 _sheet_height = sheet->height / 16;
01649 _blocks = new VariableImageNode[_sheet_width*_sheet_height];
01650 }
01651
01652
01653
01654
01655
01656
01657
01658
01659 VariableTexMemMgr::~VariableTexMemMgr()
01660 {
01661 delete [] _blocks;
01662 }
01663
01664
01665
01666
01667 bool GameVideo::_DEBUG_ShowTexSheet()
01668 {
01669
01670 if(_current_debug_TexSheet == -1)
01671 {
01672 return true;
01673 }
01674
01675
01676 if(_tex_sheets.empty())
01677 {
01678 if(VIDEO_DEBUG)
01679 cerr << "VIDEO_WARNING: Called DEBUG_ShowTexture(), but there were no texture sheets" << endl;
01680 return false;
01681 }
01682
01683 int32 num_sheets = (int32) _tex_sheets.size();
01684
01685
01686
01687 if(_current_debug_TexSheet >= num_sheets)
01688 {
01689 _current_debug_TexSheet = num_sheets - 1;
01690 }
01691
01692 TexSheet *sheet = _tex_sheets[_current_debug_TexSheet];
01693
01694 if(!sheet)
01695 {
01696 return false;
01697 }
01698
01699 int32 w = sheet->width;
01700 int32 h = sheet->height;
01701
01702 Image img(sheet, string(), "<T>", 0, 0, 0.0f, 0.0f, 1.0f, 1.0f, w, h, false);
01703
01704
01705 _PushContext();
01706 SetDrawFlags(VIDEO_NO_BLEND, VIDEO_X_LEFT, VIDEO_Y_BOTTOM, 0);
01707 SetCoordSys(0.0f, 1024.0f, 0.0f, 760.0f);
01708
01709 glPushMatrix();
01710
01711 Move(0.0f,0.0f);
01712 glScalef(0.5f, 0.5f, 0.5f);
01713
01714 ImageElement elem(&img, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, (float)w, (float)h);
01715
01716 StillImage id;
01717 id._elements.push_back(elem);
01718
01719
01720 if(!DrawImage(id))
01721 {
01722 glPopMatrix();
01723 _PopContext();
01724 return false;
01725 }
01726
01727 glPopMatrix();
01728
01729 if(!SetFont("debug_font"))
01730 {
01731 _PopContext();
01732 return false;
01733 }
01734
01735 char buf[200];
01736
01737 Move(20, _coord_sys.GetTop() - 30);
01738 if(!DrawText("Current Texture sheet:"))
01739 {
01740 _PopContext();
01741 return false;
01742 }
01743
01744 sprintf(buf, " Sheet #: %d", _current_debug_TexSheet);
01745 MoveRelative(0, -20);
01746 if(!DrawText(buf))
01747 {
01748 _PopContext();
01749 return false;
01750 }
01751
01752 MoveRelative(0, -20);
01753 sprintf(buf, " Size: %dx%d", sheet->width, sheet->height);
01754 if(!DrawText(buf))
01755 {
01756 _PopContext();
01757 return false;
01758 }
01759
01760 if(sheet->type == VIDEO_TEXSHEET_32x32)
01761 sprintf(buf, " Type: 32x32");
01762 else if(sheet->type == VIDEO_TEXSHEET_32x64)
01763 sprintf(buf, " Type: 32x64");
01764 else if(sheet->type == VIDEO_TEXSHEET_64x64)
01765 sprintf(buf, " Type: 64x64");
01766 else if(sheet->type == VIDEO_TEXSHEET_ANY)
01767 sprintf(buf, " Type: Any size");
01768
01769 MoveRelative(0, -20);
01770 if(!DrawText(buf))
01771 {
01772 _PopContext();
01773 return false;
01774 }
01775
01776 sprintf(buf, " Static: %d", sheet->is_static);
01777 MoveRelative(0, -20);
01778 if(!DrawText(buf))
01779 {
01780 _PopContext();
01781 return false;
01782 }
01783
01784 sprintf(buf, " TexID: %d", sheet->tex_ID);
01785 MoveRelative(0, -20);
01786 if(!DrawText(buf))
01787 {
01788 _PopContext();
01789 return false;
01790 }
01791
01792 _PopContext();
01793 return true;
01794 }
01795
01796
01797
01798
01799
01800
01801
01802
01803
01804
01805 bool GameVideo::_DeleteImage(Image *const img)
01806 {
01807
01808 if (img->grayscale)
01809 {
01810
01811 string filename (img->filename,0,img->filename.length()-10);
01812
01813 map<string,Image*>::iterator it = _images.find(filename);
01814 if (it == _images.end())
01815 {
01816 if (VIDEO_DEBUG)
01817 cerr << "Attemp to delete a color copy didn't work" << endl;
01818 return false;
01819 }
01820
01821 _DeleteImage(it->second);
01822 }
01823
01824 if(img->width > 512 || img->height > 512)
01825 {
01826
01827 _RemoveSheet(img->texture_sheet);
01828 _RemoveImage(img);
01829 }
01830 else
01831 {
01832
01833 --(img->ref_count);
01834 if(img->ref_count <= 0)
01835 {
01836 img->texture_sheet->FreeImage(img);
01837 }
01838 }
01839
01840 return true;
01841 }
01842
01843
01844
01845
01846
01847
01848
01849
01850 bool GameVideo::_RemoveSheet(TexSheet *sheet)
01851 {
01852 if(_tex_sheets.empty())
01853 {
01854 return false;
01855 }
01856
01857 vector<TexSheet*>::iterator iSheet = _tex_sheets.begin();
01858 vector<TexSheet*>::iterator iEnd = _tex_sheets.end();
01859
01860
01861 while(iSheet != iEnd)
01862 {
01863 if(*iSheet == sheet)
01864 {
01865 delete sheet;
01866 _tex_sheets.erase(iSheet);
01867 return true;
01868 }
01869 ++iSheet;
01870 }
01871
01872
01873 return false;
01874 }
01875
01876
01877
01878
01879
01880
01881
01882
01883
01884 bool TexSheet::AddImage(Image *img, ImageLoadInfo & load_info)
01885 {
01886
01887 bool could_insert = tex_mem_manager->Insert(img);
01888 if(!could_insert)
01889 return false;
01890
01891
01892
01893
01894 TexSheet *tex_sheet = img->texture_sheet;
01895 if(!tex_sheet)
01896 {
01897
01898 if(VIDEO_DEBUG)
01899 {
01900 cerr << "VIDEO ERROR: texSheet was NULL after tex_mem_manager->Insert() returned true" << endl;
01901 }
01902 return false;
01903 }
01904
01905 if(!CopyRect(img->x, img->y, load_info))
01906 {
01907 if(VIDEO_DEBUG)
01908 cerr << "VIDEO ERROR: CopyRect() failed in TexSheet::AddImage()!" << endl;
01909 return false;
01910 }
01911
01912 return true;
01913 }
01914
01915
01916
01917
01918
01919
01920
01921
01922 bool TexSheet::CopyRect(int32 x, int32 y, private_video::ImageLoadInfo & load_info)
01923 {
01924 GLenum error;
01925
01926 if (!VideoManager->_BindTexture(tex_ID))
01927 {
01928 if(VIDEO_DEBUG)
01929 {
01930 cerr << "VIDEO ERROR: could not bind texture in TexSheet::CopyRect()!" << endl;
01931 }
01932 return false;
01933 }
01934
01935 glTexSubImage2D
01936 (
01937 GL_TEXTURE_2D,
01938 0,
01939 x,
01940 y,
01941 load_info.width,
01942 load_info.height,
01943 GL_RGBA,
01944 GL_UNSIGNED_BYTE,
01945 load_info.pixels
01946 );
01947
01948 error = glGetError();
01949 if(error)
01950 {
01951 if(VIDEO_DEBUG)
01952 {
01953 cerr << "VIDEO ERROR: glTexSubImage2D() failed in TexSheet::CopyRect()!" << endl;
01954 }
01955 return false;
01956 }
01957
01958 return true;
01959 }
01960
01961 bool TexSheet::CopyScreenRect(int32 x, int32 y, const ScreenRect &screen_rect)
01962 {
01963 GLenum error;
01964
01965 if (!VideoManager->_BindTexture(tex_ID))
01966 {
01967 if(VIDEO_DEBUG)
01968 {
01969 cerr << "VIDEO ERROR: could not bind texture in TexSheet::CopyScreenRect()!" << endl;
01970 }
01971 return false;
01972 }
01973
01974 glCopyTexSubImage2D
01975 (
01976 GL_TEXTURE_2D,
01977 0,
01978 x,
01979 y,
01980 screen_rect.left,
01981 screen_rect.top - screen_rect.height,
01982 screen_rect.width,
01983 screen_rect.height
01984 );
01985
01986 error = glGetError();
01987 if(error)
01988 {
01989 if(VIDEO_DEBUG)
01990 {
01991 cerr << "VIDEO ERROR: glTexSubImage2D() failed in TexSheet::CopyScreenRect()!" << endl;
01992 }
01993 return false;
01994 }
01995
01996 return true;
01997 }
01998
01999
02000
02001
02002
02003
02004
02005
02006 bool TexSheet::RemoveImage(Image *img)
02007 {
02008 return tex_mem_manager->Remove(img);
02009 }
02010
02011
02012
02013
02014
02015
02016
02017
02018
02019
02020
02021 bool TexSheet::FreeImage(Image *img)
02022 {
02023 return tex_mem_manager->Free(img);
02024 }
02025
02026
02027
02028
02029
02030
02031
02032
02033
02034
02035 bool TexSheet::RestoreImage(Image *img)
02036 {
02037 return tex_mem_manager->Restore(img);
02038 }
02039
02040
02041
02042
02043
02044
02045
02046
02047 bool GameVideo::DeleteImage(ImageDescriptor &id)
02048 {
02049 if(id._animated)
02050 {
02051 return _DeleteImage(dynamic_cast<AnimatedImage &>(id));
02052 }
02053 else
02054 {
02055 return _DeleteImage(dynamic_cast<StillImage &>(id));
02056 }
02057 }
02058
02059
02060
02061
02062
02063
02064
02065
02066
02067 bool GameVideo::_DeleteImage(AnimatedImage &id)
02068 {
02069 int32 num_frames = id.GetNumFrames();
02070 bool success = true;
02071
02072 for(int32 j = 0; j < num_frames; ++j)
02073 {
02074 success &= _DeleteImage(id._frames[j].image);
02075 }
02076
02077 return success;
02078 }
02079
02080
02081
02082
02083
02084
02085
02086
02087
02088
02089
02090
02091
02092 bool GameVideo::_DeleteImage(StillImage &id)
02093 {
02094 vector<ImageElement>::iterator iImage = id._elements.begin();
02095 vector<ImageElement>::iterator iEnd = id._elements.end();
02096
02097
02098 while(iImage != iEnd)
02099 {
02100 Image *img = (*iImage).image;
02101
02102
02103
02104
02105 if(img)
02106 {
02107 if(img->ref_count <= 0)
02108 {
02109 if(VIDEO_DEBUG)
02110 cerr << "VIDEO ERROR: Called DeleteImage() when refcount was already <= 0!" << endl;
02111 return false;
02112 }
02113
02114 --(img->ref_count);
02115
02116 if(img->ref_count == 0)
02117 {
02118
02119
02120
02121
02122
02123 if(img->width > 512 || img->height > 512)
02124 {
02125 _DeleteImage(img);
02126 }
02127
02128
02129
02130 else if(!img->texture_sheet->FreeImage(img))
02131 {
02132 if(VIDEO_DEBUG)
02133 cerr << "VIDEO ERROR: Could not remove image from texture sheet!" << endl;
02134 return false;
02135 }
02136 }
02137 }
02138
02139 ++iImage;
02140 }
02141
02142 id._elements.clear();
02143 id._filename = "";
02144 id._height = id._width = 0;
02145 id._is_static = 0;
02146
02147 return true;
02148 }
02149
02150
02151
02152
02153
02154
02155
02156
02157 bool GameVideo::_RemoveImage(Image *img)
02158 {
02159
02160 if(!img)
02161 return true;
02162
02163 if(_images.empty())
02164 {
02165 return false;
02166 }
02167
02168 map<string, Image*>::iterator iImage = _images.begin();
02169 map<string, Image*>::iterator iEnd = _images.end();
02170
02171
02172 while(iImage != iEnd)
02173 {
02174 if(iImage->second == img)
02175 {
02176 delete img;
02177 _images.erase(iImage);
02178 return true;
02179 }
02180 ++iImage;
02181 }
02182
02183
02184 return false;
02185 }
02186
02187
02188
02189
02190
02191
02192
02193
02194 FixedTexMemMgr::FixedTexMemMgr
02195 (
02196 TexSheet *tex_sheet,
02197 int32 img_width,
02198 int32 img_height
02199 )
02200 {
02201 _tex_sheet = tex_sheet;
02202
02203
02204 _sheet_width = tex_sheet->width / img_width;
02205 _sheet_height = tex_sheet->height / img_height;
02206 _image_width = img_width;
02207 _image_height = img_height;
02208
02209
02210 int32 num_blocks = _sheet_width * _sheet_height;
02211 _blocks = new FixedImageNode[num_blocks];
02212
02213
02214
02215 _open_list_head = &_blocks[0];
02216 _open_list_tail = &_blocks[num_blocks-1];
02217
02218
02219 for(int32 i = 0; i < num_blocks - 1; ++i)
02220 {
02221 _blocks[i].next = &_blocks[i+1];
02222 _blocks[i].image = NULL;
02223 _blocks[i].block_index = i;
02224 }
02225
02226 _blocks[num_blocks-1].next = NULL;
02227 _blocks[num_blocks-1].image = NULL;
02228 _blocks[num_blocks-1].block_index = num_blocks - 1;
02229 }
02230
02231
02232
02233
02234
02235
02236
02237
02238 FixedTexMemMgr::~FixedTexMemMgr()
02239 {
02240 delete [] _blocks;
02241 }
02242
02243
02244
02245
02246
02247
02248
02249
02250 bool VariableTexMemMgr::Insert (Image *img)
02251 {
02252
02253
02254
02255
02256
02257
02258 if(_sheet_width > 32 || _sheet_height > 32)
02259 {
02260 if(!_blocks[0].free)
02261 return false;
02262 }
02263
02264
02265
02266
02267 int32 w = (img->width + 15) / 16;
02268 int32 h = (img->height + 15) / 16;
02269
02270 int32 block_x=-1, block_y=-1;
02271
02272
02273
02274
02275
02276
02277
02278
02279 for(int32 y = 0; y < _sheet_height - h + 1; ++y)
02280 {
02281 for(int32 x = 0; x < _sheet_width - w + 1; ++x)
02282 {
02283 int32 furthest_blocker = -1;
02284
02285 for(int32 dy = 0; dy < h; ++dy)
02286 {
02287 for(int32 dx = 0; dx < w; ++dx)
02288 {
02289 if(!_blocks[(x+dx)+((y+dy)*_sheet_width)].free)
02290 {
02291 furthest_blocker = x+dx;
02292 goto endneighborsearch_GOTO;
02293 }
02294 }
02295 }
02296
02297 endneighborsearch_GOTO:
02298
02299 if(furthest_blocker == -1)
02300 {
02301 block_x = x;
02302 block_y = y;
02303 goto endsearch_GOTO;
02304 }
02305 }
02306 }
02307
02308 endsearch_GOTO:
02309
02310 if(block_x == -1 || block_y == -1)
02311 return false;
02312
02313
02314
02315
02316
02317
02318 std::set<hoa_video::private_video::Image *> remove_images;
02319
02320 for(int32 y = block_y; y < block_y + h; ++y)
02321 {
02322 for(int32 x = block_x; x < block_x + w; ++x)
02323 {
02324 int32 index = x + (y * _sheet_width);
02325
02326
02327
02328
02329 if(_blocks[index].image)
02330 {
02331 remove_images.insert(_blocks[index].image);
02332 }
02333
02334 _blocks[index].free = false;
02335 _blocks[index].image = img;
02336
02337 }
02338 }
02339
02340 for(std::set<hoa_video::private_video::Image *>::iterator itr = remove_images.begin(); itr != remove_images.end(); itr++)
02341 {
02342 Remove(*itr);
02343 VideoManager->_RemoveImage(*itr);
02344 }
02345
02346
02347
02348
02349
02350 img->x = block_x * 16;
02351 img->y = block_y * 16;
02352
02353
02354
02355 float sheet_width = (float) _tex_sheet->width;
02356 float sheet_height = (float) _tex_sheet->height;
02357
02358 img->u1 = float(img->x + 0.5f) / sheet_width;
02359 img->u2 = float(img->x + img->width - 0.5f) / sheet_width;
02360 img->v1 = float(img->y + 0.5f) / sheet_height;
02361 img->v2 = float(img->y + img->height - 0.5f) / sheet_height;
02362
02363 img->texture_sheet = _tex_sheet;
02364 return true;
02365 }
02366
02367
02368
02369
02370
02371
02372
02373
02374
02375
02376
02377
02378 bool VariableTexMemMgr::Remove(Image *img)
02379 {
02380 return SetBlockProperties(img, true, true, true, NULL);
02381 }
02382
02383
02384
02385
02386
02387
02388
02389
02390
02391
02392 bool VariableTexMemMgr::SetBlockProperties
02393 (
02394 Image *img,
02395 bool change_free,
02396 bool change_image,
02397 bool free,
02398 Image *new_image
02399 )
02400 {
02401 int32 block_x = img->x / 16;
02402 int32 block_y = img->y / 16;
02403
02404 int32 w = (img->width + 15) / 16;
02405 int32 h = (img->height + 15) / 16;
02406
02407 for(int32 y = block_y; y < block_y + h; ++y)
02408 {
02409 for(int32 x = block_x; x < block_x + w; ++x)
02410 {
02411 if(_blocks[x+y*_sheet_width].image == img)
02412 {
02413 if(change_free)
02414 _blocks[x+y*_sheet_width].free = free;
02415 if(change_image)
02416 _blocks[x+y*_sheet_width].image = new_image;
02417 }
02418 }
02419 }
02420
02421 return true;
02422 }
02423
02424
02425
02426
02427
02428
02429
02430
02431
02432 bool VariableTexMemMgr::Free(Image *img)
02433 {
02434 return SetBlockProperties(img, true, false, true, NULL);
02435 }
02436
02437
02438
02439
02440
02441
02442
02443
02444 bool VariableTexMemMgr::Restore(Image *img)
02445 {
02446 return SetBlockProperties(img, true, false, false, NULL);
02447 }
02448
02449
02450
02451
02452
02453
02454
02455
02456
02457 bool FixedTexMemMgr::Insert(Image *img)
02458 {
02459
02460
02461 if(_open_list_head == NULL)
02462 return false;
02463
02464
02465
02466 FixedImageNode *node = _open_list_head;
02467 _open_list_head = _open_list_head->next;
02468
02469 if(_open_list_head == NULL)
02470 {
02471
02472
02473 _open_list_tail = NULL;
02474 }
02475 else
02476 {
02477
02478 _open_list_head->prev = NULL;
02479 }
02480
02481 node->next = NULL;
02482
02483
02484
02485
02486
02487 if(node->image)
02488 {
02489 VideoManager->_RemoveImage(node->image);
02490 node->image = NULL;
02491 }
02492
02493
02494
02495
02496 img->x = _image_width * (node->block_index % _sheet_width);
02497 img->y = _image_height * (node->block_index / _sheet_width);
02498
02499
02500
02501 float sheet_width = (float) _tex_sheet->width;
02502 float sheet_height = (float) _tex_sheet->height;
02503
02504 img->u1 = float(img->x + 0.5f) / sheet_width;
02505 img->u2 = float(img->x + img->width - 0.5f) / sheet_width;
02506 img->v1 = float(img->y + 0.5f) / sheet_height;
02507 img->v2 = float(img->y + img->height - 0.5f) / sheet_height;
02508
02509 img->texture_sheet = _tex_sheet;
02510
02511 return true;
02512 }
02513
02514
02515
02516
02517
02518
02519
02520
02521 int32 FixedTexMemMgr::_CalculateBlockIndex(Image *img)
02522 {
02523 int32 block_x = img->x / _image_width;
02524 int32 block_y = img->y / _image_height;
02525
02526 int32 block_index = block_x + _sheet_width * block_y;
02527 return block_index;
02528 }
02529
02530
02531
02532
02533
02534
02535
02536
02537
02538
02539
02540 bool FixedTexMemMgr::Remove(Image *img)
02541 {
02542
02543 int32 block_index = _CalculateBlockIndex(img);
02544
02545
02546 if(_blocks[block_index].image != img)
02547 {
02548
02549
02550
02551 if(VIDEO_DEBUG)
02552 cerr << "VIDEO ERROR: tried to remove a fixed block not owned by this Image" << endl;
02553 return false;
02554 }
02555
02556
02557 _blocks[block_index].image = NULL;
02558
02559
02560 _DeleteNode(block_index);
02561
02562 return true;
02563 }
02564
02565
02566
02567
02568
02569
02570
02571
02572 void FixedTexMemMgr::_DeleteNode(int32 block_index)
02573 {
02574 if(block_index < 0)
02575 return;
02576
02577 if(block_index >= _sheet_width * _sheet_height)
02578 return;
02579
02580 FixedImageNode *node = &_blocks[block_index];
02581
02582 if(node->prev && node->next)
02583 {
02584
02585 node->prev->next = node->next;
02586 }
02587 else if(node->prev)
02588 {
02589
02590 node->prev->next = NULL;
02591 _open_list_tail = node->prev;
02592 }
02593 else if(node->next)
02594 {
02595
02596 _open_list_head = node->next;
02597 node->next->prev = NULL;
02598 }
02599 else
02600 {
02601
02602 _open_list_head = NULL;
02603 _open_list_tail = NULL;
02604 }
02605
02606
02607 node->prev = NULL;
02608 node->next = NULL;
02609 }
02610
02611
02612
02613
02614
02615
02616
02617
02618
02619
02620
02621
02622 bool FixedTexMemMgr::Free(Image *img)
02623 {
02624 int32 block_index = _CalculateBlockIndex(img);
02625
02626 FixedImageNode *node = &_blocks[block_index];
02627
02628 if(_open_list_tail != NULL)
02629 {
02630
02631 _open_list_tail->next = node;
02632 node->prev = _open_list_tail;
02633 node->next = NULL;
02634 _open_list_tail = node;
02635 }
02636 else
02637 {
02638
02639 _open_list_head = _open_list_tail = node;
02640 node->next = node->prev = NULL;
02641 }
02642
02643 return true;
02644 }
02645
02646
02647
02648
02649
02650
02651
02652
02653
02654 bool FixedTexMemMgr::Restore(Image *img)
02655 {
02656 int32 block_index = _CalculateBlockIndex(img);
02657 _DeleteNode(block_index);
02658 return true;
02659 }
02660
02661
02662
02663
02664
02665
02666
02667
02668
02669 void GameVideo::DEBUG_NextTexSheet()
02670 {
02671 ++_current_debug_TexSheet;
02672
02673 if(_current_debug_TexSheet >= (int32) _tex_sheets.size())
02674 {
02675 _current_debug_TexSheet = -1;
02676 }
02677 }
02678
02679
02680
02681
02682
02683
02684
02685
02686
02687 void GameVideo::DEBUG_PrevTexSheet()
02688 {
02689 --_current_debug_TexSheet;
02690
02691 if(_current_debug_TexSheet < -1)
02692 {
02693 _current_debug_TexSheet = (int32) _tex_sheets.size() - 1;
02694 }
02695 }
02696
02697
02698
02699
02700
02701
02702
02703
02704
02705
02706 bool GameVideo::ReloadTextures()
02707 {
02708
02709
02710 vector<TexSheet *>::iterator iSheet = _tex_sheets.begin();
02711 vector<TexSheet *>::iterator iSheetEnd = _tex_sheets.end();
02712
02713 bool success = true;
02714
02715 while(iSheet != iSheetEnd)
02716 {
02717 TexSheet *sheet = *iSheet;
02718
02719 if(sheet)
02720 {
02721 if(!sheet->Reload())
02722 {
02723 if(VIDEO_DEBUG)
02724 cerr << "VIDEO_ERROR: in ReloadTextures(), sheet->Reload() failed!" << endl;
02725 success = false;
02726 }
02727 }
02728 else
02729 {
02730 if(VIDEO_DEBUG)
02731 cerr << "VIDEO ERROR: in ReloadTextures(), one of the tex sheets in the vector was NULL!" << endl;
02732 success = false;
02733 }
02734
02735 ++iSheet;
02736 }
02737
02738 _DeleteTempTextures();
02739
02740 if(_uses_lights)
02741 _light_overlay = _CreateBlankGLTexture(1024, 1024);
02742
02743 return success;
02744 }
02745
02746
02747
02748
02749
02750
02751
02752
02753
02754
02755 bool GameVideo::UnloadTextures()
02756 {
02757
02758
02759
02760 _SaveTempTextures();
02761
02762
02763 vector<TexSheet *>::iterator iSheet = _tex_sheets.begin();
02764 vector<TexSheet *>::iterator iSheetEnd = _tex_sheets.end();
02765
02766 bool success = true;
02767
02768 while(iSheet != iSheetEnd)
02769 {
02770 TexSheet *sheet = *iSheet;
02771
02772 if(sheet)
02773 {
02774 if(!sheet->Unload())
02775 {
02776 if(VIDEO_DEBUG)
02777 cerr << "VIDEO_ERROR: in UnloadTextures(), sheet->Unload() failed!" << endl;
02778 success = false;
02779 }
02780 }
02781 else
02782 {
02783 if(VIDEO_DEBUG)
02784 cerr << "VIDEO ERROR: in UnloadTextures(), one of the tex sheets in the vector was NULL!" << endl;
02785 success = false;
02786 }
02787
02788 ++iSheet;
02789 }
02790
02791 if(_light_overlay != 0xFFFFFFFF)
02792 {
02793 _DeleteTexture(_light_overlay);
02794 _light_overlay = 0xFFFFFFFF;
02795 }
02796
02797
02798 map<string, FontProperties *>::iterator iFontProp = _font_map.begin();
02799 map<string, FontProperties *>::iterator iFontPropEnd = _font_map.end();
02800
02801 while(iFontProp != _font_map.end())
02802 {
02803 FontProperties *fp = iFontProp->second;
02804
02805 if(fp->glyph_cache)
02806 {
02807 for(std::map<uint16, FontGlyph *>::iterator glyphitr = fp->glyph_cache->begin(); glyphitr != fp->glyph_cache->end(); glyphitr++)
02808 {
02809 _DeleteTexture((*glyphitr).second->texture);
02810 delete (*glyphitr).second;
02811 }
02812
02813 fp->glyph_cache->clear();
02814 }
02815
02816 ++iFontProp;
02817 }
02818
02819 return success;
02820 }
02821
02822
02823
02824
02825
02826
02827
02828
02829
02830
02831 bool GameVideo::_DeleteTexture(GLuint tex_ID)
02832 {
02833 glDeleteTextures(1, &tex_ID);
02834
02835 if(_last_tex_ID == tex_ID)
02836 _last_tex_ID = 0xFFFFFFFF;
02837
02838 if(glGetError())
02839 return false;
02840
02841 return true;
02842 }
02843
02844
02845
02846
02847
02848
02849
02850
02851
02852
02853 bool TexSheet::Unload()
02854 {
02855
02856 if(!loaded)
02857 {
02858 if(VIDEO_DEBUG)
02859 cerr << "VIDEO ERROR: unloading an already unloaded texture sheet" << endl;
02860 return false;
02861 }
02862
02863
02864 if(!VideoManager->_DeleteTexture(tex_ID))
02865 {
02866 if(VIDEO_DEBUG)
02867 cerr << "VIDEO ERROR: _DeleteTexture() failed in TexSheet::Unload()!" << endl;
02868 return false;
02869 }
02870
02871 loaded = false;
02872 return true;
02873 }
02874
02875
02876
02877
02878
02879
02880
02881
02882
02883
02884 GLuint GameVideo::_CreateBlankGLTexture(int32 width, int32 height)
02885 {
02886
02887
02888
02889 int32 error;
02890
02891 GLuint tex_ID;
02892
02893 glGenTextures(1, &tex_ID);
02894 error = glGetError();
02895
02896 if(!error)
02897 {
02898 _BindTexture(tex_ID);
02899 error = glGetError();
02900
02901
02902 if(!error)
02903 {
02904 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
02905 error = glGetError();
02906 }
02907 }
02908
02909 if(error != 0)
02910 {
02911 _DeleteTexture(tex_ID);
02912
02913 if(VIDEO_DEBUG)
02914 {
02915 cerr << "VIDEO ERROR: failed to create new texture in _CreateBlankGLTexture()." << endl;
02916 cerr << " OpenGL reported the following error:" << endl << " ";
02917 char *errString = (char*)gluErrorString(error);
02918 cerr << errString << endl;
02919 }
02920 return 0xffffffff;
02921 }
02922
02923
02924 GLenum filtering_type = VideoManager->_ShouldSmooth() ? GL_LINEAR : GL_NEAREST;
02925
02926 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering_type );
02927 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering_type );
02928 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
02929 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
02930
02931 return tex_ID;
02932 }
02933
02934
02935
02936
02937
02938
02939
02940
02941
02942
02943 bool TexSheet::Reload()
02944 {
02945
02946 if(loaded)
02947 {
02948 if(VIDEO_DEBUG)
02949 cerr << "VIDEO ERROR: loading an already loaded texture sheet" << endl;
02950 return false;
02951 }
02952
02953
02954 GLuint tID = VideoManager->_CreateBlankGLTexture(width, height);
02955
02956 if(tID == 0xFFFFFFFF)
02957 {
02958 if(VIDEO_DEBUG)
02959 cerr << "VIDEO ERROR: _CreateBlankGLTexture() failed in TexSheet::Reload()!" << endl;
02960 return false;
02961 }
02962
02963 tex_ID = tID;
02964
02965
02966
02967
02968 if(!VideoManager->_ReloadImagesToSheet(this))
02969 {
02970 if(VIDEO_DEBUG)
02971 cerr << "VIDEO ERROR: CopyImagesToSheet() failed in TexSheet::Reload()!" << endl;
02972 return false;
02973 }
02974
02975 loaded = true;
02976 return true;
02977 }
02978
02979
02980
02981
02982
02983
02984
02985
02986
02987
02988 bool GameVideo::_ReloadImagesToSheet(TexSheet *sheet)
02989 {
02990
02991 map<string, Image *>::iterator iImage = _images.begin();
02992 map<string, Image *>::iterator iImageEnd = _images.end();
02993
02994 std::map <string, private_video::MultiImageInfo> multi_image_info;
02995
02996 bool success = true;
02997 while(iImage != iImageEnd)
02998 {
02999 Image *i = iImage->second;
03000
03001
03002 if(i->texture_sheet == sheet)
03003 {
03004 ImageLoadInfo load_info;
03005
03006 bool is_multi_image = ( i->tags.find("<X",0) != i->filename.npos);
03007
03008 if (is_multi_image)
03009 {
03010 ImageLoadInfo image;
03011
03012 if (multi_image_info.find(i->filename) == multi_image_info.end())
03013 {
03014
03015 if(!_LoadRawImage(i->filename, load_info))
03016 {
03017 if(VIDEO_DEBUG)
03018 cerr << "VIDEO ERROR: _LoadRawImage() failed in _ReloadImagesToSheet()!" << endl;
03019 success = false;
03020 }
03021
03022
03023 image.height = i->height;
03024 image.width = i->width;
03025 image.pixels = malloc(image.height * image.width * 4);
03026
03027 MultiImageInfo info;
03028 info.multi_image = load_info;
03029 info.image = image;
03030 multi_image_info[i->filename] = info;
03031 }
03032 else
03033 {
03034 load_info = multi_image_info[i->filename].multi_image;
03035 image = multi_image_info[i->filename].image;
03036 }
03037
03038 if (!image.pixels)
03039 {
03040 if (VIDEO_DEBUG)
03041 cerr << "VIDEO ERROR: run out of memory in _ReloadImageToSheet()" << endl;
03042 success = false;
03043 }
03044
03045 uint16 pos0, pos1;
03046 pos0 = i->tags.find("<X", 0);
03047 pos1 = i->tags.find('_', pos0);
03048 uint32 x = atoi( i->tags.substr(pos0+2, pos1).c_str() );
03049 uint32 rows = load_info.height / image.height;
03050 pos0 = i->tags.find("<Y", 0);
03051 pos1 = i->tags.find('_', pos0);
03052 uint32 y = atoi( i->tags.substr(pos0+2, pos1).c_str() );
03053 uint32 cols = load_info.width / image.width;
03054
03055 for (int32 row=0; row<image.height; row++)
03056 {
03057 memcpy ((uint8*)image.pixels+4*image.width*row, (uint8*)load_info.pixels+(((x*load_info.height/rows)+row)*load_info.width+y*load_info.width/cols)*4, 4*image.width);
03058 }
03059
03060
03061 if (i->tags.find("<G>",0) != i->filename.npos)
03062 _ConvertImageToGrayscale(image, image);
03063
03064
03065 if(!sheet->CopyRect(i->x, i->y, image))
03066 {
03067 if(VIDEO_DEBUG)
03068 cerr << "VIDEO ERROR: sheet->CopyRect() failed in _ReloadImagesToSheet()!" << endl;
03069 success = false;
03070 }
03071 }
03072 else
03073 {
03074 std::string fname = i->filename;
03075 if (i->tags.find("<T>",0) != i->tags.npos)
03076 {
03077 fname = "img\\temp\\" + fname + ".png";
03078 }
03079
03080 if(!_LoadRawImage(fname, load_info))
03081 {
03082 if(VIDEO_DEBUG)
03083 cerr << "VIDEO ERROR: _LoadRawImage() failed in _ReloadImagesToSheet()!" << endl;
03084 success = false;
03085 }
03086
03087
03088 if (i->tags.find("<G>",0) != i->filename.npos)
03089 _ConvertImageToGrayscale(load_info, load_info);
03090
03091 if(!sheet->CopyRect(i->x, i->y, load_info))
03092 {
03093 if(VIDEO_DEBUG)
03094 cerr << "VIDEO ERROR: sheet->CopyRect() failed in _ReloadImagesToSheet()!" << endl;
03095 success = false;
03096 }
03097
03098 if (load_info.pixels)
03099 free (load_info.pixels);
03100 }
03101 }
03102
03103 ++iImage;
03104 }
03105
03106 for (map<string,MultiImageInfo>::iterator it=multi_image_info.begin(); it!=multi_image_info.end(); ++it)
03107 {
03108 free ((*it).second.multi_image.pixels);
03109 free ((*it).second.image.pixels);
03110 }
03111
03112 return success;
03113 }
03114
03115
03116
03117
03118
03119
03120
03121
03122 bool GameVideo::_SaveTempTextures()
03123 {
03124 map<string, Image*>::iterator iImage = _images.begin();
03125 map<string, Image*>::iterator iEnd = _images.end();
03126
03127 while(iImage != iEnd)
03128 {
03129 Image *image = iImage->second;
03130
03131
03132 if(image->tags.find("<T>") != string::npos)
03133 {
03134 hoa_video::private_video::ImageLoadInfo buffer;
03135
03136 _GetBufferFromImage (buffer, image);
03137 _SavePng ("img\\temp\\"+image->filename+".png", buffer);
03138 }
03139
03140 ++iImage;
03141 }
03142 return true;
03143 }
03144
03145
03146
03147
03148
03149
03150
03151
03152 bool GameVideo::_DeleteTempTextures()
03153 {
03154 return CleanDirectory("img\\temp");
03155 }
03156
03157
03158
03159 }
03160