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

cwinter.codecraft.graphics.model.CompositeModelBuilder.scala Maven / Gradle / Ivy

package cwinter.codecraft.graphics.model

import cwinter.codecraft.graphics.engine.GraphicsContext
import cwinter.codecraft.graphics.materials.Material
import cwinter.codecraft.util.maths.{Vertex, VertexXYZ}

import scala.collection.mutable
import scala.collection.mutable.ListBuffer


private[codecraft] trait CompositeModelBuilder[TStatic <: AnyRef, TDynamic]
    extends ModelBuilder[TStatic, TDynamic] {
  protected def buildSubcomponents: (Seq[ModelBuilder[_, Unit]], Seq[ModelBuilder[_, TDynamic]])

  def subcomponents(context: GraphicsContext): (Seq[ModelBuilder[_, Unit]], Seq[ModelBuilder[_, TDynamic]]) =
    if (isCacheable) context.modelBuilderCache.getOrElseUpdate(signature)(optimized.buildSubcomponents)
    else buildSubcomponents

  def buildModel(context: GraphicsContext): Model[TDynamic] = {
    val (staticComponents, dynamicComponents) = subcomponents(context)
    val model = CompositeModel(
      staticComponents.map(_.getModel(context)),
      dynamicComponents.map(_.getModel(context))
    )
    decorate(model, context)
  }

  protected def decorate(model: Model[TDynamic], context: GraphicsContext): Model[TDynamic] = model


  override def optimized: CompositeModelBuilder[TStatic, TDynamic] = {
    val (allStatic, allDynamic) = flatten

    val compactedStatic = compact(allStatic)

    val self = this
    new CompositeModelBuilder[TStatic, TDynamic] {
      override def decorate(model: Model[TDynamic], context: GraphicsContext) =
        self.decorate(model, context)
      override def signature = self.signature
      override def buildSubcomponents = (compactedStatic, allDynamic)
    }
  }

  def flatten: (mutable.UnrolledBuffer[ModelBuilder[_, Unit]], mutable.UnrolledBuffer[ModelBuilder[_, TDynamic]]) = {
    val allStatic = mutable.UnrolledBuffer.empty[ModelBuilder[_, Unit]]
    val allDynamic = mutable.UnrolledBuffer.empty[ModelBuilder[_, TDynamic]]

    val (staticComponents, dynamicComponents) = buildSubcomponents

    for (static <- staticComponents) static match {
      case compositeChild: CompositeModelBuilder[_, Unit] =>
        val (static1, static2) = compositeChild.flatten
        allStatic concat static1
        allStatic concat static2
      case other => allStatic append other.optimized
    }

    for (dynamic <- dynamicComponents) dynamic match {
      case compositeChild: CompositeModelBuilder[_, TDynamic] =>
        val (static1, dynamic1) = compositeChild.flatten
        allStatic concat static1
        allDynamic concat dynamic1
      case other => allDynamic append other.optimized
    }

    (allStatic, allDynamic)
  }

  def compact(models: Seq[ModelBuilder[_, Unit]]): Seq[ModelBuilder[_, Unit]] = {
    val (compactable, other) =
      models
        .partition(isCompactable)
        .asInstanceOf[(Seq[ModelBuilder[_, TDynamic]], Seq[ModelBuilder[_, Unit]])]

    val groupedCompactables =
      compactable.groupBy {
        case p: PrimitiveModelBuilder[_, _, _] => p.material
        case c: VertexCollectionModelBuilder[_] => c.material
        case x => throw new Exception(s"Trying to compact model builder of type ${x.getClass}")
      }

    val compactedPrimitives =
      for ((material, compactables) <- groupedCompactables) yield {
        if (compactables.size == 1) compactables.head
        else {
          val allVertices = ListBuffer.empty[Seq[(VertexXYZ, Vertex)]]
          for (compactable <- compactables) compactable match {
            case p: PrimitiveModelBuilder[_, _, _] =>
              allVertices.append(p.getVertexData)
            case c: VertexCollectionModelBuilder[_] =>
              for (vertices <- c.vertexData)
                allVertices.append(vertices)
          }
          VertexCollectionModelBuilder(allVertices.toList, material.asInstanceOf[Material[VertexXYZ, Vertex, Unit]])
        }
      }

    compactedPrimitives.toSeq.asInstanceOf[Seq[ModelBuilder[_, Unit]]] ++ other
  }

  private def isCompactable(modelBuilder: ModelBuilder[_, Unit]): Boolean =
    modelBuilder.isInstanceOf[PrimitiveModelBuilder[_, _ , Unit]] ||
    modelBuilder.isInstanceOf[VertexCollectionModelBuilder[_]]
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy