Отрисовка фоновых тайлов!
This commit is contained in:
parent
3962eec095
commit
5b03608527
@ -144,17 +144,17 @@ private fun loop() {
|
|||||||
var y = 0
|
var y = 0
|
||||||
|
|
||||||
for (tile in Starbound.tilesAccess.values) {
|
for (tile in Starbound.tilesAccess.values) {
|
||||||
chunk.foreground[x, y + 1] = tile
|
chunk.background[x, y + 1] = tile
|
||||||
chunk.foreground[x++, y] = tile
|
chunk.background[x++, y] = tile
|
||||||
chunk.foreground[x, y + 1] = tile
|
chunk.background[x, y + 1] = tile
|
||||||
chunk.foreground[x++, y] = tile
|
chunk.background[x++, y] = tile
|
||||||
chunk.foreground[x, y + 1] = tile
|
chunk.background[x, y + 1] = tile
|
||||||
chunk.foreground[x++, y] = tile
|
chunk.background[x++, y] = tile
|
||||||
chunk.foreground[x, y + 1] = tile
|
chunk.background[x, y + 1] = tile
|
||||||
chunk.foreground[x++, y] = tile
|
chunk.background[x++, y] = tile
|
||||||
chunk.foreground[x, y + 1] = tile
|
chunk.background[x, y + 1] = tile
|
||||||
chunk.foreground[x++, y] = tile
|
chunk.background[x++, y] = tile
|
||||||
chunk.foreground[x, y + 1] = tile
|
chunk.background[x, y + 1] = tile
|
||||||
|
|
||||||
if (x >= 32) {
|
if (x >= 32) {
|
||||||
x = 0
|
x = 0
|
||||||
@ -162,6 +162,14 @@ private fun loop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val tile = Starbound.getTileDefinition("glass")
|
||||||
|
|
||||||
|
for (x in 0 .. 32) {
|
||||||
|
for (y in 0 .. 32) {
|
||||||
|
chunk.foreground[x, y] = tile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
for (x in 0 .. 24) {
|
for (x in 0 .. 24) {
|
||||||
for (y in 0 .. 24) {
|
for (y in 0 .. 24) {
|
||||||
@ -170,7 +178,7 @@ private fun loop() {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
val chunkRenderer = ChunkRenderer(state, chunk)
|
val chunkRenderer = ChunkRenderer(state, chunk, Starbound.world)
|
||||||
chunkRenderer.tesselateStatic()
|
chunkRenderer.tesselateStatic()
|
||||||
chunkRenderer.uploadStatic()
|
chunkRenderer.uploadStatic()
|
||||||
|
|
||||||
|
@ -9,6 +9,6 @@ interface IStruct3f : IStruct2f {
|
|||||||
operator fun component3(): Float
|
operator fun component3(): Float
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IStruct4F : IStruct3f {
|
interface IStruct4f : IStruct3f {
|
||||||
operator fun component4(): Float
|
operator fun component4(): Float
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,10 @@ class GLShader(
|
|||||||
private set
|
private set
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
if (body == "") {
|
||||||
|
throw IllegalArgumentException("Shader source is empty")
|
||||||
|
}
|
||||||
|
|
||||||
glShaderSource(pointer, body)
|
glShaderSource(pointer, body)
|
||||||
glCompileShader(pointer)
|
glCompileShader(pointer)
|
||||||
|
|
||||||
@ -43,5 +47,17 @@ class GLShader(
|
|||||||
companion object {
|
companion object {
|
||||||
fun vertex(file: File) = GLShader(file, GL_VERTEX_SHADER)
|
fun vertex(file: File) = GLShader(file, GL_VERTEX_SHADER)
|
||||||
fun fragment(file: File) = GLShader(file, GL_FRAGMENT_SHADER)
|
fun fragment(file: File) = GLShader(file, GL_FRAGMENT_SHADER)
|
||||||
|
|
||||||
|
private fun readInternal(file: String): String {
|
||||||
|
return ClassLoader.getSystemClassLoader().getResourceAsStream(file)!!.bufferedReader()
|
||||||
|
.let {
|
||||||
|
val read = it.readText()
|
||||||
|
it.close()
|
||||||
|
return@let read
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun internalVertex(file: String) = GLShader(readInternal(file), GL_VERTEX_SHADER)
|
||||||
|
fun internalFragment(file: String) = GLShader(readInternal(file), GL_FRAGMENT_SHADER)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,9 @@ package ru.dbotthepony.kstarbound.gl
|
|||||||
|
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap
|
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
|
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
|
||||||
import org.lwjgl.opengl.GL41
|
|
||||||
import org.lwjgl.opengl.GL46.*
|
import org.lwjgl.opengl.GL46.*
|
||||||
import ru.dbotthepony.kstarbound.api.IStruct3f
|
import ru.dbotthepony.kstarbound.api.IStruct3f
|
||||||
import ru.dbotthepony.kstarbound.api.IStruct4F
|
import ru.dbotthepony.kstarbound.api.IStruct4f
|
||||||
import ru.dbotthepony.kstarbound.math.AbstractMatrix3f
|
import ru.dbotthepony.kstarbound.math.AbstractMatrix3f
|
||||||
import ru.dbotthepony.kstarbound.math.AbstractMatrix4f
|
import ru.dbotthepony.kstarbound.math.AbstractMatrix4f
|
||||||
import ru.dbotthepony.kstarbound.math.FloatMatrix
|
import ru.dbotthepony.kstarbound.math.FloatMatrix
|
||||||
@ -14,11 +13,11 @@ import kotlin.collections.HashSet
|
|||||||
|
|
||||||
class ShaderLinkException(reason: String) : RuntimeException(reason)
|
class ShaderLinkException(reason: String) : RuntimeException(reason)
|
||||||
|
|
||||||
data class Uniform4f(val x: Float, val y: Float, val z: Float, val w: Float) : IStruct4F
|
data class Uniform4f(val x: Float, val y: Float, val z: Float, val w: Float) : IStruct4f
|
||||||
data class Uniform3f(val x: Float, val y: Float, val z: Float) : IStruct3f
|
data class Uniform3f(val x: Float, val y: Float, val z: Float) : IStruct3f
|
||||||
|
|
||||||
class GLUniformLocation(val program: GLShaderProgram, val name: String, val pointer: Int) {
|
class GLUniformLocation(val program: GLShaderProgram, val name: String, val pointer: Int) {
|
||||||
fun set(value: IStruct4F): GLUniformLocation {
|
fun set(value: IStruct4f): GLUniformLocation {
|
||||||
program.state.ensureSameThread()
|
program.state.ensureSameThread()
|
||||||
val (v0, v1, v2, v3) = value
|
val (v0, v1, v2, v3) = value
|
||||||
glProgramUniform4f(program.pointer, pointer, v0, v1, v2, v3)
|
glProgramUniform4f(program.pointer, pointer, v0, v1, v2, v3)
|
||||||
@ -99,24 +98,25 @@ class GLShaderProgram(val state: GLStateTracker, vararg shaders: GLShader) {
|
|||||||
}).orElse(null)
|
}).orElse(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun set(name: String, value: Uniform4f) = this[name]?.set(value)
|
operator fun set(name: String, value: IStruct4f) = this[name]?.set(value)
|
||||||
operator fun set(name: String, value: Uniform3f) = this[name]?.set(value)
|
operator fun set(name: String, value: IStruct3f) = this[name]?.set(value)
|
||||||
operator fun set(name: String, value: Int) = this[name]?.set(value)
|
operator fun set(name: String, value: Int) = this[name]?.set(value)
|
||||||
operator fun set(name: String, value: FloatMatrix<*>) = this[name]?.set(value)
|
operator fun set(name: String, value: FloatMatrix<*>) = this[name]?.set(value)
|
||||||
|
|
||||||
fun attach(shader: GLShader) {
|
fun attach(shader: GLShader) {
|
||||||
state.ensureSameThread()
|
state.ensureSameThread()
|
||||||
check(!linked) { "Already linked!" }
|
check(!linked) { "Program is already linked!" }
|
||||||
|
|
||||||
if (!attached.add(shader)) {
|
if (!attached.add(shader)) {
|
||||||
throw IllegalStateException("Already attached! $shader")
|
throw IllegalStateException("Already attached! $shader")
|
||||||
}
|
}
|
||||||
|
require(!shader.unlinked) { "$shader is already unlinked, and thus can not be used" }
|
||||||
|
|
||||||
glAttachShader(pointer, shader.pointer)
|
glAttachShader(pointer, shader.pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun link() {
|
fun link() {
|
||||||
check(!linked) { "Already linked!" }
|
check(!linked) { "Program is already linked!" }
|
||||||
glLinkProgram(pointer)
|
glLinkProgram(pointer)
|
||||||
|
|
||||||
val success = intArrayOf(0)
|
val success = intArrayOf(0)
|
||||||
|
@ -204,13 +204,26 @@ class GLStateTracker {
|
|||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
val shaderVertexTexture = program(
|
val shaderVertexTexture: GLShaderProgram
|
||||||
GLShader.fragment(File("./src/main/resources/shaders/f_texture.glsl")),
|
val shaderVertexTextureColor: GLShaderProgram
|
||||||
GLShader.vertex(File("./src/main/resources/shaders/v_vertex_texture.glsl"))
|
|
||||||
).also {
|
init {
|
||||||
it.link()
|
val textureF = GLShader.internalFragment("shaders/fragment/texture.glsl")
|
||||||
it.unlinkChildren()
|
val textureColorF = GLShader.internalFragment("shaders/fragment/texture_color.glsl")
|
||||||
it["_transform"] = Matrix4f.IDENTITY
|
val textureV = GLShader.internalVertex("shaders/vertex/texture.glsl")
|
||||||
|
|
||||||
|
shaderVertexTexture = program(textureF, textureV)
|
||||||
|
shaderVertexTextureColor = program(textureColorF, textureV)
|
||||||
|
|
||||||
|
shaderVertexTexture.link()
|
||||||
|
shaderVertexTexture["_transform"] = Matrix4f.IDENTITY
|
||||||
|
|
||||||
|
shaderVertexTextureColor.link()
|
||||||
|
shaderVertexTextureColor["_transform"] = Matrix4f.IDENTITY
|
||||||
|
|
||||||
|
textureF.unlink()
|
||||||
|
textureColorF.unlink()
|
||||||
|
textureV.unlink()
|
||||||
}
|
}
|
||||||
|
|
||||||
val matrixStack = Matrix4fStack()
|
val matrixStack = Matrix4fStack()
|
||||||
|
@ -4,19 +4,27 @@ import com.google.gson.JsonArray
|
|||||||
import kotlin.math.cos
|
import kotlin.math.cos
|
||||||
import kotlin.math.sin
|
import kotlin.math.sin
|
||||||
|
|
||||||
data class Vector2i(val x: Int, val y: Int) : IMatrixLike, IMatrixLikeGetterI {
|
abstract class IVector2i<T : IVector2i<T>> : IMatrixLike, IMatrixLikeGetterI {
|
||||||
operator fun plus(other: Vector2i) = Vector2i(x + other.x, y + other.y)
|
|
||||||
operator fun plus(other: Int) = Vector2i(x + other, y + other)
|
|
||||||
operator fun minus(other: Vector2i) = Vector2i(x - other.x, y - other.y)
|
|
||||||
operator fun minus(other: Int) = Vector2i(x - other, y - other)
|
|
||||||
operator fun times(other: Vector2i) = Vector2i(x * other.x, y * other.y)
|
|
||||||
operator fun times(other: Int) = Vector2i(x * other, y * other)
|
|
||||||
operator fun div(other: Vector2i) = Vector2i(x / other.x, y / other.y)
|
|
||||||
operator fun div(other: Int) = Vector2i(x / other, y / other)
|
|
||||||
|
|
||||||
override val columns = 1
|
override val columns = 1
|
||||||
override val rows = 2
|
override val rows = 2
|
||||||
|
|
||||||
|
abstract val x: Int
|
||||||
|
abstract val y: Int
|
||||||
|
|
||||||
|
operator fun plus(other: IVector2i<*>) = make(x + other.x, y + other.y)
|
||||||
|
operator fun plus(other: Int) = make(x + other, y + other)
|
||||||
|
operator fun minus(other: IVector2i<*>) = make(x - other.x, y - other.y)
|
||||||
|
operator fun minus(other: Int) = make(x - other, y - other)
|
||||||
|
operator fun times(other: IVector2i<*>) = make(x * other.x, y * other.y)
|
||||||
|
operator fun times(other: Int) = make(x * other, y * other)
|
||||||
|
operator fun div(other: IVector2i<*>) = make(x / other.x, y / other.y)
|
||||||
|
operator fun div(other: Int) = make(x / other, y / other)
|
||||||
|
|
||||||
|
fun left() = make(x - 1, y)
|
||||||
|
fun right() = make(x + 1, y)
|
||||||
|
fun up() = make(x, y + 1)
|
||||||
|
fun down() = make(x, y - 1)
|
||||||
|
|
||||||
override fun get(row: Int, column: Int): Int {
|
override fun get(row: Int, column: Int): Int {
|
||||||
if (column != 0) {
|
if (column != 0) {
|
||||||
throw IndexOutOfBoundsException("Column must be 0 ($column given)")
|
throw IndexOutOfBoundsException("Column must be 0 ($column given)")
|
||||||
@ -29,12 +37,22 @@ data class Vector2i(val x: Int, val y: Int) : IMatrixLike, IMatrixLikeGetterI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract fun make(x: Int, y: Int): T
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Vector2i(override val x: Int = 0, override val y: Int = 0) : IVector2i<Vector2i>() {
|
||||||
|
override fun make(x: Int, y: Int) = Vector2i(x, y)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun fromJson(input: JsonArray): Vector2i {
|
fun fromJson(input: JsonArray): Vector2i {
|
||||||
return Vector2i(input[0].asInt, input[1].asInt)
|
return Vector2i(input[0].asInt, input[1].asInt)
|
||||||
}
|
}
|
||||||
|
|
||||||
val ZERO = Vector2i(0, 0)
|
val ZERO = Vector2i()
|
||||||
|
val LEFT = Vector2i().left()
|
||||||
|
val RIGHT = Vector2i().right()
|
||||||
|
val UP = Vector2i().up()
|
||||||
|
val DOWN = Vector2i().down()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,14 +3,24 @@ package ru.dbotthepony.kstarbound.render
|
|||||||
import ru.dbotthepony.kstarbound.gl.*
|
import ru.dbotthepony.kstarbound.gl.*
|
||||||
import ru.dbotthepony.kstarbound.math.FloatMatrix
|
import ru.dbotthepony.kstarbound.math.FloatMatrix
|
||||||
import ru.dbotthepony.kstarbound.world.Chunk
|
import ru.dbotthepony.kstarbound.world.Chunk
|
||||||
|
import ru.dbotthepony.kstarbound.world.ITileChunk
|
||||||
|
import ru.dbotthepony.kstarbound.world.World
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
import kotlin.collections.HashMap
|
|
||||||
|
|
||||||
class ChunkRenderer(val state: GLStateTracker, val chunk: Chunk) : AutoCloseable {
|
class ChunkRenderer(val state: GLStateTracker, val chunk: Chunk, val world: World? = null) : AutoCloseable {
|
||||||
private val layers = TileLayerList()
|
private val foregroundLayers = TileLayerList()
|
||||||
|
private val backgroundLayers = TileLayerList()
|
||||||
private val bakedMeshes = ArrayList<BakedStaticMesh>()
|
private val bakedMeshes = ArrayList<BakedStaticMesh>()
|
||||||
private val unloadableBakedMeshes = ArrayList<BakedStaticMesh>()
|
private val unloadableBakedMeshes = ArrayList<BakedStaticMesh>()
|
||||||
|
|
||||||
|
private fun getForeground(): ITileChunk {
|
||||||
|
return world?.getForegroundView(chunk.pos) ?: chunk.foreground
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getBackground(): ITileChunk {
|
||||||
|
return world?.getBackgroundView(chunk.pos) ?: chunk.background
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Тесселирует "статичную" геометрию в builders (к примеру тайлы).
|
* Тесселирует "статичную" геометрию в builders (к примеру тайлы).
|
||||||
*
|
*
|
||||||
@ -29,13 +39,26 @@ class ChunkRenderer(val state: GLStateTracker, val chunk: Chunk) : AutoCloseable
|
|||||||
bakedMeshes.clear()
|
bakedMeshes.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
layers.clear()
|
foregroundLayers.clear()
|
||||||
|
|
||||||
|
val foreground = getForeground()
|
||||||
|
|
||||||
// TODO: Синхронизация (ибо обновления игровой логики будут в потоке вне рендер потока)
|
// TODO: Синхронизация (ибо обновления игровой логики будут в потоке вне рендер потока)
|
||||||
for ((pos, tile) in chunk.foreground.posToTile) {
|
for ((pos, tile) in foreground.posToTile) {
|
||||||
if (tile != null) {
|
if (tile != null) {
|
||||||
val renderer = state.tileRenderers.get(tile.def.materialName)
|
val renderer = state.tileRenderers.get(tile.def.materialName)
|
||||||
renderer.tesselate(chunk.foreground, layers, pos)
|
renderer.tesselate(foreground, foregroundLayers, pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
backgroundLayers.clear()
|
||||||
|
|
||||||
|
val background = getBackground()
|
||||||
|
|
||||||
|
for ((pos, tile) in background.posToTile) {
|
||||||
|
if (tile != null) {
|
||||||
|
val renderer = state.tileRenderers.get(tile.def.materialName)
|
||||||
|
renderer.tesselate(background, backgroundLayers, pos, background = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,7 +72,13 @@ class ChunkRenderer(val state: GLStateTracker, val chunk: Chunk) : AutoCloseable
|
|||||||
unloadUnused()
|
unloadUnused()
|
||||||
|
|
||||||
// TODO: Синхронизация (ибо обновления игровой логики будут в потоке вне рендер потока)
|
// TODO: Синхронизация (ибо обновления игровой логики будут в потоке вне рендер потока)
|
||||||
for ((pos, tile) in chunk.foreground.posToTile) {
|
for ((_, tile) in getForeground().posToTile) {
|
||||||
|
if (tile != null) {
|
||||||
|
state.tileRenderers.get(tile.def.materialName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((_, tile) in getBackground().posToTile) {
|
||||||
if (tile != null) {
|
if (tile != null) {
|
||||||
state.tileRenderers.get(tile.def.materialName)
|
state.tileRenderers.get(tile.def.materialName)
|
||||||
}
|
}
|
||||||
@ -69,12 +98,17 @@ class ChunkRenderer(val state: GLStateTracker, val chunk: Chunk) : AutoCloseable
|
|||||||
fun uploadStatic(clear: Boolean = true) {
|
fun uploadStatic(clear: Boolean = true) {
|
||||||
unloadUnused()
|
unloadUnused()
|
||||||
|
|
||||||
for ((baked, builder) in layers.buildList()) {
|
for ((baked, builder) in backgroundLayers.buildList()) {
|
||||||
|
bakedMeshes.add(BakedStaticMesh(baked, builder))
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((baked, builder) in foregroundLayers.buildList()) {
|
||||||
bakedMeshes.add(BakedStaticMesh(baked, builder))
|
bakedMeshes.add(BakedStaticMesh(baked, builder))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clear) {
|
if (clear) {
|
||||||
layers.clear()
|
backgroundLayers.clear()
|
||||||
|
foregroundLayers.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import ru.dbotthepony.kstarbound.defs.TileRenderMatchPiece
|
|||||||
import ru.dbotthepony.kstarbound.defs.TileRenderPiece
|
import ru.dbotthepony.kstarbound.defs.TileRenderPiece
|
||||||
import ru.dbotthepony.kstarbound.gl.*
|
import ru.dbotthepony.kstarbound.gl.*
|
||||||
import ru.dbotthepony.kstarbound.math.Vector2i
|
import ru.dbotthepony.kstarbound.math.Vector2i
|
||||||
|
import ru.dbotthepony.kstarbound.util.Color
|
||||||
import ru.dbotthepony.kstarbound.world.ITileChunk
|
import ru.dbotthepony.kstarbound.world.ITileChunk
|
||||||
import kotlin.collections.HashMap
|
import kotlin.collections.HashMap
|
||||||
|
|
||||||
@ -52,7 +53,8 @@ class TileLayerList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TileRenderers(val state: GLStateTracker) {
|
class TileRenderers(val state: GLStateTracker) {
|
||||||
private val simpleBakedPrograms = HashMap<GLTexture2D, SimpleBakedProgram>()
|
private val foregroundTilePrograms = HashMap<GLTexture2D, ForegroundTileProgram>()
|
||||||
|
private val backgroundTilePrograms = HashMap<GLTexture2D, BackgroundTileProgram>()
|
||||||
private val tileRenderers = HashMap<String, TileRenderer>()
|
private val tileRenderers = HashMap<String, TileRenderer>()
|
||||||
|
|
||||||
operator fun get(tile: String): TileRenderer {
|
operator fun get(tile: String): TileRenderer {
|
||||||
@ -61,11 +63,11 @@ class TileRenderers(val state: GLStateTracker) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class SimpleBakedProgram(private val texture: GLTexture2D) : BakedProgramState(state.shaderVertexTexture) {
|
private inner class ForegroundTileProgram(private val texture: GLTexture2D) : BakedProgramState(state.shaderVertexTexture) {
|
||||||
override fun setup() {
|
override fun setup() {
|
||||||
super.setup()
|
super.setup()
|
||||||
state.activeTexture = 0
|
state.activeTexture = 0
|
||||||
// state.depthTest = true
|
state.depthTest = false
|
||||||
program["_texture"] = 0
|
program["_texture"] = 0
|
||||||
texture.bind()
|
texture.bind()
|
||||||
texture.textureMagFilter = GL_NEAREST
|
texture.textureMagFilter = GL_NEAREST
|
||||||
@ -77,7 +79,37 @@ class TileRenderers(val state: GLStateTracker) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (other is SimpleBakedProgram) {
|
if (other is ForegroundTileProgram) {
|
||||||
|
return texture == other.texture
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.equals(other)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return texture.hashCode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class BackgroundTileProgram(private val texture: GLTexture2D) : BakedProgramState(state.shaderVertexTextureColor) {
|
||||||
|
override fun setup() {
|
||||||
|
super.setup()
|
||||||
|
state.activeTexture = 0
|
||||||
|
state.depthTest = false
|
||||||
|
program["_texture"] = 0
|
||||||
|
texture.bind()
|
||||||
|
texture.textureMagFilter = GL_NEAREST
|
||||||
|
texture.textureMinFilter = GL_NEAREST
|
||||||
|
|
||||||
|
program["_color"] = BACKGROUND_COLOR
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (other is BackgroundTileProgram) {
|
||||||
return texture == other.texture
|
return texture == other.texture
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,8 +124,19 @@ class TileRenderers(val state: GLStateTracker) {
|
|||||||
/**
|
/**
|
||||||
* Возвращает запечённое состояние shaderVertexTexture с данной текстурой
|
* Возвращает запечённое состояние shaderVertexTexture с данной текстурой
|
||||||
*/
|
*/
|
||||||
fun simpleProgram(texture: GLTexture2D): BakedProgramState {
|
fun foreground(texture: GLTexture2D): BakedProgramState {
|
||||||
return simpleBakedPrograms.computeIfAbsent(texture, ::SimpleBakedProgram)
|
return foregroundTilePrograms.computeIfAbsent(texture, ::ForegroundTileProgram)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает запечённое состояние shaderVertexTextureColor с данной текстурой
|
||||||
|
*/
|
||||||
|
fun background(texture: GLTexture2D): BakedProgramState {
|
||||||
|
return backgroundTilePrograms.computeIfAbsent(texture, ::BackgroundTileProgram)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val BACKGROUND_COLOR = Color(0.4f, 0.4f, 0.4f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,7 +151,8 @@ class TileRenderer(val state: GLStateTracker, val tile: TileDefinition) {
|
|||||||
it.textureMagFilter = GL_NEAREST
|
it.textureMagFilter = GL_NEAREST
|
||||||
}
|
}
|
||||||
|
|
||||||
val bakedProgramState = state.tileRenderers.simpleProgram(texture)
|
val bakedProgramState = state.tileRenderers.foreground(texture)
|
||||||
|
val bakedBackgroundProgramState = state.tileRenderers.background(texture)
|
||||||
// private var notifiedDepth = false
|
// private var notifiedDepth = false
|
||||||
|
|
||||||
private fun tesselateAt(piece: TileRenderPiece, getter: ITileChunk, builder: VertexBuilder, pos: Vector2i, offset: Vector2i = Vector2i.ZERO) {
|
private fun tesselateAt(piece: TileRenderPiece, getter: ITileChunk, builder: VertexBuilder, pos: Vector2i, offset: Vector2i = Vector2i.ZERO) {
|
||||||
@ -155,11 +199,19 @@ class TileRenderer(val state: GLStateTracker, val tile: TileDefinition) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun tesselatePiece(matchPiece: TileRenderMatchPiece, getter: ITileChunk, layers: TileLayerList, pos: Vector2i, thisBuilder: VertexBuilder): TileRenderTesselateResult {
|
private fun tesselatePiece(matchPiece: TileRenderMatchPiece, getter: ITileChunk, layers: TileLayerList, pos: Vector2i, thisBuilder: VertexBuilder, background: Boolean): TileRenderTesselateResult {
|
||||||
if (matchPiece.test(getter, tile, pos)) {
|
if (matchPiece.test(getter, tile, pos)) {
|
||||||
for (renderPiece in matchPiece.pieces) {
|
for (renderPiece in matchPiece.pieces) {
|
||||||
if (renderPiece.piece.texture != null) {
|
if (renderPiece.piece.texture != null) {
|
||||||
tesselateAt(renderPiece.piece, getter, layers.getLayer(state.tileRenderers.simpleProgram(state.loadNamedTexture(renderPiece.piece.texture)), tile.render.zLevel) {
|
val program: BakedProgramState
|
||||||
|
|
||||||
|
if (background) {
|
||||||
|
program = state.tileRenderers.background(state.loadNamedTexture(renderPiece.piece.texture))
|
||||||
|
} else {
|
||||||
|
program = state.tileRenderers.foreground(state.loadNamedTexture(renderPiece.piece.texture))
|
||||||
|
}
|
||||||
|
|
||||||
|
tesselateAt(renderPiece.piece, getter, layers.getLayer(program, tile.render.zLevel) {
|
||||||
return@getLayer VertexBuilder(GLFlatAttributeList.VERTEX_TEXTURE, VertexType.QUADS)
|
return@getLayer VertexBuilder(GLFlatAttributeList.VERTEX_TEXTURE, VertexType.QUADS)
|
||||||
}, pos, renderPiece.offset)
|
}, pos, renderPiece.offset)
|
||||||
} else {
|
} else {
|
||||||
@ -168,7 +220,7 @@ class TileRenderer(val state: GLStateTracker, val tile: TileDefinition) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (subPiece in matchPiece.subMatches) {
|
for (subPiece in matchPiece.subMatches) {
|
||||||
val matched = tesselatePiece(subPiece, getter, layers, pos, thisBuilder)
|
val matched = tesselatePiece(subPiece, getter, layers, pos, thisBuilder, background)
|
||||||
|
|
||||||
if (matched == TileRenderTesselateResult.HALT || matched == TileRenderTesselateResult.CONTINUE && matchPiece.haltOnSubMatch) {
|
if (matched == TileRenderTesselateResult.HALT || matched == TileRenderTesselateResult.CONTINUE && matchPiece.haltOnSubMatch) {
|
||||||
return TileRenderTesselateResult.HALT
|
return TileRenderTesselateResult.HALT
|
||||||
@ -194,18 +246,18 @@ class TileRenderer(val state: GLStateTracker, val tile: TileDefinition) {
|
|||||||
*
|
*
|
||||||
* Тесселирует тайлы в границы -1f .. CHUNK_SIZEf + 1f на основе [pos]
|
* Тесселирует тайлы в границы -1f .. CHUNK_SIZEf + 1f на основе [pos]
|
||||||
*/
|
*/
|
||||||
fun tesselate(getter: ITileChunk, layers: TileLayerList, pos: Vector2i) {
|
fun tesselate(getter: ITileChunk, layers: TileLayerList, pos: Vector2i, background: Boolean = false) {
|
||||||
// если у нас нет renderTemplate
|
// если у нас нет renderTemplate
|
||||||
// то мы просто не можем его отрисовать
|
// то мы просто не можем его отрисовать
|
||||||
tile.render.renderTemplate ?: return
|
tile.render.renderTemplate ?: return
|
||||||
|
|
||||||
val builder = layers.getLayer(bakedProgramState, tile.render.zLevel) {
|
val builder = layers.getLayer(if (background) bakedBackgroundProgramState else bakedProgramState, tile.render.zLevel) {
|
||||||
return@getLayer VertexBuilder(GLFlatAttributeList.VERTEX_TEXTURE, VertexType.QUADS)
|
return@getLayer VertexBuilder(GLFlatAttributeList.VERTEX_TEXTURE, VertexType.QUADS)
|
||||||
}
|
}
|
||||||
|
|
||||||
for ((_, matcher) in tile.render.renderTemplate.matches) {
|
for ((_, matcher) in tile.render.renderTemplate.matches) {
|
||||||
for (matchPiece in matcher.pieces) {
|
for (matchPiece in matcher.pieces) {
|
||||||
val matched = tesselatePiece(matchPiece, getter, layers, pos, builder)
|
val matched = tesselatePiece(matchPiece, getter, layers, pos, builder, background)
|
||||||
|
|
||||||
if (matched == TileRenderTesselateResult.HALT) {
|
if (matched == TileRenderTesselateResult.HALT) {
|
||||||
break
|
break
|
||||||
@ -216,7 +268,7 @@ class TileRenderer(val state: GLStateTracker, val tile: TileDefinition) {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val BASELINE_TEXTURE_SIZE = 8f
|
const val BASELINE_TEXTURE_SIZE = 8f
|
||||||
const val Z_LEVEL = 1f
|
const val Z_LEVEL = 10f
|
||||||
private val LOGGER = LogManager.getLogger()
|
private val LOGGER = LogManager.getLogger()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
package ru.dbotthepony.kstarbound.util
|
package ru.dbotthepony.kstarbound.util
|
||||||
|
|
||||||
import com.google.gson.JsonArray
|
import com.google.gson.JsonArray
|
||||||
|
import ru.dbotthepony.kstarbound.api.IStruct4f
|
||||||
|
|
||||||
data class Color(val red: Float, val green: Float, val blue: Float, val alpha: Float = 1f) {
|
data class Color(val red: Float, val green: Float, val blue: Float, val alpha: Float = 1f) : IStruct4f {
|
||||||
constructor(input: JsonArray) : this(input[0].asFloat / 255f, input[1].asFloat / 255f, input[2].asFloat / 255f, if (input.size() >= 4) input[3].asFloat / 255f else 1f)
|
constructor(input: JsonArray) : this(input[0].asFloat / 255f, input[1].asFloat / 255f, input[2].asFloat / 255f, if (input.size() >= 4) input[3].asFloat / 255f else 1f)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package ru.dbotthepony.kstarbound.world
|
package ru.dbotthepony.kstarbound.world
|
||||||
|
|
||||||
import ru.dbotthepony.kstarbound.defs.TileDefinition
|
import ru.dbotthepony.kstarbound.defs.TileDefinition
|
||||||
|
import ru.dbotthepony.kstarbound.math.IVector2i
|
||||||
import ru.dbotthepony.kstarbound.math.Vector2i
|
import ru.dbotthepony.kstarbound.math.Vector2i
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -137,13 +138,124 @@ const val CHUNK_SHIFT = 6
|
|||||||
const val CHUNK_SIZE = 1 shl CHUNK_SHIFT // 64
|
const val CHUNK_SIZE = 1 shl CHUNK_SHIFT // 64
|
||||||
const val CHUNK_SIZE_FF = CHUNK_SIZE - 1
|
const val CHUNK_SIZE_FF = CHUNK_SIZE - 1
|
||||||
|
|
||||||
data class ChunkPos(val x: Int, val y: Int) {
|
data class ChunkPos(override val x: Int, override val y: Int) : IVector2i<ChunkPos>() {
|
||||||
constructor(pos: Vector2i) : this(pos.x shr CHUNK_SHIFT, pos.y shr CHUNK_SHIFT)
|
constructor(pos: Vector2i) : this(pos.x shr CHUNK_SHIFT, pos.y shr CHUNK_SHIFT)
|
||||||
|
override fun make(x: Int, y: Int) = ChunkPos(x, y)
|
||||||
|
|
||||||
val firstBlock get() = Vector2i(x shl CHUNK_SHIFT, y shl CHUNK_SHIFT)
|
val firstBlock get() = Vector2i(x shl CHUNK_SHIFT, y shl CHUNK_SHIFT)
|
||||||
val lastBlock get() = Vector2i(((x + 1) shl CHUNK_SHIFT) - 1, ((y + 1) shl CHUNK_SHIFT) - 1)
|
val lastBlock get() = Vector2i(((x + 1) shl CHUNK_SHIFT) - 1, ((y + 1) shl CHUNK_SHIFT) - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Предоставляет доступ к чанку и его соседям
|
||||||
|
*
|
||||||
|
* В основном для использования в местах, где нужен не мир, а определённый чанк мира,
|
||||||
|
* и при этом координаты проверяются относительно чанка и могут спокойно выйти за его пределы,
|
||||||
|
* с желанием получить тайл из соседнего чанка
|
||||||
|
*/
|
||||||
|
open class TileChunkView(
|
||||||
|
open val center: ITileChunk,
|
||||||
|
|
||||||
|
open val right: ITileChunk?,
|
||||||
|
open val top: ITileChunk?,
|
||||||
|
open val topRight: ITileChunk?,
|
||||||
|
open val topLeft: ITileChunk?,
|
||||||
|
|
||||||
|
open val left: ITileChunk?,
|
||||||
|
open val bottom: ITileChunk?,
|
||||||
|
open val bottomLeft: ITileChunk?,
|
||||||
|
open val bottomRight: ITileChunk?,
|
||||||
|
) : ITileChunk {
|
||||||
|
override fun get(x: Int, y: Int): ChunkTile? {
|
||||||
|
if (x in 0 .. CHUNK_SIZE_FF) {
|
||||||
|
if (y in 0 .. CHUNK_SIZE_FF) {
|
||||||
|
return center[x, y]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y < 0) {
|
||||||
|
return bottom?.get(x, y + CHUNK_SIZE)
|
||||||
|
} else {
|
||||||
|
return top?.get(x, y - CHUNK_SIZE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x < 0) {
|
||||||
|
if (y in 0 .. CHUNK_SIZE_FF) {
|
||||||
|
return left?.get(x + CHUNK_SIZE, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y < 0) {
|
||||||
|
return bottomLeft?.get(x + CHUNK_SIZE, y + CHUNK_SIZE)
|
||||||
|
} else {
|
||||||
|
return topLeft?.get(x + CHUNK_SIZE, y - CHUNK_SIZE)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (y in 0 .. CHUNK_SIZE_FF) {
|
||||||
|
return right?.get(x - CHUNK_SIZE, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y < 0) {
|
||||||
|
return bottomRight?.get(x - CHUNK_SIZE, y + CHUNK_SIZE)
|
||||||
|
} else {
|
||||||
|
return topRight?.get(x - CHUNK_SIZE, y - CHUNK_SIZE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val pos: ChunkPos
|
||||||
|
get() = center.pos
|
||||||
|
}
|
||||||
|
|
||||||
|
class MutableTileChunkView(
|
||||||
|
override val center: IMutableTileChunk,
|
||||||
|
|
||||||
|
override val right: IMutableTileChunk?,
|
||||||
|
override val top: IMutableTileChunk?,
|
||||||
|
override val topRight: IMutableTileChunk?,
|
||||||
|
override val topLeft: IMutableTileChunk?,
|
||||||
|
|
||||||
|
override val left: IMutableTileChunk?,
|
||||||
|
override val bottom: IMutableTileChunk?,
|
||||||
|
override val bottomLeft: IMutableTileChunk?,
|
||||||
|
override val bottomRight: IMutableTileChunk?,
|
||||||
|
) : TileChunkView(center, right, top, topRight, topLeft, left, bottom, bottomLeft, bottomRight), IMutableTileChunk {
|
||||||
|
override fun set(x: Int, y: Int, tile: TileDefinition?): ChunkTile? {
|
||||||
|
if (x in 0 .. CHUNK_SIZE_FF) {
|
||||||
|
if (y in 0 .. CHUNK_SIZE_FF) {
|
||||||
|
return center.set(x, y, tile)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y < 0) {
|
||||||
|
return bottom?.set(x, y + CHUNK_SIZE, tile)
|
||||||
|
} else {
|
||||||
|
return top?.set(x, y - CHUNK_SIZE, tile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x < 0) {
|
||||||
|
if (y in 0 .. CHUNK_SIZE_FF) {
|
||||||
|
return left?.set(x + CHUNK_SIZE, y, tile)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y < 0) {
|
||||||
|
return bottomLeft?.set(x + CHUNK_SIZE, y + CHUNK_SIZE, tile)
|
||||||
|
} else {
|
||||||
|
return topLeft?.set(x + CHUNK_SIZE, y - CHUNK_SIZE, tile)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (y in 0 .. CHUNK_SIZE_FF) {
|
||||||
|
return right?.set(x - CHUNK_SIZE, y, tile)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y < 0) {
|
||||||
|
return bottomRight?.set(x - CHUNK_SIZE, y + CHUNK_SIZE, tile)
|
||||||
|
} else {
|
||||||
|
return topRight?.set(x - CHUNK_SIZE, y - CHUNK_SIZE, tile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
open class Chunk(val world: World, val pos: ChunkPos) {
|
open class Chunk(val world: World, val pos: ChunkPos) {
|
||||||
inner class ChunkTileLayer : IMutableTileChunk {
|
inner class ChunkTileLayer : IMutableTileChunk {
|
||||||
override val pos: ChunkPos
|
override val pos: ChunkPos
|
||||||
|
@ -39,9 +39,86 @@ class World(val seed: Long = 0L) {
|
|||||||
return chunk
|
return chunk
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getForegroundView(pos: ChunkPos): TileChunkView? {
|
||||||
|
val get = getChunk(pos) ?: return null
|
||||||
|
|
||||||
|
return TileChunkView(
|
||||||
|
center = get.foreground,
|
||||||
|
left = getChunk(pos.left())?.foreground,
|
||||||
|
top = getChunk(pos.up())?.foreground,
|
||||||
|
topLeft = getChunk(pos.up().left())?.foreground,
|
||||||
|
topRight = getChunk(pos.up().right())?.foreground,
|
||||||
|
right = getChunk(pos.right())?.foreground,
|
||||||
|
bottom = getChunk(pos.down())?.foreground,
|
||||||
|
bottomLeft = getChunk(pos.down().left())?.foreground,
|
||||||
|
bottomRight = getChunk(pos.down().right())?.foreground,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBackgroundView(pos: ChunkPos): TileChunkView? {
|
||||||
|
val get = getChunk(pos) ?: return null
|
||||||
|
|
||||||
|
return TileChunkView(
|
||||||
|
center = get.background,
|
||||||
|
left = getChunk(pos.left())?.background,
|
||||||
|
top = getChunk(pos.up())?.background,
|
||||||
|
topLeft = getChunk(pos.up().left())?.background,
|
||||||
|
topRight = getChunk(pos.up().right())?.background,
|
||||||
|
right = getChunk(pos.right())?.background,
|
||||||
|
bottom = getChunk(pos.down())?.background,
|
||||||
|
bottomLeft = getChunk(pos.down().left())?.background,
|
||||||
|
bottomRight = getChunk(pos.down().right())?.background,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Считается, что [pos] это абсолютные координаты ТАЙЛА в мире, поэтому они
|
||||||
|
* трансформируются в координаты чанка
|
||||||
|
*/
|
||||||
fun getChunk(pos: Vector2i) = getChunk(ChunkPos(pos))
|
fun getChunk(pos: Vector2i) = getChunk(ChunkPos(pos))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Считается, что [pos] это абсолютные координаты ТАЙЛА в мире, поэтому они
|
||||||
|
* трансформируются в координаты чанка
|
||||||
|
*/
|
||||||
fun getOrMakeChunk(pos: Vector2i) = getOrMakeChunk(ChunkPos(pos))
|
fun getOrMakeChunk(pos: Vector2i) = getOrMakeChunk(ChunkPos(pos))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Считается, что [pos] это абсолютные координаты ТАЙЛА в мире, поэтому они
|
||||||
|
* трансформируются в координаты чанка
|
||||||
|
*/
|
||||||
|
fun getForegroundView(pos: Vector2i) = getForegroundView(ChunkPos(pos))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Считается, что [pos] это абсолютные координаты ТАЙЛА в мире, поэтому они
|
||||||
|
* трансформируются в координаты чанка
|
||||||
|
*/
|
||||||
|
fun getBackgroundView(pos: Vector2i) = getBackgroundView(ChunkPos(pos))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Считается, что [x] и [y] это абсолютные координаты ЧАНКА в мире, поэтому они
|
||||||
|
* НЕ трансформируются в координаты чанка, а используются напрямую
|
||||||
|
*/
|
||||||
|
fun getChunk(x: Int, y: Int) = getChunk(ChunkPos(x, y))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Считается, что [x] и [y] это абсолютные координаты ЧАНКА в мире, поэтому они
|
||||||
|
* НЕ трансформируются в координаты чанка, а используются напрямую
|
||||||
|
*/
|
||||||
|
fun getOrMakeChunk(x: Int, y: Int) = getOrMakeChunk(ChunkPos(x, y))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Считается, что [x] и [y] это абсолютные координаты ЧАНКА в мире, поэтому они
|
||||||
|
* НЕ трансформируются в координаты чанка, а используются напрямую
|
||||||
|
*/
|
||||||
|
fun getForegroundView(x: Int, y: Int) = getForegroundView(ChunkPos(x, y))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Считается, что [x] и [y] это абсолютные координаты ЧАНКА в мире, поэтому они
|
||||||
|
* НЕ трансформируются в координаты чанка, а используются напрямую
|
||||||
|
*/
|
||||||
|
fun getBackgroundView(x: Int, y: Int) = getBackgroundView(ChunkPos(x, y))
|
||||||
|
|
||||||
fun getTile(pos: Vector2i): ChunkTile? {
|
fun getTile(pos: Vector2i): ChunkTile? {
|
||||||
return getChunk(pos)?.foreground?.get(pos.x, pos.y)
|
return getChunk(pos)?.foreground?.get(pos.x, pos.y)
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,5 @@ out vec4 _color_out;
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 texel = texture(_texture, _uv_out);
|
vec4 texel = texture(_texture, _uv_out);
|
||||||
|
|
||||||
//if (texel.a < 0.5)
|
|
||||||
// discard;
|
|
||||||
|
|
||||||
_color_out = texel;
|
_color_out = texel;
|
||||||
}
|
}
|
13
src/main/resources/shaders/fragment/texture_color.glsl
Normal file
13
src/main/resources/shaders/fragment/texture_color.glsl
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
#version 460
|
||||||
|
|
||||||
|
uniform sampler2D _texture;
|
||||||
|
uniform vec4 _color;
|
||||||
|
|
||||||
|
in vec2 _uv_out;
|
||||||
|
out vec4 _color_out;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 texel = texture(_texture, _uv_out);
|
||||||
|
_color_out = texel * _color;
|
||||||
|
}
|
@ -1,13 +0,0 @@
|
|||||||
|
|
||||||
#version 460
|
|
||||||
|
|
||||||
out vec4 FragColor;
|
|
||||||
in vec3 ourColor;
|
|
||||||
in vec2 TexCoord;
|
|
||||||
|
|
||||||
uniform vec3 globalColor;
|
|
||||||
uniform sampler2D ourTexture;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
FragColor = texture(ourTexture, TexCoord);
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
|
|
||||||
#version 460
|
|
||||||
|
|
||||||
layout (location = 0) in vec3 aPos;
|
|
||||||
layout (location = 1) in vec3 aColor;
|
|
||||||
layout (location = 2) in vec2 aTexCoord;
|
|
||||||
out vec3 ourColor;
|
|
||||||
out vec2 TexCoord;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
gl_Position = vec4(aPos, 1.0);
|
|
||||||
ourColor = aColor;
|
|
||||||
TexCoord = aTexCoord;
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user