1+ /* *
2+ * Animatium
3+ * The all-you-could-want legacy animations mod for modern minecraft versions.
4+ * Brings back animations from the 1.7/1.8 era and more.
5+ * <p>
6+ * Copyright (C) 2024-2025 lowercasebtw
7+ * Copyright (C) 2024-2025 mixces
8+ * Copyright (C) 2024-2025 Contributors to the project retain their copyright
9+ * <p>
10+ * This program is free software: you can redistribute it and/or modify
11+ * it under the terms of the GNU General Public License as published by
12+ * the Free Software Foundation, either version 3 of the License, or
13+ * (at your option) any later version.
14+ * <p>
15+ * This program is distributed in the hope that it will be useful,
16+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
17+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+ * GNU General Public License for more details.
19+ * <p>
20+ * You should have received a copy of the GNU General Public License
21+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
22+ * <p>
23+ * "MINECRAFT" LINKING EXCEPTION TO THE GPL
24+ */
25+
26+ package org.visuals.legacy.animatium.renderer.uniform
27+
28+ import com.mojang.blaze3d.buffers.GpuBuffer
29+ import com.mojang.blaze3d.buffers.Std140SizeCalculator
30+ import com.mojang.blaze3d.systems.CommandEncoder
31+ import com.mojang.blaze3d.systems.RenderSystem
32+ import org.lwjgl.system.MemoryStack
33+
34+ class UniformStorage : AutoCloseable {
35+ private val name: String
36+ private val ubo: GpuBuffer
37+ private val keys: MutableList <UniformKey <* >>
38+ private val values = LinkedHashMap <UniformKey <* >, Any? > ()
39+ private val size: Int
40+
41+ private var dirty = true
42+ private var closed = false
43+
44+ private constructor (name: String , keys: List <UniformKey <* >>, size: Int ) {
45+ this .name = name
46+ this .ubo = RenderSystem .getDevice().createBuffer(
47+ { " Dynamic Uniform Storage (${this .name} )" },
48+ GpuBuffer .USAGE_UNIFORM or GpuBuffer .USAGE_COPY_DST ,
49+ size.toLong()
50+ )
51+ this .keys = keys.toMutableList()
52+ this .size = size
53+ for (key in this .keys) {
54+ this .values[key] = null
55+ }
56+ }
57+
58+ companion object {
59+ fun builder (name : String ) = Builder (name)
60+ }
61+
62+ fun <T > set (key : UniformKey <T >, value : T ): UniformStorage {
63+ if (this .closed) {
64+ throw RuntimeException (" Cannot set value in uniform storage \" " + this .name + " \" as it has been closed!" )
65+ } else if (! this .keys.contains(key)) {
66+ throw UnsupportedOperationException (" Uniform storage does not contain key '" + key.name() + " '!" )
67+ } else {
68+ val currentValue = this .values[key]
69+ if (currentValue != values) {
70+ this .dirty = true
71+ this .values[key] = value
72+ }
73+
74+ return this
75+ }
76+ }
77+
78+ fun <T > get (key : UniformKey <T >): T ? =
79+ if (! this .keys.contains(key)) {
80+ null
81+ } else {
82+ this .values[key] as T ?
83+ }
84+
85+ fun update (commandEncoder : CommandEncoder ) {
86+ if (this .closed) {
87+ throw RuntimeException (" Cannot update uniform storage \" " + this .name + " \" as it has been closed!" )
88+ } else if (this .dirty) {
89+ val slice = this .ubo.slice()
90+ MemoryStack .stackPush().use { stack ->
91+ val buffer = stack.malloc(this .size)
92+ for (entry in this .values) {
93+ val key = entry.key
94+ val value = entry.value
95+ if (value == null ) {
96+ throw RuntimeException (" Failed to bind \" " + key.name() + " \" in Uniform Storage (" + this .name + " ) as value is not set!" )
97+ } else {
98+ (key.serializer() as UniformSerializer <Any >).put(buffer, value)
99+ }
100+ }
101+
102+ commandEncoder.writeToBuffer(slice, buffer)
103+ }
104+
105+ this .dirty = false
106+ }
107+ }
108+
109+ fun update () = this .update(RenderSystem .getDevice().createCommandEncoder())
110+
111+ fun slice () = this .ubo.slice()
112+
113+ fun isClose () = this .closed
114+
115+ override fun close () {
116+ if (! this .closed) {
117+ this .closed = true
118+ this .ubo.close()
119+ this .keys.clear()
120+ this .values.clear()
121+ }
122+ }
123+
124+ class Builder (private val name : String ) {
125+ private val keys = arrayListOf<UniformKey <* >>()
126+ private val calculator = Std140SizeCalculator ()
127+
128+ fun with (key : UniformKey <* >): Builder {
129+ this .keys.add(key)
130+ key.serializer().size(this .calculator)
131+ return this
132+ }
133+
134+ fun build (): UniformStorage {
135+ val size = this .calculator.get()
136+ if (size == 0 ) {
137+ throw RuntimeException (" Cannot build Uniform Storage (" + this .name + " ) as it contains no uniforms!" )
138+ } else {
139+ return UniformStorage (this .name, this .keys, size)
140+ }
141+ }
142+ }
143+ }
0 commit comments