28#include <wx/tokenzr.h>
29#include <wx/filename.h>
39#include "glTexCache.h"
40#include "glTextureDescriptor.h"
43#include "glChartCanvas.h"
48#include "OCPNPlatform.h"
49#include "mipmap/mipmap.h"
51#ifndef GL_ETC1_RGB8_OES
52#define GL_ETC1_RGB8_OES 0x8D64
61typedef void (*PFNGLGENBUFFERSPROC)(GLsizei n, GLuint *buffers);
62typedef void (*PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer);
63typedef void (*PFNGLDELETEBUFFERSPROC)(GLsizei n,
const GLuint *buffers);
64typedef void (*PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname,
66typedef void (*PFNGLDELETERENDERBUFFERSEXTPROC)(GLsizei n,
67 const GLuint *renderbuffers);
68typedef void (*PFNGLDELETEFRAMEBUFFERSEXTPROC)(GLsizei n,
69 const GLuint *framebuffers);
70typedef void (*PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum target, GLint level,
71 GLint xoffset, GLsizei width,
75typedef void (*PFNGLGETCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint level,
77typedef GLenum (*PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)(GLenum target);
78typedef void (*PFNGLBINDRENDERBUFFEREXTPROC)(GLenum target,
80typedef void (*PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size,
81 const GLvoid *data, GLenum usage);
82typedef void (*PFNGLGENFRAMEBUFFERSEXTPROC)(GLsizei n, GLuint *framebuffers);
83typedef void (*PFNGLGENRENDERBUFFERSEXTPROC)(GLsizei n, GLuint *renderbuffers);
84typedef void (*PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)(GLenum target,
87 GLuint texture, GLint level);
88typedef void (*PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level,
89 GLenum internalformat,
90 GLsizei width, GLsizei height,
91 GLint border, GLsizei imageSize,
93typedef void (*PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)(GLenum target,
95 GLenum renderbuffertarget,
97typedef void (*PFNGLRENDERBUFFERSTORAGEEXTPROC)(GLenum target,
98 GLenum internalformat,
99 GLsizei width, GLsizei height);
100typedef void (*PFNGLBINDFRAMEBUFFEREXTPROC)(GLenum target, GLuint framebuffer);
103extern long g_tex_mem_used;
104extern int g_mipmap_max_level;
105extern GLuint g_raster_format;
106extern int g_memCacheLimit;
108extern ColorScheme global_color_scheme;
113extern int g_tile_size;
115extern bool GetMemoryStatus(
int *mem_total,
int *mem_used);
117extern wxString CompressedCachePath(wxString path);
121CatalogEntry::CatalogEntry() {}
123CatalogEntry::~CatalogEntry() {}
125CatalogEntry::CatalogEntry(
int level,
int x0,
int y0, ColorScheme colorscheme) {
129 k.tcolorscheme = colorscheme;
132int CatalogEntry::GetSerialSize() {
return CATALOG_ENTRY_SERIAL_SIZE; }
134void CatalogEntry::Serialize(
unsigned char *t) {
135 uint32_t *p = (uint32_t *)t;
140 *p++ = k.tcolorscheme;
141 *p++ = v.texture_offset;
142 *p++ = v.compressed_size;
145void CatalogEntry::DeSerialize(
unsigned char *t) {
146 uint32_t *p = (uint32_t *)t;
151 k.tcolorscheme = (ColorScheme)*p++;
152 v.texture_offset = *p++;
153 v.compressed_size = *p++;
157enum TextureDataType { COMPRESSED_BUFFER_OK, MAP_BUFFER_OK };
159glTexFactory::glTexFactory(
ChartBase *chart,
int raster_format) {
161 n_catalog_entries = 0;
163 wxDateTime ed = chart->GetEditionDate();
164 m_chart_date_binary = (uint32_t)ed.IsValid() ? ed.GetTicks() : 0;
165 m_chartfile_date_binary = ::wxFileModificationTime(chart->GetFullPath());
167 (uint32_t)wxFileName::GetSize(chart->GetFullPath()).GetLo();
168 m_ChartPath = chart->GetFullPath();
170 m_CompressedCacheFilePath = CompressedCachePath(chart->GetFullPath());
175 m_catalogCorrupted =
false;
181 for (
int i = 0; i < N_COLOR_SCHEMES; i++) {
182 for (
int j = 0; j < MAX_TEX_LEVEL; j++) {
183 m_cache[i][j] = NULL;
189 if (!pBSBChart)
return;
191 m_size_X = pBSBChart->GetSize_X();
192 m_size_Y = pBSBChart->GetSize_Y();
195 m_tex_dim = g_GLOptions.m_iTextureDimension;
196 m_nx_tex = (m_size_X / m_tex_dim) + ((m_size_X % m_tex_dim) == 0 ? 0 : 1);
197 m_ny_tex = (m_size_Y / m_tex_dim) + ((m_size_Y % m_tex_dim) == 0 ? 0 : 1);
200 m_ntex = m_nx_tex * m_ny_tex;
204 m_prepared_projection_type = 0;
207glTexFactory::~glTexFactory() {
210 PurgeBackgroundCompressionPool();
212 DeleteAllDescriptors();
214 for (
int i = 0; i < N_COLOR_SCHEMES; i++) {
215 for (
int j = 0; j < MAX_TEX_LEVEL; j++) {
226 for (
int i = 0; i < m_ntex; i++)
delete m_tiles[i];
231 int array_index = ArrayIndex(rect.x, rect.y);
232 return m_td_array[array_index];
235bool glTexFactory::OnTimer() {
236 for (
int i = 0; i < m_ntex; i++) {
241 if (ptd && ptd->compdata_ticks) {
242 ptd->compdata_ticks--;
250 if(g_GLOptions.m_bTextureCompression) {
251 ChartBase *pChart = ChartData->OpenChartFromDB( m_ChartPath, FULL_INIT );
255 for(
int y = 0; y<m_ny_tex; y++) {
256 int dim = g_GLOptions.m_iTextureDimension;
258 if(!pBSBChart->HaveLineCacheRow(y*dim))
261 for(
int x = 0; x<m_nx_tex; x++) {
262 int i = ArrayIndex(x, y);
268 if( ptd->compcomp_array[0] )
276 pBSBChart->FreeLineCacheRows(y*dim, (y+1)*dim);
284 if (g_GLOptions.m_bTextureCompressionCaching)
285 for (
int i = 0; i < m_ntex; i++) {
287 if (ptd && ptd->IsCompCompArrayComplete(0)) {
288 int dim = g_GLOptions.m_iTextureDimension;
289 UpdateCacheAllLevels(wxRect(ptd->x, ptd->y, dim, dim),
290 ptd->m_colorscheme, ptd->compcomp_array,
303#ifdef __OCPN__ANDROID__
306 bool bGLMemCrunch = g_tex_mem_used > 30 * 1024 * 1024;
309 for(wxTextureListNode *node = m_texture_list.GetFirst(); node;
310 node = node->GetNext()) {
312 if(ptd->nGPU_compressed == GPU_TEXTURE_UNCOMPRESSED){
313 DeleteSingleTexture(ptd);
320void glTexFactory::AccumulateMemStatistics(
int &map_size,
int &comp_size,
321 int &compcomp_size) {
322 for (
int i = 0; i < m_ntex; i++) {
325 map_size += ptd->GetMapArrayAlloc();
326 comp_size += ptd->GetCompArrayAlloc();
327 compcomp_size += ptd->GetCompCompArrayAlloc();
332void glTexFactory::DeleteTexture(
const wxRect &rect) {
334 int array_index = ArrayIndex(rect.x, rect.y);
337 if (ptd && ptd->tex_name > 0) {
338 DeleteSingleTexture(ptd);
342void glTexFactory::DeleteAllTextures(
void) {
347 for (
int i = 0; i < m_ntex; i++) {
356 DeleteSingleTexture(ptd);
361void glTexFactory::DeleteSomeTextures(
long target) {
367 for (
int i = 0; i < m_ntex; i++) {
376 if (ptd->tex_name) DeleteSingleTexture(ptd);
378 if (g_tex_mem_used <= target)
break;
383void glTexFactory::FreeSome(
long target) {
384 for (
int i = 0; i < m_ntex; i++) {
387 if (ptd) ptd->FreeMap();
391void glTexFactory::DeleteAllDescriptors(
void) {
394 for (
int i = 0; i < m_ntex; i++) {
401bool glTexFactory::BackgroundCompressionAsJob()
const {
402 return g_glTextureManager->AsJob(m_ChartPath);
405void glTexFactory::PurgeBackgroundCompressionPool() {
407 g_glTextureManager->PurgeJobList(m_ChartPath);
411 if (!ptd->tex_name)
return;
413 g_tex_mem_used -= ptd->tex_mem_used;
414 ptd->level_min = g_mipmap_max_level + 1;
416 glDeleteTextures(1, &ptd->tex_name);
418 ptd->tex_mem_used = 0;
419 ptd->nGPU_compressed = GPU_TEXTURE_UNKNOWN;
422void glTexFactory::ArrayXY(wxRect *r,
int index)
const {
423 r->y = (index / m_stride) * m_tex_dim;
424 r->x = (index - ((r->y / m_tex_dim) * m_stride)) * m_tex_dim;
428 ColorScheme color_scheme) {
429 if (level < 0 || level >= MAX_TEX_LEVEL)
return 0;
435 if (v == 0)
return 0;
437 int array_index = ArrayIndex(x, y);
438 if (array_index >= m_ntex)
return 0;
441 if (r->compressed_size == 0)
return 0;
446bool glTexFactory::IsLevelInCache(
int level,
const wxRect &rect,
447 ColorScheme color_scheme) {
450 if (g_GLOptions.m_bTextureCompression &&
451 g_GLOptions.m_bTextureCompressionCaching) {
453 if (GetCacheEntryValue(level, rect.x, rect.y, color_scheme) != 0)
461 int array_index = ArrayIndex(rect.x, rect.y);
462 if (!m_td_array[array_index]) {
467 p->level_min = g_mipmap_max_level + 1;
468 p->m_colorscheme = global_color_scheme;
469 m_td_array[array_index] = p;
471 return m_td_array[array_index];
474static void CreateTexture(GLuint &tex_name,
bool b_use_mipmaps) {
475 glGenTextures(1, &tex_name);
479 glBindTexture(GL_TEXTURE_2D, tex_name);
481 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
482 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
483 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
486 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
487 GL_LINEAR_MIPMAP_LINEAR);
489 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
491#ifdef __OCPN__ANDROID__
492 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
493 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
498 const wxRect &rect) {
499 bool busy_shown =
false;
506 bool b_use_compressed_mipmaps =
false;
507 bool b_use_uncompressed_mipmaps =
false;
509 bool b_use_compressed_mipmaps =
true;
512 bool b_use_uncompressed_mipmaps = !g_GLOptions.m_bTextureCompression;
525 b_lowmem = g_GLOptions.m_bTextureCompression;
527 if (g_GLOptions.m_bTextureCompression &&
528 ptd->nGPU_compressed == GPU_TEXTURE_UNCOMPRESSED) {
530 if (ptd->comp_array[base_level]) DeleteSingleTexture(ptd);
534 if (base_level == ptd->level_min)
return false;
536 if (base_level > ptd->level_min) {
540 bool b_use_mipmaps = ptd->nGPU_compressed == GPU_TEXTURE_COMPRESSED
541 ? b_use_compressed_mipmaps
542 : b_use_uncompressed_mipmaps;
547 (double)(g_GLOptions.m_iTextureMemorySize * 1024 * 1024) * factor;
548 if (!bGLMemCrunch)
return false;
552 int status = GetTextureLevel(ptd, rect, base_level, ptd->m_colorscheme);
554 bool b_use_mipmaps = COMPRESSED_BUFFER_OK == status
555 ? b_use_compressed_mipmaps
556 : b_use_uncompressed_mipmaps;
558 DeleteSingleTexture(ptd);
559 CreateTexture(ptd->tex_name, b_use_mipmaps);
560 ptd->nGPU_compressed = COMPRESSED_BUFFER_OK == status
561 ? GPU_TEXTURE_COMPRESSED
562 : GPU_TEXTURE_UNCOMPRESSED;
564 if (COMPRESSED_BUFFER_OK == status) {
565 int texture_level = 0;
566 for (
int level = base_level; level < ptd->level_min; level++) {
567 int size = TextureTileSize(level,
true);
568 int status = GetTextureLevel(ptd, rect, level, ptd->m_colorscheme);
569 int dim = TextureDim(level);
570 glCompressedTexImage2D(GL_TEXTURE_2D, texture_level, g_raster_format,
571 dim, dim, 0, size, ptd->comp_array[level]);
573 ptd->tex_mem_used += size;
574 g_tex_mem_used += size;
577 if (!b_use_mipmaps)
break;
586 OCPNPlatform::ShowBusySpinner();
588 m_newCatalog =
false;
594 if (GL_COMPRESSED_RGB_FXT1_3DFX == g_raster_format &&
595 g_GLOptions.m_bTextureCompression) {
597 g_glTextureManager->ScheduleJob(
this, rect, base_level,
true,
false,
true,
600 ptd->nGPU_compressed = GPU_TEXTURE_COMPRESSED;
601 b_use_mipmaps = b_use_compressed_mipmaps;
602 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
603 GL_LINEAR_MIPMAP_LINEAR);
607 int uc_base_level = base_level;
608 if (b_lowmem) uc_base_level++;
609 int texture_level = 0;
610 for (
int level = uc_base_level; level < ptd->level_min + b_lowmem;
612 int status = GetTextureLevel(ptd, rect, level, ptd->m_colorscheme);
613 int dim = TextureDim(level);
614 glTexImage2D(GL_TEXTURE_2D, texture_level, GL_RGB, dim, dim, 0,
615 FORMAT_BITS, GL_UNSIGNED_BYTE, ptd->map_array[level]);
616 int size = TextureTileSize(level,
false);
617 ptd->tex_mem_used += size;
618 g_tex_mem_used += size;
621 if (!b_use_mipmaps)
break;
626 ptd->level_min = base_level;
629 for (
int i = 0; i < base_level - 1; i++) {
630 free(ptd->map_array[i]);
631 ptd->map_array[i] = 0;
634 if (busy_shown) OCPNPlatform::HideBusySpinner();
639bool glTexFactory::PrepareTexture(
int base_level,
const wxRect &rect,
640 ColorScheme color_scheme,
int mem_used) {
644 ptd = GetOrCreateTD(rect);
646 ptd->m_colorscheme = color_scheme;
650 if (!BuildTexture(ptd, base_level, rect))
651 glBindTexture(GL_TEXTURE_2D, ptd->tex_name);
654 if (g_GLOptions.m_bTextureCompression &&
655 ptd->nGPU_compressed == GPU_TEXTURE_UNCOMPRESSED) {
658 g_glTextureManager->ScheduleJob(
this, rect, 0 ,
true,
false,
660 if (GL_COMPRESSED_RGB_FXT1_3DFX == g_raster_format)
661 glBindTexture(GL_TEXTURE_2D, ptd->tex_name);
680 if (g_memCacheLimit > 0) {
682 if(mem_used > g_memCacheLimit * 7 / 10)
685 if(mem_used > g_memCacheLimit * 9 / 10)
698 DeleteSingleTexture(ptd);
703void glTexFactory::PrepareTiles(
const ViewPort &vp,
bool use_norm_vp,
706 if (!pChartBSB)
return;
709 if (vp.m_projection_type == PROJECTION_POLAR) {
710 bool north = vp.clat > 0;
711 if (m_north != north) m_prepared_projection_type = 0;
715 if (vp.m_projection_type == m_prepared_projection_type)
return;
717 m_prepared_projection_type = vp.m_projection_type;
721 native_scale = pChartBSB->GetNativeScale();
724 for (
int i = 0; i < m_ntex; i++)
delete m_tiles[i];
728 int tex_dim = g_GLOptions.m_iTextureDimension;
735 double xsplits, ysplits;
736 switch (vp.m_projection_type) {
737 case PROJECTION_POLAR:
738 case PROJECTION_STEREOGRAPHIC:
739 case PROJECTION_ORTHOGRAPHIC:
740 case PROJECTION_GNOMONIC:
741 case PROJECTION_POLYCONIC:
742 xsplits = native_scale / 1000000000.0 * tex_dim;
746 if (vp.m_projection_type == PROJECTION_ORTHOGRAPHIC) {
748 pChartBSB->GetChartExtent(&e);
749 xsplits = xsplits * wxMax(fabsf(e.NLAT), fabsf(e.SLAT)) / 90;
752 xsplits = round(xsplits);
753 ysplits = 2 * xsplits;
755 xsplits = wxMin(wxMax(xsplits, 1), 8);
756 ysplits = wxMin(wxMax(ysplits, 1), 8);
758 case PROJECTION_EQUIRECTANGULAR:
770 pChartBSB->chartpix_to_latlong(m_size_X / 2, m_size_Y / 2, &m_clat,
772 nvp = glChartCanvas::NormalizedViewPort(vp, m_clat, m_clon);
778 for (
int i = 0; i < m_ny_tex; i++) {
779 rect.height = tex_dim;
781 for (
int j = 0; j < m_nx_tex; j++) {
782 rect.width = tex_dim;
789 int x[4] = {rect.x, rect.x, rect.x + rect.width, rect.x + rect.width};
790 int y[4] = {rect.y + rect.height, rect.y, rect.y, rect.y + rect.height};
792 for (
int k = 0; k < 4; k++) {
793 pChartBSB->chartpix_to_latlong(x[k], y[k], &lat, &lon);
794 ll[2 * k + 0] = lon, ll[2 * k + 1] = lat;
798 float lonmin = ll[0], lonmax = ll[0];
799 float latmin = ll[1], latmax = ll[1];
800 for (
int i = 2; i < 8; i += 2) {
801 lonmin = wxMin(lonmin, ll[i]), lonmax = wxMax(lonmax, ll[i]);
802 latmin = wxMin(latmin, ll[i + 1]), latmax = wxMax(latmax, ll[i + 1]);
805 if (fabsf(lonmin - lonmax) > 180) {
806 lonmin = 540, lonmax = 0;
807 for (
int i = 0; i < 8; i += 2) {
808 float lon = ll[i] < 0 ? ll[i] + 360 : ll[i];
809 lonmin = wxMin(lonmin, lon), lonmax = wxMax(lonmax, lon);
813 tile->box.Set(latmin, lonmin, latmax, lonmax);
815 double xs = rect.width / xsplits;
816 double ys = rect.height / ysplits;
817 double x1 = rect.x, u1 = 0;
819 int maxncoords = 4 * xsplits * ysplits;
820 tile->m_coords =
new float[2 * maxncoords];
821 tile->m_texcoords =
new float[2 * maxncoords];
827 for (
int x = 0; x < xsplits; x++) {
828 double x2 = wxMin(x1 + xs, m_size_X - end);
829 double u2 = (x2 - rect.x) / rect.width;
831 double y1 = rect.y, v1 = 0;
832 for (
int y = 0; y < ysplits; y++) {
833 double y2 = wxMin(y1 + ys, m_size_Y - end);
834 double v2 = (y2 - rect.y) / rect.height;
837 double xc[4] = {x1, x1, x2, x2}, yc[4] = {y2, y1, y1, y2};
838 double lat[4], lon[4];
839 for (
int k = 0; k < 4; k++) {
840 pChartBSB->chartpix_to_latlong(xc[k], yc[k], lat + k, lon + k);
843 double u[4] = {u1, u1, u2, u2}, v[4] = {v2, v1, v1, v2};
844 for (
int j = 0; j < 4; j++) {
845 int idx = 2 * tile->m_ncoords;
846 tile->m_texcoords[idx + 0] = u[j];
847 tile->m_texcoords[idx + 1] = v[j];
850 wxPoint2DDouble p = nvp.GetDoublePixFromLL(lat[j], lon[j]);
851 tile->m_coords[idx + 0] = p.m_x;
852 tile->m_coords[idx + 1] = p.m_y;
854 tile->m_coords[idx + 0] = lat[j];
855 tile->m_coords[idx + 1] = lon[j];
860 if (y1 + ys > m_size_Y - end)
break;
865 if (x1 + xs > m_size_X - end)
break;
870 rect.x += rect.width;
872 rect.y += rect.height;
876bool glTexFactory::UpdateCacheLevel(
const wxRect &rect,
int level,
877 ColorScheme color_scheme,
878 unsigned char *data,
int size) {
879 if (!g_GLOptions.m_bTextureCompressionCaching)
return false;
881 if (!data)
return false;
886 GetCacheEntryValue(level, rect.x, rect.y, color_scheme);
889 if (v != 0)
return false;
891 return UpdateCachePrecomp(data, size, rect, level, color_scheme);
894bool glTexFactory::UpdateCacheAllLevels(
const wxRect &rect,
895 ColorScheme color_scheme,
896 unsigned char **compcomp_array,
897 int *compcomp_size) {
898 if (!g_GLOptions.m_bTextureCompressionCaching)
return false;
902 for (
int level = 0; level < g_mipmap_max_level + 1; level++)
903 work |= UpdateCacheLevel(rect, level, color_scheme, compcomp_array[level],
904 compcomp_size[level]);
906 WriteCatalogAndHeader();
913 int level, ColorScheme color_scheme) {
915 if (g_GLOptions.m_bTextureCompression) {
916 if (ptd->comp_array[level])
return COMPRESSED_BUFFER_OK;
917 if (ptd->compcomp_array[level]) {
919 int size = TextureTileSize(level,
true);
920 unsigned char *cb = (
unsigned char *)malloc(size);
921 LZ4_decompress_fast((
char *)ptd->compcomp_array[level], (
char *)cb, size);
922 ptd->comp_array[level] = cb;
923 return COMPRESSED_BUFFER_OK;
924 }
else if (g_GLOptions.m_bTextureCompressionCaching) {
929 GetCacheEntryValue(level, rect.x, rect.y, color_scheme);
934 int size = TextureTileSize(level,
true);
936 if (m_fs->IsOpened()) {
937 m_fs->Seek(p->texture_offset);
938 ptd->comp_array[level] = (
unsigned char *)malloc(size);
939 int max_compressed_size = LZ4_COMPRESSBOUND(g_tile_size);
940 char *compressed_data = (
char *)malloc(p->compressed_size);
941 m_fs->Read(compressed_data, p->compressed_size);
942 LZ4_decompress_fast(compressed_data, (
char *)ptd->comp_array[level],
944 free(compressed_data);
947 return COMPRESSED_BUFFER_OK;
954 if (!ptd->map_array[level]) GetFullMap(ptd, rect, m_ChartPath, level);
956 return MAP_BUFFER_OK;
962bool glTexFactory::LoadHeader(
void) {
963 if (m_hdrOK)
return true;
965 bool need_new =
false;
967 if (wxFileName::FileExists(m_CompressedCacheFilePath)) {
968 m_fs =
new wxFFile(m_CompressedCacheFilePath, _T(
"rb+"));
969 if (m_fs->IsOpened()) {
973 wxFileOffset hdr_offset = m_fs->Length() -
sizeof(hdr);
974 hdr_offset = m_fs->Seek(hdr_offset);
976 if (
sizeof(hdr) == m_fs->Read(&hdr,
sizeof(hdr))) {
977 if (hdr.magic != COMPRESSED_CACHE_MAGIC ||
978 hdr.chartdate != m_chart_date_binary ||
979 hdr.chartfile_date != m_chartfile_date_binary ||
980 hdr.chartfile_size != m_chartfile_size ||
981 hdr.format != g_raster_format) {
986 n_catalog_entries = hdr.m_nentries;
987 m_catalog_offset = hdr.catalog_offset;
990 n_catalog_entries = 0;
991 m_catalog_offset = 0;
992 WriteCatalogAndHeader();
999 wxRemoveFile(m_CompressedCacheFilePath);
1005 wxFileName fn(m_CompressedCacheFilePath);
1006 if (!fn.DirExists()) fn.Mkdir();
1012 m_fs =
new wxFFile(m_CompressedCacheFilePath, _T(
"wb"));
1013 n_catalog_entries = 0;
1014 m_catalog_offset = 0;
1015 WriteCatalogAndHeader();
1018 m_fs =
new wxFFile(m_CompressedCacheFilePath, _T(
"rb+"));
1024bool glTexFactory::AddCacheEntryValue(
const CatalogEntry &p) {
1025 if ((
int)p.k.tcolorscheme < 0 || p.k.tcolorscheme >= N_COLOR_SCHEMES)
1028 if (p.k.mip_level < 0 || p.k.mip_level >= MAX_TEX_LEVEL)
return false;
1030 int array_index = ArrayIndex(p.k.x, p.k.y);
1031 if (array_index < 0 || array_index >= m_ntex)
return false;
1033 if (m_cache[p.k.tcolorscheme][p.k.mip_level] == 0)
1034 m_cache[p.k.tcolorscheme][p.k.mip_level] =
1043bool glTexFactory::LoadCatalog(
void) {
1044 m_newCatalog =
false;
1045 if (m_catalogOK)
return true;
1047 if (!LoadHeader())
return false;
1049 if (n_catalog_entries == 0) {
1052 m_newCatalog =
true;
1056 m_fs->Seek(m_catalog_offset);
1059 int buf_size = ps.GetSerialSize();
1060 unsigned char *buf = (
unsigned char *)malloc(buf_size);
1064 for (
int i = 0; i < n_catalog_entries; i++) {
1065 m_fs->Read(buf, buf_size);
1067 if (!AddCacheEntryValue(p)) bad =
true;
1071 if (bad && !m_catalogCorrupted) {
1072 wxLogMessage(_T(
"Bad cache catalog %s %s"), m_ChartPath.c_str(),
1073 m_CompressedCacheFilePath.c_str());
1074 m_catalogCorrupted =
true;
1080bool glTexFactory::WriteCatalogAndHeader() {
1081 if (m_fs && m_fs->IsOpened()) {
1082 m_fs->Seek(m_catalog_offset);
1085 int buf_size = ps.GetSerialSize();
1086 unsigned char buf[CATALOG_ENTRY_SERIAL_SIZE];
1088 int new_n_catalog_entries = 0;
1091 for (
int i = 0; i < N_COLOR_SCHEMES; i++) {
1092 p.k.tcolorscheme = (ColorScheme)i;
1093 for (
int j = 0; j < MAX_TEX_LEVEL; j++) {
1097 for (
int k = 0; k < m_ntex; k++) {
1102 if (r->compressed_size == 0)
continue;
1104 new_n_catalog_entries++;
1106 m_fs->Write(buf, buf_size);
1111 n_catalog_entries = new_n_catalog_entries;
1114 hdr.magic = COMPRESSED_CACHE_MAGIC;
1115 hdr.format = g_raster_format;
1116 hdr.m_nentries = n_catalog_entries;
1117 hdr.catalog_offset = m_catalog_offset;
1118 hdr.chartdate = m_chart_date_binary;
1119 hdr.chartfile_date = m_chartfile_date_binary;
1120 hdr.chartfile_size = m_chartfile_size;
1122 m_fs->Write(&hdr,
sizeof(hdr));
1130bool glTexFactory::UpdateCachePrecomp(
unsigned char *data,
int data_size,
1131 const wxRect &rect,
int level,
1132 ColorScheme color_scheme,
1133 bool write_catalog) {
1134 if (level < 0 || level >= MAX_TEX_LEVEL)
return false;
1137 if (GetCacheEntryValue(level, rect.x, rect.y, color_scheme) != 0)
1141 wxASSERT(m_fs != 0);
1143 if (!m_fs->IsOpened())
return false;
1149 p.v.texture_offset = m_catalog_offset;
1151 p.v.compressed_size = data_size;
1152 AddCacheEntryValue(p);
1153 n_catalog_entries++;
1157 m_fs->Seek(m_catalog_offset);
1158 m_fs->Write(data, data_size);
1162 m_catalog_offset += data_size;
1163 if (write_catalog) WriteCatalogAndHeader();