From 7697efeb5026b10c8f7da000eb0a359830ea0c56 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 31 Dec 2022 00:16:49 +0700 Subject: [PATCH] =?UTF-8?q?=D0=90=D1=82=D0=BB=D0=B0=D1=81=20=D1=81=D0=BF?= =?UTF-8?q?=D1=80=D0=B0=D0=B9=D1=82=D0=BE=D0=B2=20=D1=82=D0=B5=D0=BF=D0=B5?= =?UTF-8?q?=D1=80=D1=8C=20=D0=B1=D0=BE=D0=BB=D0=B5=D0=B5=20=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=B5=D0=B5=20=D1=80=D0=B0=D0=B1=D0=BE=D1=87=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kstarbound/client/render/BoundSprite.kt | 58 +++++++++++++++++++ .../client/render/entity/ItemRenderer.kt | 5 +- .../defs/animation/AtlasDefinition.kt | 50 +++++++++++++++- .../defs/animation/UVCoordinates.kt | 7 ++- 4 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/kstarbound/client/render/BoundSprite.kt diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/BoundSprite.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/BoundSprite.kt new file mode 100644 index 00000000..a435856b --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/BoundSprite.kt @@ -0,0 +1,58 @@ +package ru.dbotthepony.kstarbound.client.render + +import ru.dbotthepony.kstarbound.client.gl.GLStateTracker +import ru.dbotthepony.kstarbound.client.gl.GLTexture2D +import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers +import ru.dbotthepony.kstarbound.defs.animation.IUVCoordinates +import ru.dbotthepony.kstarbound.defs.animation.SpriteReference + +/** + * Связка текстуры-атласа + координат спрайта на ней + */ +class BoundSprite( + val reference: SpriteReference, + val texture: GLTexture2D +) : IUVCoordinates { + inline val sprite get() = reference.sprite + + /** + * Настоящая ширина спрайта, в пикселях + */ + inline val width get() = reference.sprite.width(texture.width) + + /** + * Настоящая высота спрайта, в пикселях + */ + inline val height get() = reference.sprite.height(texture.height) + + override val u0: Float + override val v0: Float + override val u1: Float + override val v1: Float + + init { + val coords = reference.sprite.compute(texture) + + this.u0 = coords.u0 + this.v0 = coords.v0 + this.u1 = coords.u1 + this.v1 = coords.v1 + } + + fun bind() = texture.bind() + val transformer = QuadTransformers.uv(u0, v0, u1, v1) +} + +/** + * Создаёт связку текстуры-атласа + координгат спрайта на ней + */ +fun SpriteReference.bind(texture: GLTexture2D): BoundSprite { + return BoundSprite(this, texture) +} + +/** + * Создаёт связку текстуры-атласа, которая загружается через [GLStateTracker.loadNamedTextureSafe] + координгат спрайта на ней + */ +fun SpriteReference.bind(state: GLStateTracker): BoundSprite { + return BoundSprite(this, state.loadNamedTextureSafe(path)) +} diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/entity/ItemRenderer.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/entity/ItemRenderer.kt index bae774ea..4fab5b79 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/entity/ItemRenderer.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/entity/ItemRenderer.kt @@ -5,12 +5,13 @@ import ru.dbotthepony.kstarbound.client.ClientChunk import ru.dbotthepony.kstarbound.client.gl.GLStateTracker import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers import ru.dbotthepony.kstarbound.client.gl.vertex.quadRotatedZ +import ru.dbotthepony.kstarbound.client.render.bind import ru.dbotthepony.kstarbound.world.entities.ItemEntity import ru.dbotthepony.kvector.matrix.Matrix4fStack class ItemRenderer(state: GLStateTracker, entity: ItemEntity, chunk: ClientChunk?) : EntityRenderer(state, entity, chunk) { private val def = entity.def - private val textures = def.inventoryIcon?.stream()?.map { state.loadNamedTextureSafe(it.image.path) }?.toList() ?: listOf() + private val textures = def.inventoryIcon?.stream()?.map { it.image.bind(state) }?.toList() ?: listOf() override fun render(stack: Matrix4fStack) { if (textures.isEmpty()) @@ -31,7 +32,7 @@ class ItemRenderer(state: GLStateTracker, entity: ItemEntity, chunk: ClientChunk val width = (texture.width / PIXELS_IN_STARBOUND_UNITf) / 2f val height = (texture.height / PIXELS_IN_STARBOUND_UNITf) / 2f - builder.quadRotatedZ(-width, -height, width, height, 5f, 0f, 0f, entity.movement.angle, QuadTransformers.uv(0f, 1f, 1f, 0f)) + builder.quadRotatedZ(-width, -height, width, height, 5f, 0f, 0f, entity.movement.angle, texture.transformer) builder.upload() builder.draw() diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/animation/AtlasDefinition.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/animation/AtlasDefinition.kt index 2c312072..30f5fd6f 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/animation/AtlasDefinition.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/animation/AtlasDefinition.kt @@ -18,8 +18,13 @@ import java.util.concurrent.ConcurrentHashMap * Атлас спрайтов, собранный вручную артистом * * В файлах игры именуется frames + * + * Несмотря на название, НЕ ЯВЛЯЕТСЯ изображением, а лишь метаданными для *множества* возможных изображений */ class AtlasDefinition private constructor( + /** + * Имя данного атласа (путь к файлу) + */ val name: String, /** @@ -64,18 +69,57 @@ class AtlasDefinition private constructor( /** * Позиция и размеры данного спрайта, в пикселях + * + * Нулевой размер имеет особое значение - считается, что спрайт покрывает весь атлас */ val position: Vector4i, ) { + /** + * Ширина, в пикселях + * + * Нулевой размер имеет особое значение - считается, что спрайт покрывает весь атлас + */ + val width = position.x - position.z + + /** + * Высота, в пикселях + * + * Нулевой размер имеет особое значение - считается, что спрайт покрывает весь атлас + */ + val height = position.y - position.w + + fun width(atlasWidth: Int): Int { + if (width == 0) + return atlasWidth + + return width + } + + fun height(atlasHeight: Int): Int { + if (height == 0) + return atlasHeight + + return height + } + /** * Вычисляет uv координаты данного спрайта на заданном полотне + * + * v вычисляется инвентированным, для учёта системы координат OpenGL */ fun compute(width: Int, height: Int): UVCoordinates { + require(width > 0) { "Invalid width provided: $width" } + require(height > 0) { "Invalid height provided: $height" } + + if (this.width == 0 || this.height == 0) { + return UVCoordinates.FULL_OPENGL + } + return UVCoordinates( u0 = position.x.toFloat() / width.toFloat(), - v0 = position.y.toFloat() / height.toFloat(), + v1 = position.y.toFloat() / height.toFloat(), u1 = position.z.toFloat() / width.toFloat(), - v1 = position.w.toFloat() / height.toFloat(), + v0 = position.w.toFloat() / height.toFloat(), ) } @@ -99,7 +143,7 @@ class AtlasDefinition private constructor( } companion object { - val EMPTY = AtlasDefinition("null", ImmutableMap.of("root", Sprite("root", Vector4i(0, 0, 1, 1)))) + val EMPTY = AtlasDefinition("null", ImmutableMap.of("root", Sprite("root", Vector4i(0, 0, 0, 0)))) private val cache = ConcurrentHashMap() diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/animation/UVCoordinates.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/animation/UVCoordinates.kt index e91dd61a..f8e45e7b 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/animation/UVCoordinates.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/animation/UVCoordinates.kt @@ -5,4 +5,9 @@ data class UVCoordinates( override val v0: Float, override val u1: Float, override val v1: Float, -) : IUVCoordinates +) : IUVCoordinates { + companion object { + val FULL = UVCoordinates(0f, 0f, 1f, 1f) + val FULL_OPENGL = UVCoordinates(0f, 1f, 1f, 0f) + } +}