Browse Source

pnmimage: Support making use of emscripten preloaded images

rdb 4 years ago
parent
commit
0cca26856d

+ 2 - 0
panda/src/pnmimage/CMakeLists.txt

@@ -9,6 +9,7 @@ set(P3PNMIMAGE_HEADERS
   pnmPainter.h pnmPainter.I
   pnmPainter.h pnmPainter.I
   pnmReader.I
   pnmReader.I
   pnmReader.h pnmWriter.I pnmWriter.h pnmimage_base.h
   pnmReader.h pnmWriter.I pnmWriter.h pnmimage_base.h
+  pnmReaderEmscripten.h
   ppmcmap.h
   ppmcmap.h
 )
 )
 
 
@@ -24,6 +25,7 @@ set(P3PNMIMAGE_SOURCES
   pnmFileTypeRegistry.cxx pnmImage.cxx pnmImageHeader.cxx
   pnmFileTypeRegistry.cxx pnmImage.cxx pnmImageHeader.cxx
   pnmPainter.cxx
   pnmPainter.cxx
   pnmReader.cxx pnmWriter.cxx pnmimage_base.cxx
   pnmReader.cxx pnmWriter.cxx pnmimage_base.cxx
+  pnmReaderEmscripten.cxx
   ppmcmap.cxx
   ppmcmap.cxx
 )
 )
 
 

+ 1 - 0
panda/src/pnmimage/p3pnmimage_composite2.cxx

@@ -2,6 +2,7 @@
 #include "pnmImageHeader.cxx"
 #include "pnmImageHeader.cxx"
 #include "pnmPainter.cxx"
 #include "pnmPainter.cxx"
 #include "pnmReader.cxx"
 #include "pnmReader.cxx"
+#include "pnmReaderEmscripten.cxx"
 #include "pnmWriter.cxx"
 #include "pnmWriter.cxx"
 #include "pnmFileTypeRegistry.cxx"
 #include "pnmFileTypeRegistry.cxx"
 #include "pnmimage_base.cxx" 
 #include "pnmimage_base.cxx" 

+ 56 - 5
panda/src/pnmimage/pnmImageHeader.cxx

@@ -20,10 +20,36 @@
 #include "virtualFileSystem.h"
 #include "virtualFileSystem.h"
 #include "zStream.h"
 #include "zStream.h"
 
 
+#ifdef __EMSCRIPTEN__
+#include "subfileInfo.h"
+#include "pnmReaderEmscripten.h"
+
+#include <emscripten.h>
+#endif
+
 using std::istream;
 using std::istream;
 using std::ostream;
 using std::ostream;
 using std::string;
 using std::string;
 
 
