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

se.llbit.chunky.world.SkymapTexture Maven / Gradle / Ivy

There is a newer version: 1.4.5
Show newest version
/* Copyright (c) 2012-2014 Jesper Öqvist 
 *
 * This file is part of Chunky.
 *
 * Chunky is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Chunky is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with Chunky.  If not, see .
 */
package se.llbit.chunky.world;

import org.apache.commons.math3.util.FastMath;
import se.llbit.chunky.renderer.scene.Scene;
import se.llbit.chunky.resources.BitmapImage;
import se.llbit.chunky.resources.Texture;
import se.llbit.log.Log;
import se.llbit.math.ColorUtil;
import se.llbit.math.QuickMath;
import se.llbit.math.Ray;
import se.llbit.math.Vector4;
import se.llbit.util.ImageTools;

import java.awt.image.BufferedImage;

/**
 * Specialized skymap texture with multithreaded gamma correction
 * preprocessing.
 *
 * @author Jesper Öqvist ([email protected])
 */
public class SkymapTexture extends Texture {

  class TexturePreprocessor extends Thread {
    private final int x0;
    private final int x1;
    private final int y0;
    private final int y1;

    TexturePreprocessor(int x0, int x1, int y0, int y1) {
      super("Texture Preprocessor");

      this.x0 = x0;
      this.x1 = x1;
      this.y0 = y0;
      this.y1 = y1;
    }

    @Override public void run() {
      float[] c = new float[4];
      for (int y = y0; y <= y1; ++y) {
        for (int x = x0; x <= x1; ++x) {
          int index = width * y + x;
          ColorUtil.getRGBAComponents(image.data[index], c);
          ColorUtil.getRGBAComponents(image.getPixel(x, y), c);
          c[0] = (float) FastMath.pow(c[0], Scene.DEFAULT_GAMMA);
          c[1] = (float) FastMath.pow(c[1], Scene.DEFAULT_GAMMA);
          c[2] = (float) FastMath.pow(c[2], Scene.DEFAULT_GAMMA);
          image.data[index] = ColorUtil.getRGB(c);
        }
      }
    }
  }

  /**
   * Create new skymap.
   */
  public SkymapTexture(BitmapImage image) {
    super(image);
  }

  @Override public void setTexture(BitmapImage newImage) {
    image = newImage;

    width = image.width;
    height = image.height;
    avgColor = ImageTools.calcAvgColor(image);

    Log.info("Preprocessing skymap texture");
    long start = System.currentTimeMillis();

    // Gamma correct the texture.

    int segX = 4;
    int segY = 4;
    if (width < segX) {
      segX = 1;
    }
    if (height < segY) {
      segY = 1;
    }
    TexturePreprocessor[][] preprocessor = new TexturePreprocessor[segX][segY];
    int w = width / segX;
    int h = height / segY;
    for (int i = 0; i < segX; ++i) {
      int x0 = w * i;
      int x1 = x0 + w - 1;
      if ((i + 1) == segX)
        x1 = width - 1;
      for (int j = 0; j < segY; ++j) {
        int y0 = h * j;
        int y1 = y0 + h - 1;
        if ((j + 1) == segY)
          y1 = height - 1;
        preprocessor[i][j] = new TexturePreprocessor(x0, x1, y0, y1);
        preprocessor[i][j].start();
      }
    }

    for (int i = 0; i < segX; ++i) {
      for (int j = 0; j < segY; ++j) {
        try {
          preprocessor[i][j].join();
        } catch (InterruptedException e) {
          // Interrupted.
        }
      }
    }

    long time = System.currentTimeMillis() - start;

    Log.info("Skymap preprocessing took " + time + "ms");

  }

  @Override public void getColor(double u, double v, Vector4 c) {
    ColorUtil.getRGBComponents(image.getPixel((int) (u * width - Ray.EPSILON),
        (int) ((1 - v) * height - Ray.EPSILON)), c);
  }

  /**
   * Get skymap color at (x, y).
   */
  public void getColor(int x, int y, Vector4 c) {
    ColorUtil.getRGBComponents(image.getPixel(x, y), c);
  }

  @Override public void getColor(Ray ray) {
    throw new UnsupportedOperationException();
  }

  @Override public float[] getColor(double u, double v) {
    throw new UnsupportedOperationException();
  }

  @Override public void getColorInterpolated(double u, double v, Vector4 c) {
    double x = u * (width - 1);
    double y = (1 - v) * (height - 1);
    double weight;
    int fx = (int) QuickMath.floor(x);
    int cx = (int) QuickMath.ceil(x);
    int fy = (int) QuickMath.floor(y);
    int cy = (int) QuickMath.ceil(y);

    double r, g, b;
    getColor(fx, fy, c);
    weight = (1 - (y - fy)) * (1 - (x - fx));
    r = weight * c.x;
    g = weight * c.y;
    b = weight * c.z;
    getColor(cx, fy, c);
    weight = (1 - (y - fy)) * (1 - (cx - x));
    r += weight * c.x;
    g += weight * c.y;
    b += weight * c.z;
    getColor(fx, cy, c);
    weight = (1 - (cy - y)) * (1 - (x - fx));
    r += weight * c.x;
    g += weight * c.y;
    b += weight * c.z;
    getColor(cx, cy, c);
    weight = (1 - (cy - y)) * (1 - (cx - x));
    r += weight * c.x;
    g += weight * c.y;
    b += weight * c.z;
    c.set(r, g, b, 1);
  }

  @Override public int getColorWrapped(int u, int v) {
    throw new UnsupportedOperationException();
  }

  @Override public int getAvgColor() {
    throw new UnsupportedOperationException();
  }

  @Override public void getAvgColorLinear(Vector4 c) {
    throw new UnsupportedOperationException();
  }

  @Override public int getWidth() {
    return super.getWidth();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy