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, dim,
571 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 BasePlatform::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) AbstractPlatform::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];
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();
Base class for BSB (Maptech/NOS) format nautical charts.
Base class for all chart types.
Manages the chart database and provides access to chart data.
Represents the view port for chart display in OpenCPN.
wxPoint2DDouble GetDoublePixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates with double precision.
double clat
Center latitude of the viewport in degrees.