Атлас спрайтов теперь более менее рабочий

This commit is contained in:
DBotThePony 2022-12-31 00:16:49 +07:00
parent 8ef4ab0eb1
commit 7697efeb50
Signed by: DBot
GPG Key ID: DCC23B5715498507
4 changed files with 114 additions and 6 deletions
src/main/kotlin/ru/dbotthepony/kstarbound

View File

@ -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))
}

View File

@ -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()

View File

@ -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<String, AtlasDefinition>()

View File

@ -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)
}
}