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

simplex3d.engine.graphics.Texture.scala Maven / Gradle / Ivy

/*
 * Simplex3dEngine - Core Module
 * Copyright (C) 2011, Aleksey Nikiforov
 *
 * This file is part of Simplex3dEngine.
 *
 * Simplex3dEngine is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Simplex3dEngine 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see .
 */

package simplex3d.engine
package graphics

import scala.reflect._
import simplex3d.math.types._
import simplex3d.math._
import simplex3d.math.double._
import simplex3d.math.double.functions._
import simplex3d.data.extension._
import simplex3d.data._
import simplex3d.data.double._
import simplex3d.engine.util._


trait Concrete

abstract class Texture[A <: Accessor] private[engine] (
  @transient protected val accessible: ReadData[A] with DirectSrc with ContiguousSrc,
  protected val linked: DirectSrc with ContiguousSrc
)
extends EngineInfoRef {
  
  type Accessor = A with simplex3d.data.Accessor
  
  def bindingDimensions: AnyVec[Int]//XXX possibly simplify to dimensions?
  
  protected var dataChanges = true
    
  private[engine] def hasDataChanges = dataChanges
  private[engine] def clearDataChanges() { dataChanges = false }
  
  
  {
    var count = 0
    if (accessible != null) count += 1
    if (linked != null) count += 1
    
    if (count != 1) throw new IllegalArgumentException("Data source must not be null.")
  }

  
  def isAccessible = (accessible != null)
  def isWritable = (isAccessible && !accessible.isReadOnly)
  
  def read: ReadData[A] with DirectSrc with ContiguousSrc = {
    if (isAccessible) accessible.asReadOnly().asInstanceOf[ReadData[A] with DirectSrc with ContiguousSrc]
    else throw new IllegalAccessException("Texture data is not accessible.")
  }
  
  def write: Data[A] with DirectSrc with ContiguousSrc = {
    if (isWritable) {
      dataChanges = true
      accessible.asInstanceOf[Data[A] with DirectSrc with ContiguousSrc]
    }
    else throw new IllegalAccessException("Texture data is not writable.")
  }
  
  def src: DirectSrc with ContiguousSrc = if (isAccessible) accessible else linked
  
  
  // *** Parameters ***************************************************************************************************
  protected var parameterChanges = true
  private[engine] def hasParameterChanges = parameterChanges//XXX bridge via AnyVal proxy
  private[engine] def clearParameterChanges() { parameterChanges = false }//XXX bridge via AnyVal proxy
  
  private var _magFilter: ImageFilter.Value = ImageFilter.Linear
  def magFilter = _magFilter
  def magFilter_=(filter: ImageFilter.Value) { parameterChanges = true; _magFilter = filter }
  
  private var _minFilter: ImageFilter.Value = ImageFilter.Linear
  def minFilter = _minFilter
  def minFilter_=(filter: ImageFilter.Value) { parameterChanges = true; _minFilter = filter }
  
  private var _mipMapFilter: MipMapFilter.Value = MipMapFilter.Linear
  def mipMapFilter = _mipMapFilter
  def mipMapFilter_=(filter: MipMapFilter.Value) { parameterChanges = true; _mipMapFilter = filter }
  
  private var _anisotropyLevel: Double = 4
  def anisotropyLevel = _anisotropyLevel
  def anisotropyLevel_=(level: Double) { parameterChanges = true; _anisotropyLevel = max(1, level) }
  
  private val _borderColor = Vec4(0)
  def borderColor: ReadVec4 = _borderColor
  def borderColor_=(color: inVec4) { parameterChanges = true; _borderColor := color }
}


object MipMapFilter extends Enumeration {
  val Disabled, Nearest, Linear = Value
}
object ImageFilter extends Enumeration {
  val Nearest, Linear = Value
}

object TextureWrap extends Enumeration {
  val ClampToEdge, ClampToBorder, MirrorRepeat, Repeat = Value
}


class Texture2d[A <: Accessor] private (
  final val dimensions: ConstVec2i,
  accessible: ReadData[A] with DirectSrc with ContiguousSrc,
  linked: DirectSrc with ContiguousSrc
)
extends Texture[A](accessible, linked) with Concrete
{
  
  if (accessible != null) {
    if (dimensions.x < 0 || dimensions.x < 0) throw new IllegalArgumentException(
      "Dimensions = " + dimensions + " contain negative components."
    )
    if (accessible.size != dimensions.x*dimensions.y) throw new IllegalArgumentException(
      "Texture dimensions do not match data size."
    )
  }
  
  
  final def bindingDimensions = dimensions
  
  
  /** Fill the texture with pixels obtained from the function.
   * 
   * @param function (dimensions, pixelCoordinates) => pixelValue
   */
  def fillWith(function: inVec2 => A#Read) :this.type = {
    val data = this.write
    
    var y = 0; while (y < dimensions.y) {
      renderLine(data, function, y)
      
      y += 1
    }
    
    this
  }
  private[this] final def renderLine = (data: Data[A], function: inVec2 => A#Read, y: Int) => {
    val pixel = Vec2(0, y)

    var x = 0; while (x < dimensions.x) { val i = x + y*dimensions.x
      
      pixel.x = x
      data(i) = function(pixel)
      
      x += 1
    }
  }
  
  
  private var _wrapS: TextureWrap.Value = TextureWrap.Repeat
  def wrapS = _wrapS
  def wrapS_=(wrapValue: TextureWrap.Value) { parameterChanges = true; _wrapS = wrapValue }
  
  private var _wrapT: TextureWrap.Value = TextureWrap.Repeat
  def wrapT = _wrapT
  def wrapT_=(wrapValue: TextureWrap.Value) { parameterChanges = true; _wrapT = wrapValue }
}


object Texture2d {
  val Tag = classTag[Texture2d[_]]
  
  def apply[F <: Format { type Component = RDouble; type Accessor <: simplex3d.data.Accessor }](
    dimensions: ConstVec2i
  )(implicit
    composition: CompositionFactory[F, _ >: UByte]
  )
  :Texture2d[F#Accessor] =
  {
    val primitive = implicitly[PrimitiveFactory[RDouble, UByte]]
    val data = composition.mkDataBuffer(primitive.mkDataBuffer(dimensions.x*dimensions.y*composition.components))
    new Texture2d[F#Accessor](dimensions, data, null)
  }
  
  def fromData[A <: Accessor](
    dimensions: ConstVec2i, data: ReadData[A] with DirectSrc with ContiguousSrc
  )
  :Texture2d[A] = {
    new Texture2d(dimensions, data, null)
  }

  def fromUncheckedSrc[A <: Accessor](
    dimensions: ConstVec2i, src: DirectSrc with ContiguousSrc
  )(implicit accessorTag: ClassTag[A]) :Texture2d[A] = {
    
    if (src.accessorTag != accessorTag) throw new IllegalArgumentException(
      "Data accessor type doest not match the tag.")
    
    if (src.isInstanceOf[Data[_]]) {
      fromData(dimensions, src.asInstanceOf[Data[A] with DirectSrc with ContiguousSrc])
    }
    else {
      new Texture2d(dimensions, null, src)
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy