Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation for CachedMeshContent #105

Merged
merged 5 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import org.vitrivr.engine.core.model.mesh.texturemodel.Model3d
* @author Rahel Arnold
* @version 1.0.0
*/
interface Model3DContent : ContentElement<Model3d> {
/** The [ContentType] of a [Model3DContent] is always [ContentType.MESH]. */
interface Model3dContent : ContentElement<Model3d> {
/** The [ContentType] of a [Model3dContent] is always [ContentType.MESH]. */

override val type: ContentType
get() = ContentType.MESH
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@ import io.github.oshai.kotlinlogging.KLogger
import io.github.oshai.kotlinlogging.KotlinLogging
import org.vitrivr.engine.core.context.Context
import org.vitrivr.engine.core.model.content.element.*
import org.vitrivr.engine.core.model.content.impl.cache.CachedAudioContent
import org.vitrivr.engine.core.model.content.impl.cache.CachedContent
import org.vitrivr.engine.core.model.content.impl.cache.CachedImageContent
import org.vitrivr.engine.core.model.content.impl.cache.CachedTextContent
import org.vitrivr.engine.core.model.content.impl.memory.InMemoryMeshContent
import org.vitrivr.engine.core.model.content.impl.cache.*
import org.vitrivr.engine.core.model.mesh.texturemodel.Model3d
import org.vitrivr.engine.core.model.metamodel.Schema
import java.awt.image.BufferedImage
Expand Down Expand Up @@ -118,10 +114,10 @@ class CachedContentFactory : ContentFactoriesFactory {
return content
}

override fun newMeshContent(model3d: Model3d): Model3DContent {
override fun newMeshContent(model3d: Model3d): Model3dContent {
check(!this.closed) { "CachedContentFactory has been closed." }
val content = InMemoryMeshContent(model3d) /* TODO: Caching. */
logger.warn { "Caching of MeshContent is not yet implemented. Using in-memory content instead." }
val content = CachedModel3dContent(this.nextPath(), model3d)
this.refSet.add(CachedItem(content, this.referenceQueue))
return content
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package org.vitrivr.engine.core.model.content.factory

import org.vitrivr.engine.core.model.content.element.AudioContent
import org.vitrivr.engine.core.model.content.element.ImageContent
import org.vitrivr.engine.core.model.content.element.Model3DContent
import org.vitrivr.engine.core.model.content.element.Model3dContent
import org.vitrivr.engine.core.model.content.element.TextContent
import org.vitrivr.engine.core.model.mesh.texturemodel.Model3d
import java.awt.image.BufferedImage
Expand All @@ -15,5 +15,5 @@ interface ContentFactory {

fun newTextContent(text: String): TextContent

fun newMeshContent(model3d: Model3d): Model3DContent
fun newMeshContent(model3d: Model3d): Model3dContent
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ package org.vitrivr.engine.core.model.content.factory

import org.vitrivr.engine.core.context.Context
import org.vitrivr.engine.core.model.content.element.ContentElement
import org.vitrivr.engine.core.model.content.element.Model3DContent
import org.vitrivr.engine.core.model.content.element.Model3dContent
import org.vitrivr.engine.core.model.content.element.TextContent
import org.vitrivr.engine.core.model.content.impl.memory.InMemoryAudioContent
import org.vitrivr.engine.core.model.content.impl.memory.InMemoryImageContent
import org.vitrivr.engine.core.model.content.impl.memory.InMemoryMeshContent
import org.vitrivr.engine.core.model.content.impl.memory.InMemoryModel3dContent
import org.vitrivr.engine.core.model.content.impl.memory.InMemoryTextContent
import org.vitrivr.engine.core.model.mesh.texturemodel.Model3d
import org.vitrivr.engine.core.model.metamodel.Schema
Expand All @@ -21,10 +21,10 @@ import java.nio.ShortBuffer
*/
class InMemoryContentFactory : ContentFactoriesFactory {
override fun newContentFactory(schema: Schema, context: Context): ContentFactory = Instance()
private class Instance() : ContentFactory {
private class Instance : ContentFactory {
override fun newImageContent(bufferedImage: BufferedImage) = InMemoryImageContent(bufferedImage)
override fun newAudioContent(channels: Short, sampleRate: Int, audio: ShortBuffer) = InMemoryAudioContent(channels, sampleRate, audio)
override fun newTextContent(text: String): TextContent = InMemoryTextContent(text)
override fun newMeshContent(model3d: Model3d): Model3DContent = InMemoryMeshContent(model3d)
override fun newMeshContent(model3d: Model3d): Model3dContent = InMemoryModel3dContent(model3d)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import java.nio.ShortBuffer
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardOpenOption
import java.util.*

/**
* A [AudioContent] implementation that is backed by a cache file.
Expand All @@ -29,6 +28,7 @@ class CachedAudioContent(override val path: Path, override val channels: Short,

/** The audio samples contained in this [CachedAudioContent]. */
override val content: ShortBuffer
@Synchronized
get() {
var buffer = this.reference.get()
if (buffer == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import java.lang.ref.SoftReference
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardOpenOption
import java.util.*
import javax.imageio.ImageIO

/**
Expand All @@ -29,6 +28,7 @@ class CachedImageContent(override val path: Path, image: BufferedImage, override

/** The [BufferedImage] contained in this [CachedImageContent]. */
override val content: BufferedImage
@Synchronized
get() {
var image = this.reference.get()
if (image == null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package org.vitrivr.engine.core.model.content.impl.cache

import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import org.vitrivr.engine.core.model.content.element.ContentId
import org.vitrivr.engine.core.model.content.element.Model3dContent
import org.vitrivr.engine.core.model.mesh.texturemodel.Model3d
import java.lang.ref.SoftReference
import java.nio.charset.StandardCharsets
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardOpenOption

/**
* A [Model3dContent] implementation that is backed by a cache file.
*
* This class caches a 3D model to disk in JSON format and uses a [SoftReference] to hold it in memory,
* reloading from JSON if necessary.
*
* @author Rahel Arnold
* @version 1.0.0
*/
class CachedModel3dContent(override val path: Path, model: Model3d, override val id: ContentId = ContentId.randomUUID()) : Model3dContent, CachedContent {

/** The [SoftReference] of the [Model3d] used for caching. */
private var reference: SoftReference<Model3d> = SoftReference(model)

/** The [Model3d] contained in this [CachedModel3dContent]. */
override val content: Model3d
@Synchronized
get() {
var cachedModel = reference.get()
if (cachedModel == null) {
cachedModel = reload()
reference = SoftReference(cachedModel)
}
return cachedModel
}

init {
/* Serialize the Model3d to JSON and write it to the cache file during initialization. */
Files.newBufferedWriter(this.path, StandardCharsets.UTF_8, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE).use { writer ->
writer.write(Json.encodeToString(model))
}
}

/**
* Reloads the [Model3d] from the cached JSON file.
*
* @return The [Model3d] loaded from the JSON file.
*/
private fun reload(): Model3d {
return Files.newBufferedReader(this.path, StandardCharsets.UTF_8).use { reader ->
Json.decodeFromString(reader.readText())
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import java.lang.ref.SoftReference
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardOpenOption
import java.util.*

/**
* A [TextContent] implementation that is backed by a cache file.
Expand All @@ -24,6 +23,7 @@ class CachedTextContent(override val path: Path, text: String, override val id:

/** The [String] contained in this [CachedTextContent]. */
override val content: String
@Synchronized
get() {
var image = this.reference.get()
if (image == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ package org.vitrivr.engine.core.model.content.impl.memory

import org.vitrivr.engine.core.model.content.element.ContentId
import org.vitrivr.engine.core.model.content.element.ImageContent
import org.vitrivr.engine.core.model.content.element.Model3DContent
import org.vitrivr.engine.core.model.content.element.Model3dContent
import org.vitrivr.engine.core.model.mesh.texturemodel.Model3d

/**
* A naive in-memory implementation of the [ImageContent] interface.
*
* Warning: Usage of [InMemoryMeshContent] may lead to out-of-memory situations in large extraction pipelines.
* Warning: Usage of [InMemoryModel3dContent] may lead to out-of-memory situations in large extraction pipelines.
*
* @author Luca Rossetto.
* @version 1.0.0
*/
data class InMemoryMeshContent(override val content: Model3d, override val id: ContentId = ContentId.randomUUID()) : Model3DContent
data class InMemoryModel3dContent(override val content: Model3d, override val id: ContentId = ContentId.randomUUID()) : Model3dContent
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Logger
import org.vitrivr.engine.core.model.mesh.texturemodel.util.types.Matrix4f
import org.vitrivr.engine.core.model.mesh.texturemodel.util.types.Quaternionf
import kotlinx.serialization.Serializable

/**
* An Entity in the context of a [Model3d] describes a position and scale of a model in the scene.
Expand All @@ -14,6 +15,7 @@ import org.vitrivr.engine.core.model.mesh.texturemodel.util.types.Quaternionf
* It does not change the mesh of the model.
* Neither does it change the viewpoint of the camera.
*/
@Serializable
class Entity(val id: String, val modelId: String) {

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package org.vitrivr.engine.core.model.mesh.texturemodel

import kotlinx.serialization.Serializable
import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Logger
import org.vitrivr.engine.core.model.mesh.texturemodel.util.MinimalBoundingBox
import org.vitrivr.engine.core.model.mesh.texturemodel.util.types.Vec4f
import java.io.Serializable
import java.io.Serializable as JavaSerializable
import java.util.*

/**
* The Material contains all meshes and the texture that are drawn with on the meshes.
* Further, it contains the diffuse color of the material.
*/
class Material : Serializable {
@Serializable
class Material : JavaSerializable {

/**
* List of [Mesh] objects that define the appearance of the model.
Expand Down Expand Up @@ -42,6 +44,26 @@ class Material : Serializable {
val EMPTY = Material()
}

override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Material) return false

return materialMeshes == other.materialMeshes &&
materialTexture == other.materialTexture &&
materialDiffuseColor == other.materialDiffuseColor
}

override fun hashCode(): Int {
var result = materialMeshes.hashCode()
result = 31 * result + (materialTexture?.hashCode() ?: 0)
result = 31 * result + materialDiffuseColor.hashCode()
return result
}

override fun toString(): String {
return "Material(materialMeshes=$materialMeshes, materialTexture=$materialTexture, materialDiffuseColor=$materialDiffuseColor)"
}

/**
* @return A MinimalBoundingBox which encloses all MinimalBoundingBoxes from containing meshes.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package org.vitrivr.engine.core.model.mesh.texturemodel

import kotlinx.serialization.Serializable
import org.vitrivr.engine.core.model.mesh.texturemodel.util.types.Vec3f
import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Logger
import org.vitrivr.engine.core.model.mesh.texturemodel.util.MinimalBoundingBox
import java.io.Serializable
import java.io.Serializable as JavaSerializable
import kotlin.math.sign
import kotlin.math.sqrt

Expand All @@ -13,6 +14,7 @@ import kotlin.math.sqrt
* It contains the vertices, faces, normals, and texture coordinates.
* It also constructs the face normals and the minimal bounding box.
*/
@Serializable
class Mesh(
/**
* List of all vertices in the mesh.
Expand Down Expand Up @@ -43,12 +45,32 @@ class Mesh(
* face2 = (3, 1, 2)
*/
private val idx: IntArray
) : Serializable {
) : JavaSerializable {

companion object {
private val LOGGER: Logger = LogManager.getLogger()
}

override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Mesh) return false

if (!positions.contentEquals(other.positions)) return false
if (!normals.contentEquals(other.normals)) return false
if (!textureCoords.contentEquals(other.textureCoords)) return false
if (!idx.contentEquals(other.idx)) return false

return true
}

override fun hashCode(): Int {
var result = positions.contentHashCode()
result = 31 * result + (normals?.contentHashCode() ?: 0)
result = 31 * result + textureCoords.contentHashCode()
result = 31 * result + idx.contentHashCode()
return result
}

/**
* Number of all vertices in the mesh.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@ import org.vitrivr.engine.core.model.mesh.texturemodel.util.types.Vec3f
import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Logger
import org.vitrivr.engine.core.model.mesh.texturemodel.util.MinimalBoundingBox
import java.io.Serializable
import java.io.Serializable as JavaSerializable
import java.util.*
import java.util.function.Consumer
import kotlinx.serialization.Serializable

/**
* This class represents a 3d model that can be rendered by the [Engine]. The 3d3 model is composed of a
* list of [Entity] objects and a list of [Material] objects. The [Entity] objects are used to
* position and scale the 3d model in the scene. The [Material] objects are used to define the
* appearance of the 3d model.
*/
@Serializable
data class Model3d(
/** ID of the 3d model. */
val modelId: String,
Expand All @@ -22,7 +24,7 @@ data class Model3d(
* Textures that are used by the 3d model.
*/
val modelMaterials: MutableList<Material>
) : IModel, Serializable {
) : IModel, JavaSerializable {
/** List of [Entity] objects that define the position and scale of the 3d model. */
private val entities: MutableList<Entity> = ArrayList()

Expand Down
Loading