All Downloads are FREE. Search and download functionalities are using the official Maven repository.

playn.robovm.RoboAssets Maven / Gradle / Ivy

/**
 * Copyright 2014 The PlayN Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the
 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing permissions and
 * limitations under the License.
 */
package playn.robovm;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;

import org.robovm.apple.coregraphics.CGImage;
import org.robovm.apple.foundation.NSBundle;
import org.robovm.apple.foundation.NSData;
import org.robovm.apple.foundation.NSDataReadingOptions;
import org.robovm.apple.foundation.NSErrorException;
import org.robovm.apple.uikit.UIImage;

import playn.core.*;
import react.Slot;

public class RoboAssets extends Assets {

  private final RoboPlatform plat;
  private final File bundleRoot = new File(NSBundle.getMainBundle().getBundlePath());
  private File assetRoot = new File(bundleRoot, "assets");

  public RoboAssets(RoboPlatform plat) {
    super(plat.exec());
    this.plat = plat;
  }

  /**
   * Configures the prefix prepended to asset paths before fetching them from the app directory.
   */
  public void setPathPrefix(String pathPrefix) {
    this.assetRoot = new File(bundleRoot, pathPrefix);
  }

  @Override public Image getRemoteImage(final String url, int width, int height) {
    final ImageImpl image = createImage(true, width, height, url);
    plat.net().req(url).execute().
      onSuccess(new Slot() {
        public void onEmit (Net.Response rsp) {
          try {
            image.succeed(toData(Scale.ONE, new UIImage(new NSData(rsp.payload()))));
          } catch (Throwable t) {
            plat.log().warn("Failed to decode remote image [url=" + url + "]", t);
            image.fail(t);
          }
        }
      }).
      onFailure(new Slot() {
        public void onEmit (Throwable cause) { image.fail(cause); }
      });
    return image;
  }

  @Override
  public Sound getSound(String path) {
    return createSound(path, false);
  }

  @Override
  public Sound getMusic(String path) {
    return createSound(path, true);
  }

  @Override
  public String getTextSync(String path) throws Exception {
    plat.log().debug("Loading text " + path);
    ByteBuffer data = getBytesSync(path);
    byte[] bytes;
    if (data.hasArray()) bytes = data.array();
    else data.get(bytes = new byte[data.remaining()]);
    return new String(bytes, "UTF-8");
  }

  @Override
  public ByteBuffer getBytesSync(String path) throws Exception {
    File fullPath = resolvePath(path);
    plat.log().debug("Loading bytes " + fullPath);
    // this NSData will release resources when garbage collected
    return NSData.read(fullPath, READ_OPTS).asByteBuffer();
  }

  @Override protected ImageImpl.Data load (String path) throws Exception {
    Exception error = null;
    for (Scale.ScaledResource rsrc : plat.graphics().scale().getScaledResources(path)) {
      File fullPath = resolvePath(rsrc.path);
      if (!fullPath.exists()) continue;

      // plat.log().debug("Loading image: " + fullPath);
      UIImage img = UIImage.getImage(fullPath);
      if (img != null) return toData(rsrc.scale, img);

      // note this error if this is the lowest resolution image, but fall back to lower resolution
      // images if not; in the Java backend we'd fail here, but this is a production backend, so we
      // want to try to make things work
      plat.log().warn("Failed to load image '" + fullPath + "'.");
      error = new Exception("Failed to load " + fullPath);
    }
    if (error == null) {
      File fullPath = resolvePath(path);
      plat.log().warn("Missing image '" + fullPath + "'.");
      error = new FileNotFoundException(fullPath.toString());
    }
    throw error;
  }

  @Override protected ImageImpl createImage (boolean async, int rwid, int rhei, String source) {
    return new RoboImage(plat, async, rwid, rhei, source);
  }

  private ImageImpl.Data toData (Scale scale, UIImage image) {
    CGImage bitmap = image.getCGImage();
    return new ImageImpl.Data(scale, bitmap, (int)bitmap.getWidth(), (int)bitmap.getHeight());
  }

  protected File resolvePath (String path) {
    return new File(assetRoot, path);
  }

  private Sound createSound(String path, boolean isMusic) {
    // look for .caf (uncompressed), .aifc (compressed, but fast), then .mp3
    for (String encpath : new String[] { path + ".caf", path + ".aifc", path + ".mp3" }) {
      File fullPath = resolvePath(encpath);
      if (!fullPath.exists()) continue;
      return plat.audio().createSound(fullPath, isMusic);
    }

    plat.log().warn("Missing sound: " + path);
    return new Sound.Error(new FileNotFoundException(path));
  }

  protected static final NSDataReadingOptions READ_OPTS = new NSDataReadingOptions(
    NSDataReadingOptions.MappedIfSafe.value()|NSDataReadingOptions.Uncached.value());
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy