1717
1818package com.lambda.graphics.texture
1919
20+ import com.lambda.graphics.renderer.gui.TextureRenderer
2021import com.lambda.graphics.texture.TextureUtils.bindTexture
2122import com.lambda.graphics.texture.TextureUtils.readImage
2223import com.lambda.graphics.texture.TextureUtils.setupTexture
24+ import com.lambda.util.math.Rect.Companion.basedOn
25+ import com.lambda.util.math.Vec2d
2326import org.lwjgl.opengl.GL45C.*
2427import java.awt.image.BufferedImage
2528import java.lang.IllegalStateException
29+ import java.nio.ByteBuffer
2630
2731/* *
2832 * Represents a texture that can be uploaded and bound to the graphics pipeline
2933 * Supports mipmap generation and LOD (Level of Detail) configuration
30- *
31- * @param image Optional initial image to upload to the texture
32- * @param format The format of the image passed in
33- * @param levels Number of mipmap levels to generate for the texture
34- * @param forceConsistency Flag to enforce consistency when updating the texture. If true, attempts to update
35- * the texture after initialization will throw an exception
3634 */
37- open class Texture (
38- image : BufferedImage ? ,
39- val format : Int = GL_RGBA ,
40- private val levels : Int = 4 ,
41- private val forceConsistency : Boolean = false ,
42- ) {
35+ open class Texture {
36+ val format: Int
37+ private val levels: Int
38+ private val forceConsistency: Boolean
39+
40+ /* *
41+ * @param image Optional initial image to upload to the texture
42+ * @param format The format of the image passed in
43+ * @param levels Number of mipmap levels to generate for the texture
44+ * @param forceConsistency Flag to enforce consistency when updating the texture. If true, attempts to update
45+ * the texture after initialization will throw an exception
46+ */
47+ constructor (image: BufferedImage ? ,
48+ format: Int = GL_RGBA ,
49+ levels: Int = 4 ,
50+ forceConsistency: Boolean = false )
51+ {
52+ this .format = format
53+ this .levels = levels
54+ this .forceConsistency = forceConsistency
55+
56+ image?.let { bindTexture(id); upload(it) }
57+ }
58+
59+ /* *
60+ * @param buffer The image buffer
61+ * @param width The width of the image
62+ * @param height The height of the image
63+ * @param format The format of the image passed in
64+ * @param levels Number of mipmap levels to generate for the texture
65+ * @param forceConsistency Flag to enforce consistency when updating the texture. If true, attempts to update
66+ * the texture after initialization will throw an exception
67+ */
68+ constructor (buffer: ByteBuffer ,
69+ width: Int ,
70+ height: Int ,
71+ format: Int = GL_RGBA ,
72+ levels: Int = 4 ,
73+ forceConsistency: Boolean = false )
74+ {
75+ this .format = format
76+ this .levels = levels
77+ this .forceConsistency = forceConsistency
78+
79+ bindTexture(id)
80+ upload(buffer, width, height)
81+ }
82+
4383 /* *
4484 * Indicates whether there is an initial texture or not
4585 */
@@ -57,12 +97,20 @@ open class Texture(
5797 }
5898
5999 /* *
60- * Uploads an image to the texture and generates mipmaps for the texture if applicable.
100+ * Unbinds the currently bound texture
101+ */
102+ open fun unbind (slot : Int = 0) {
103+ bindTexture(0 , slot)
104+ }
105+
106+ /* *
107+ * Uploads an image to the texture and generates mipmaps for the texture if applicable
108+ * This function does not bind the texture
61109 *
62- * @param image The image to upload to the texture
63- * @param offset The mipmap level to upload the image to
110+ * @param image The image to upload to the texture
111+ * @param offset The mipmap level to upload the image to
64112 */
65- open fun upload (image : BufferedImage , offset : Int = 0) {
113+ fun upload (image : BufferedImage , offset : Int = 0) {
66114 if (forceConsistency && initialized) throw IllegalStateException (" Client tried to update a texture, but the enforce consistency flag was present" )
67115
68116 // Store level_base +1 through `level` images and generate
@@ -75,23 +123,90 @@ open class Texture(
75123
76124 // Set this mipmap to `offset` to define the original texture
77125 setupTexture(GL_LINEAR_MIPMAP_LINEAR , GL_LINEAR )
78- glTexImage2D(GL_TEXTURE_2D , offset, GL_RGBA , width, height, 0 , GL_RGBA , GL_UNSIGNED_BYTE , readImage(image))
126+ glTexImage2D(GL_TEXTURE_2D , offset, GL_RGBA , width, height, 0 , format , GL_UNSIGNED_BYTE , readImage(image))
79127 if (levels > 1 ) glGenerateMipmap(GL_TEXTURE_2D ) // This take the derived values GL_TEXTURE_BASE_LEVEL and GL_TEXTURE_MAX_LEVEL to generate the stack
80128 }
81129
82- open fun update (image : BufferedImage , offset : Int = 0) {
130+ /* *
131+ * Uploads an image to the texture and generates mipmaps for the texture if applicable
132+ * This function does not bind the texture
133+ *
134+ * @param buffer The image buffer to upload to the texture
135+ * @param width The width of the texture
136+ * @param height The height of the texture
137+ * @param offset The mipmap level to upload the image to
138+ */
139+ fun upload (buffer : ByteBuffer , width : Int , height : Int , offset : Int = 0) {
140+ if (forceConsistency && initialized) throw IllegalStateException (" Client tried to update a texture, but the enforce consistency flag was present" )
141+
142+ // Store level_base +1 through `level` images and generate
143+ // mipmaps from them
144+ setupLOD(levels = levels)
145+
146+ this .width = width
147+ this .height = height
148+ initialized = true
149+
150+ // Set this mipmap to `offset` to define the original texture
151+ setupTexture(GL_LINEAR_MIPMAP_LINEAR , GL_LINEAR )
152+ glTexImage2D(GL_TEXTURE_2D , offset, GL_RGBA , width, height, 0 , format, GL_UNSIGNED_BYTE , buffer)
153+ if (levels > 1 ) glGenerateMipmap(GL_TEXTURE_2D ) // This take the derived values GL_TEXTURE_BASE_LEVEL and GL_TEXTURE_MAX_LEVEL to generate the stack
154+ }
155+
156+ /* *
157+ * Updates the data of a texture
158+ * This function does not bind the texture
159+ *
160+ * @param image The image to upload to the texture
161+ * @param offset The mipmap level to upload the image to
162+ *
163+ * @throws IllegalStateException If the texture has the consistency flag and is already initialized
164+ */
165+ fun update (image : BufferedImage , offset : Int = 0) {
83166 if (! initialized) return upload(image, offset)
84167 if (forceConsistency && initialized) throw IllegalStateException (" Client tried to update a texture, but the enforce consistency flag was present" )
85168
86- check(image.width + image.height > this .width + this .height && initialized) {
169+ check(image.width + image.height <= this .width + this .height && initialized) {
87170 " Client tried to update a texture with more data than allowed" +
88171 " Expected ${this .width + this .height} bytes but got ${image.width + image.height} "
89172 }
90173
91- // Can we rebuild LOD ?
92- glTexSubImage2D(GL_TEXTURE_2D , offset, 0 , 0 , width, height, GL_RGBA , GL_UNSIGNED_BYTE , readImage(image))
174+ glTexSubImage2D(GL_TEXTURE_2D , offset, 0 , 0 , width, height, format, GL_UNSIGNED_BYTE , readImage(image))
175+ }
176+
177+ /* *
178+ * Updates the data of a texture
179+ * This function does not bind the texture
180+ *
181+ * @param buffer The image buffer to upload to the texture
182+ * @param width The width of the texture
183+ * @param height The height of the texture
184+ * @param offset The mipmap level to upload the image to
185+ *
186+ * @throws IllegalStateException If the texture has the consistency flag and is already initialized
187+ */
188+ fun update (buffer : ByteBuffer , width : Int , height : Int , offset : Int = 0) {
189+ if (! initialized) return upload(buffer, width, height, offset)
190+ if (forceConsistency && initialized) throw IllegalStateException (" Client tried to update a texture, but the enforce consistency flag was present" )
191+
192+ check(width + height <= this .width + this .height && initialized) {
193+ " Client tried to update a texture with more data than allowed\n " +
194+ " Expected ${this .width + this .height} bytes but got ${width + height} "
195+ }
196+
197+ glTexSubImage2D(GL_TEXTURE_2D , offset, 0 , 0 , width, height, format, GL_UNSIGNED_BYTE , buffer)
93198 }
94199
200+ /* *
201+ * Draws the texture
202+ * This function binds the texture
203+ *
204+ * @param coord The top left coordinate to draw at
205+ * @param scale The width and height multiplier
206+ */
207+ fun draw (coord : Vec2d , scale : Double = 0.0) =
208+ TextureRenderer .drawTexture(this , basedOn(coord, width * scale, height * scale))
209+
95210 private fun setupLOD (levels : Int ) {
96211 // When you call glTextureStorage, you're specifying the total number of levels, including level 0
97212 // This is a 0-based index system, which means that the maximum mipmap level is n-1
@@ -103,12 +218,4 @@ open class Texture(
103218 glTexParameteri(GL_TEXTURE_2D , GL_TEXTURE_BASE_LEVEL , 0 )
104219 glTexParameteri(GL_TEXTURE_2D , GL_TEXTURE_MAX_LEVEL , levels)
105220 }
106-
107- init {
108- image?.let {
109- // Don't use bind() because if a child class overrides the function we're screwed
110- bindTexture(id)
111- upload(it)
112- }
113- }
114221}
0 commit comments