+#ifdef __EMSCRIPTEN__
+/**
+ * Returns true and sets width/height if the given path is in the emscripten
+ * preload image cache.
+ */
+EM_JS(int, query_preload, (const char *path, int *width, int *height), {
+  var cache = Module["preloadedImages"];
+  if (cache) {
+    var canvas = cache[UTF8ToString(path)];
+    if (canvas) {
+      setValue(width, canvas["width"], "i32");
+      setValue(height, canvas["height"], "i32");
+      return 1;
+    }
+  }
+  return 0;
+})
+#endif
+
 /**
 /**
  * Opens up the image file and tries to read its header information to
  * Opens up the image file and tries to read its header information to
  * determine its size, number of channels, etc.  If successful, updates the
  * determine its size, number of channels, etc.  If successful, updates the
@@ -84,11 +110,11 @@ make_reader(const Filename &filename, PNMFileType *type,
       << "Reading image from " << filename << "\n";
       << "Reading image from " << filename << "\n";
   }
   }
   bool owns_file = false;
   bool owns_file = false;
-  istream *file = nullptr;
+  istream *in = nullptr;
 
 
   if (filename == "-") {
   if (filename == "-") {
     owns_file = false;
     owns_file = false;
-    file = &std::cin;
+    in = &std::cin;
 
 
     if (pnmimage_cat.is_debug()) {
     if (pnmimage_cat.is_debug()) {
       pnmimage_cat.debug()
       pnmimage_cat.debug()
@@ -97,10 +123,35 @@ make_reader(const Filename &filename, PNMFileType *type,
   } else {
   } else {
     VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
     VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
     owns_file = true;
     owns_file = true;
-    file = vfs->open_read_file(filename, true);
+    PT(VirtualFile) file = vfs->get_file(filename, false);
+    if (file != nullptr) {
+#ifdef __EMSCRIPTEN__
+      // Is this a real file, and do we have that in the Emscripten cache?
+      SubfileInfo info;
+      if (file->get_system_info(info) && info.get_start() == 0) {
+        Filename fn = info.get_filename();
+        if (!fn.make_canonical()) {
+          fn.make_absolute();
+        }
+        int width, height;
+        if (query_preload(fn.c_str(), &width, &height)) {
+          if (pnmimage_cat.is_debug()) {
+            pnmimage_cat.debug()
+              << "(found in emscripten cache)\n";
+          }
+          return new PNMReaderEmscripten(type, fn, width, height);
+        }
+      }
+#endif
+      in = vfs->open_read_file(filename, true);
+      if (in != nullptr && in->fail()) {
+        file->close_read_file(in);
+        in = nullptr;
+      }
+    }
   }
   }
 
 
-  if (file == nullptr) {
+  if (in == nullptr) {
     if (pnmimage_cat.is_debug()) {
     if (pnmimage_cat.is_debug()) {
       pnmimage_cat.debug()
       pnmimage_cat.debug()
         << "Unable to open file.\n";
         << "Unable to open file.\n";
@@ -108,7 +159,7 @@ make_reader(const Filename &filename, PNMFileType *type,
     return nullptr;
     return nullptr;
   }
   }
 
 
-  return make_reader(file, owns_file, filename, string(), type,
+  return make_reader(in, owns_file, filename, string(), type,
                      report_unknown_type);
                      report_unknown_type);
 }
 }
 
 

+ 73 - 0
panda/src/pnmimage/pnmReaderEmscripten.cxx

@@ -0,0 +1,73 @@
+/**
+ * PANDA 3D SOFTWARE
+ * Copyright (c) Carnegie Mellon University.  All rights reserved.
+ *
+ * All use of this software is subject to the terms of the revised BSD
+ * license.  You should have received a copy of this license along
+ * with this source code in a file named "LICENSE."
+ *
+ * @file pnmReaderEmscripten.cxx
+ * @author rdb
+ * @date 2021-02-05
+ */
+
+#include "pnmReaderEmscripten.h"
+
+#ifdef __EMSCRIPTEN__
+
+#include "config_pnmimagetypes.h"
+
+#include <emscripten.h>
+
+/**
+ *
+ */
+PNMReaderEmscripten::
+PNMReaderEmscripten(PNMFileType *type, Filename fullpath, int width, int height) :
+  PNMReader(type, nullptr, false),
+  _fullpath(std::move(fullpath))
+{
+  _x_size = width;
+  _y_size = height;
+  _num_channels = 4;
+  _maxval = 255;
+}
+
+/**
+ * Reads in an entire image all at once, storing it in the pre-allocated
+ * _x_size * _y_size array and alpha pointers.  (If the image type has no
+ * alpha channel, alpha is ignored.)  Returns the number of rows correctly
+ * read.
+ *
+ * Derived classes need not override this if they instead provide
+ * supports_read_row() and read_row(), below.
+ */
+int PNMReaderEmscripten::
+read_data(xel *array, xelval *alpha) {
+  if (!is_valid()) {
+    return 0;
+  }
+
+  int width, height;
+  char *data = emscripten_get_preloaded_image_data(_fullpath.c_str(), &width, &height);
+  nassertr(data != nullptr, 0);
+  nassertr(width == _x_size, 0);
+  if (height > _x_size) {
+    height = _x_size;
+  }
+
+  size_t total_size = (size_t)width * (size_t)height;
+  for (int i = 0; i < total_size; ++i) {
+    array[i].r = data[i * 4 + 0];
+    array[i].g = data[i * 4 + 1];
+    array[i].b = data[i * 4 + 2];
+    alpha[i] = data[i * 4 + 3];
+  }
+
+  free(data);
+
+  return height;
+}
+
+
+#endif  // __EMSCRIPTEN__

+ 40 - 0
panda/src/pnmimage/pnmReaderEmscripten.h

@@ -0,0 +1,40 @@
+/**
+ * PANDA 3D SOFTWARE
+ * Copyright (c) Carnegie Mellon University.  All rights reserved.
+ *
+ * All use of this software is subject to the terms of the revised BSD
+ * license.  You should have received a copy of this license along
+ * with this source code in a file named "LICENSE."
+ *
+ * @file pnmReaderEmscripten.h
+ * @author rdb
+ * @date 2021-02-05
+ */
+
+#ifndef PNMREADEREMSCRIPTEN_H
+#define PNMREADEREMSCRIPTEN_H
+
+#include "pandabase.h"
+
+#ifdef __EMSCRIPTEN__
+
+#include "pnmFileType.h"
+#include "pnmReader.h"
+#include "pnmWriter.h"
+
+/**
+ * For reading files using the emscripten pre-load system.
+ */
+class PNMReaderEmscripten final : public PNMReader {
+public:
+  PNMReaderEmscripten(PNMFileType *type, Filename fullpath, int width, int height);
+
+  virtual int read_data(xel *array, xelval *alpha);
+
+private:
+  Filename _fullpath;
+};
+
+#endif  // __EMSCRIPTEN__
+
+#endif