1717
1818package com.lambda.graphics.texture
1919
20- import com.lambda.graphics.renderer.gui.TextureRenderer
2120import com.lambda.graphics.texture.TextureUtils.bindTexture
2221import com.lambda.graphics.texture.TextureUtils.readImage
2322import com.lambda.graphics.texture.TextureUtils.setupTexture
24- import com.lambda.util.math.Rect.Companion.basedOn
25- import com.lambda.util.math.Vec2d
2623import net.minecraft.client.texture.NativeImage
2724import org.lwjgl.opengl.GL45C.*
2825import java.awt.image.BufferedImage
29- import java.lang.IllegalStateException
26+ import java.awt.image.BufferedImage.*
3027import java.nio.ByteBuffer
28+ import kotlin.IllegalStateException
3129
3230/* *
3331 * Represents a texture that can be uploaded and bound to the graphics pipeline
3432 * Supports mipmap generation and LOD (Level of Detail) configuration
3533 */
3634open class Texture {
37- val internalFormat: Int
3835 val format: Int
3936 private val levels: Int
40- private val forceConsistency : Boolean
37+ private val nativeFormat : NativeImage . Format // For mojang native images
4138
4239 /* *
4340 * @param image Optional initial image to upload to the texture
44- * @param format The format of the image passed in
41+ * @param format The format of the image passed in, if the [image] is null, then you must pass the appropriate format
4542 * @param levels Number of mipmap levels to generate for the texture
46- * @param forceConsistency Flag to enforce consistency when updating the texture. If true, attempts to update
47- * the texture after initialization will throw an exception
4843 */
49- constructor (image: BufferedImage ? ,
50- internalFormat: Int = GL_RGBA ,
51- format: Int = GL_RGBA ,
52- levels: Int = 4 ,
53- forceConsistency: Boolean = false )
54- {
55- this .internalFormat = internalFormat
56- this .format = format
44+ constructor (image: BufferedImage ? , format: Int = GL_RGBA , levels: Int = 4 ) {
45+ this .format = image?.type?.let { bufferedMapping[it] } ? : format
5746 this .levels = levels
58- this .forceConsistency = forceConsistency
47+ this .nativeFormat = nativeMapping.getOrDefault(format, NativeImage . Format . RGBA )
5948
6049 image?.let { bindTexture(id); upload(it) }
6150 }
@@ -64,23 +53,13 @@ open class Texture {
6453 * @param buffer The image buffer
6554 * @param width The width of the image
6655 * @param height The height of the image
67- * @param format The format of the image passed in
56+ * @param format The format of the image passed in, must be specified
6857 * @param levels Number of mipmap levels to generate for the texture
69- * @param forceConsistency Flag to enforce consistency when updating the texture. If true, attempts to update
70- * the texture after initialization will throw an exception
7158 */
72- constructor (buffer: ByteBuffer ,
73- width: Int ,
74- height: Int ,
75- internalFormat: Int = GL_RGBA ,
76- format: Int = GL_RGBA ,
77- levels: Int = 4 ,
78- forceConsistency: Boolean = false )
79- {
80- this .internalFormat = internalFormat
59+ constructor (buffer: ByteBuffer , width: Int , height: Int , format: Int , levels: Int = 4 ) {
8160 this .format = format
8261 this .levels = levels
83- this .forceConsistency = forceConsistency
62+ this .nativeFormat = nativeMapping.getOrDefault(format, NativeImage . Format . RGBA )
8463
8564 bindTexture(id)
8665 upload(buffer, width, height)
@@ -117,20 +96,18 @@ open class Texture {
11796 * @param offset The mipmap level to upload the image to
11897 */
11998 fun upload (image : BufferedImage , offset : Int = 0) {
120- if (forceConsistency && initialized) throw IllegalStateException (" Client tried to update a texture, but the enforce consistency flag was present" )
121-
12299 // Store level_base +1 through `level` images and generate
123100 // mipmaps from them
124- setupLOD(levels = levels )
101+ setupLOD(levels)
125102
126103 width = image.width
127104 height = image.height
128105 initialized = true
129106
130107 // Set this mipmap to `offset` to define the original texture
131108 setupTexture(GL_LINEAR_MIPMAP_LINEAR , GL_LINEAR )
132- glTexImage2D(GL_TEXTURE_2D , offset, internalFormat , width, height, 0 , format, GL_UNSIGNED_BYTE , readImage(image, getNativeFormat(format) ))
133- 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
109+ glTexImage2D(GL_TEXTURE_2D , offset, GL_RGBA , width, height, 0 , format, GL_UNSIGNED_BYTE , readImage(image, nativeFormat ))
110+ if (levels > 0 ) glGenerateMipmap(GL_TEXTURE_2D ) // This take the derived values GL_TEXTURE_BASE_LEVEL and GL_TEXTURE_MAX_LEVEL to generate the stack
134111 }
135112
136113 /* *
@@ -143,20 +120,18 @@ open class Texture {
143120 * @param offset The mipmap level to upload the image to
144121 */
145122 fun upload (buffer : ByteBuffer , width : Int , height : Int , offset : Int = 0) {
146- if (forceConsistency && initialized) throw IllegalStateException (" Client tried to update a texture, but the enforce consistency flag was present" )
147-
148123 // Store level_base +1 through `level` images and generate
149124 // mipmaps from them
150- setupLOD(levels = levels )
125+ setupLOD(levels)
151126
152127 this .width = width
153128 this .height = height
154129 initialized = true
155130
156131 // Set this mipmap to `offset` to define the original texture
157132 setupTexture(GL_LINEAR_MIPMAP_LINEAR , GL_LINEAR )
158- glTexImage2D(GL_TEXTURE_2D , offset, internalFormat , width, height, 0 , format, GL_UNSIGNED_BYTE , buffer)
159- 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
133+ glTexImage2D(GL_TEXTURE_2D , offset, GL_RGBA , width, height, 0 , format, GL_UNSIGNED_BYTE , buffer)
134+ if (levels > 0 ) glGenerateMipmap(GL_TEXTURE_2D ) // This take the derived values GL_TEXTURE_BASE_LEVEL and GL_TEXTURE_MAX_LEVEL to generate the stack
160135 }
161136
162137 /* *
@@ -170,14 +145,9 @@ open class Texture {
170145 */
171146 fun update (image : BufferedImage , offset : Int = 0) {
172147 if (! initialized) return upload(image, offset)
173- if (forceConsistency && initialized) throw IllegalStateException (" Client tried to update a texture, but the enforce consistency flag was present" )
174-
175- check(image.width + image.height <= this .width + this .height && initialized) {
176- " Client tried to update a texture with more data than allowed" +
177- " Expected ${this .width + this .height} bytes but got ${image.width + image.height} "
178- }
179148
180- glTexSubImage2D(GL_TEXTURE_2D , offset, 0 , 0 , width, height, format, GL_UNSIGNED_BYTE , readImage(image, getNativeFormat(format)))
149+ checkDimensions(width, height)
150+ glTexSubImage2D(GL_TEXTURE_2D , offset, 0 , 0 , width, height, format, GL_UNSIGNED_BYTE , readImage(image, nativeFormat))
181151 }
182152
183153 /* *
@@ -193,26 +163,11 @@ open class Texture {
193163 */
194164 fun update (buffer : ByteBuffer , width : Int , height : Int , offset : Int = 0) {
195165 if (! initialized) return upload(buffer, width, height, offset)
196- if (forceConsistency && initialized) throw IllegalStateException (" Client tried to update a texture, but the enforce consistency flag was present" )
197-
198- check(width + height <= this .width + this .height && initialized) {
199- " Client tried to update a texture with more data than allowed\n " +
200- " Expected ${this .width + this .height} bytes but got ${width + height} "
201- }
202166
167+ checkDimensions(width, height)
203168 glTexSubImage2D(GL_TEXTURE_2D , offset, 0 , 0 , width, height, format, GL_UNSIGNED_BYTE , buffer)
204169 }
205170
206- /* *
207- * Draws the texture
208- * This function binds the texture
209- *
210- * @param coord The top left coordinate to draw at
211- * @param scale The width and height multiplier
212- */
213- fun draw (coord : Vec2d , scale : Double = 0.0) =
214- TextureRenderer .drawTexture(this , basedOn(coord, width * scale, height * scale))
215-
216171 private fun setupLOD (levels : Int ) {
217172 // When you call glTextureStorage, you're specifying the total number of levels, including level 0
218173 // This is a 0-based index system, which means that the maximum mipmap level is n-1
@@ -225,11 +180,28 @@ open class Texture {
225180 glTexParameteri(GL_TEXTURE_2D , GL_TEXTURE_MAX_LEVEL , levels)
226181 }
227182
228- private fun getNativeFormat (gl : Int ) =
229- when (gl) {
230- GL_RED , GL_GREEN , GL_BLUE -> NativeImage .Format .LUMINANCE
231- GL_RG -> NativeImage .Format .LUMINANCE_ALPHA
232- GL_RGB -> NativeImage .Format .RGB
233- else -> NativeImage .Format .RGBA
183+ private fun checkDimensions (width : Int , height : Int ) =
184+ check(width + height <= this .width + this .height && initialized) {
185+ " Client tried to update a texture with more data than allowed\n " +
186+ " Expected ${this .width + this .height} bytes but got ${width + height} "
234187 }
188+
189+ companion object {
190+ private val nativeMapping = mapOf (
191+ GL_RED to NativeImage .Format .LUMINANCE ,
192+ GL_GREEN to NativeImage .Format .LUMINANCE ,
193+ GL_BLUE to NativeImage .Format .LUMINANCE ,
194+ GL_RG to NativeImage .Format .LUMINANCE_ALPHA ,
195+ GL_RGB to NativeImage .Format .RGB ,
196+ GL_RGBA to NativeImage .Format .RGBA ,
197+ )
198+
199+ private val bufferedMapping = mapOf (
200+ TYPE_BYTE_BINARY to GL_RED ,
201+ TYPE_BYTE_GRAY to GL_RG ,
202+ TYPE_INT_RGB to GL_RGB ,
203+ TYPE_INT_ARGB to GL_RGBA ,
204+ TYPE_4BYTE_ABGR to GL_BGRA ,
205+ )
206+ }
235207}
0 commit comments