From f18d6f1025c69dbfe9dff61e15bc542555f08c06 Mon Sep 17 00:00:00 2001 From: Kirill Date: Sun, 4 May 2025 16:26:52 +0300 Subject: [PATCH] fix(lab_2): worked All worked 2-nd lab --- lab_2/build.gradle.kts | 17 +- lab_2/src/main/kotlin/Bin.kt | 2 +- lab_2/src/main/kotlin/Form1.kt | 9 +- lab_2/src/main/kotlin/Main.kt | 244 +++--------------------- lab_2/src/main/kotlin/TransferHelper.kt | 2 +- lab_2/src/main/kotlin/View.kt | 92 ++------- 6 files changed, 67 insertions(+), 299 deletions(-) diff --git a/lab_2/build.gradle.kts b/lab_2/build.gradle.kts index 99a6da0..6d5cf83 100644 --- a/lab_2/build.gradle.kts +++ b/lab_2/build.gradle.kts @@ -21,18 +21,33 @@ dependencies { implementation("org.lwjgl:lwjgl") implementation("org.lwjgl:lwjgl-glfw") implementation("org.lwjgl:lwjgl-opengl") + implementation("org.lwjgl:lwjgl-stb") + implementation("org.lwjgl:lwjgl-nanovg") + implementation("org.lwjgl:lwjgl-nfd") + implementation("org.lwjgl:lwjgl-openal") runtimeOnly("org.lwjgl:lwjgl::$lwjglNatives") runtimeOnly("org.lwjgl:lwjgl-glfw::$lwjglNatives") runtimeOnly("org.lwjgl:lwjgl-opengl::$lwjglNatives") + runtimeOnly("org.lwjgl:lwjgl-stb::$lwjglNatives") + runtimeOnly("org.lwjgl:lwjgl-nanovg::$lwjglNatives") + runtimeOnly("org.lwjgl:lwjgl-nfd::$lwjglNatives") + runtimeOnly("org.lwjgl:lwjgl-openal::$lwjglNatives") + + // JavaFX bindings + implementation("org.openjfx:javafx-controls:17") + implementation("org.openjfx:javafx-fxml:17") + implementation("org.openjfx:javafx-graphics:17") } application { mainClass.set("org.exampl.MainKt") } + tasks.test { useJUnitPlatform() } + kotlin { jvmToolchain(21) -} \ No newline at end of file +} diff --git a/lab_2/src/main/kotlin/Bin.kt b/lab_2/src/main/kotlin/Bin.kt index d149867..2dadcfb 100644 --- a/lab_2/src/main/kotlin/Bin.kt +++ b/lab_2/src/main/kotlin/Bin.kt @@ -31,4 +31,4 @@ class Bin { } } } -} +} \ No newline at end of file diff --git a/lab_2/src/main/kotlin/Form1.kt b/lab_2/src/main/kotlin/Form1.kt index dd92d54..a2e8765 100644 --- a/lab_2/src/main/kotlin/Form1.kt +++ b/lab_2/src/main/kotlin/Form1.kt @@ -7,9 +7,9 @@ import javax.swing.filechooser.FileNameExtensionFilter class Form1 { private var loaded = false - private var currentLayer = 0 + var currentLayer = 0 private val bin = Bin() - private val view = View() + val view = View() private var minTF = -3000 private var widthTF = 2000 @@ -42,11 +42,14 @@ class Form1 { openFileDialog() while (!glfwWindowShouldClose(window)) { displayFPS() + glfwPollEvents() + if (loaded) { + glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) view.drawQuads(currentLayer) } + glfwSwapBuffers(window) - glfwPollEvents() } } } diff --git a/lab_2/src/main/kotlin/Main.kt b/lab_2/src/main/kotlin/Main.kt index 30a578d..9d027c5 100644 --- a/lab_2/src/main/kotlin/Main.kt +++ b/lab_2/src/main/kotlin/Main.kt @@ -1,222 +1,8 @@ package org.exampl -/*import org.lwjgl.opengl.GL -import org.lwjgl.opengl.GL11.* -import org.lwjgl.opengl.GL15.* -import org.lwjgl.opengl.GL20.* -import org.lwjgl.opengl.GL30.* -import org.lwjgl.system.MemoryUtil -import org.lwjgl.glfw.GLFW.* -import java.io.File -import java.nio.ByteBuffer -import java.nio.ByteOrder -import kotlin.math.* - -class CTVisualizer { - private var window: Long = 0 - private var vao = 0 - private var vbo = 0 - private var textureID = 0 - private var shaderProgram = 0 - private var currentLayer = 0 - private var minValue = 0 - private var maxValue = 40961 - private var windowWidth = 1600 - private var windowHeight = 1000 - private lateinit var volumeData: ShortArray - private var width = 256 // Фиксированный размер для примера - private var height = 256 - private var depth = 256 - - fun run(binFilePath: String) { - initWindow() - initOpenGL() - loadVolumeData(binFilePath) - mainLoop() - cleanup() - } - - private fun initWindow() { - if (!glfwInit()) { - throw RuntimeException("Failed to initialize GLFW") - } - - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3) - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3) - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE) - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE) - - window = glfwCreateWindow(windowWidth, windowHeight, "КТ Визуализация (OpenTK/Kotlin)", 0, 0) - if (window == 0L) { - glfwTerminate() - throw RuntimeException("Failed to create GLFW window") - } - - glfwMakeContextCurrent(window) - glfwSwapInterval(1) - glfwShowWindow(window) - } - - private fun initOpenGL() { - GL.createCapabilities() - - val vertexShader = """ - #version 330 core - layout(location = 0) in vec2 position; - layout(location = 1) in vec2 texCoord; - out vec2 TexCoord; - void main() { - gl_Position = vec4(position, 0.0, 1.0); - TexCoord = texCoord; - } - """.trimIndent() - - val fragmentShader = """ - #version 330 core - in vec2 TexCoord; - out vec4 FragColor; - uniform sampler2D ourTexture; - void main() { - FragColor = texture(ourTexture, TexCoord); - } - """.trimIndent() - - shaderProgram = createShaderProgram(vertexShader, fragmentShader) - - vao = glGenVertexArrays() - vbo = glGenBuffers() - - glBindVertexArray(vao) - glBindBuffer(GL_ARRAY_BUFFER, vbo) - - val vertices = floatArrayOf( - -1.0f, -1.0f, 0.0f, 0.0f, - 1.0f, -1.0f, 1.0f, 0.0f, - -1.0f, 1.0f, 0.0f, 1.0f, - 1.0f, 1.0f, 1.0f, 1.0f - ) - - val vertexBuffer = MemoryUtil.memAllocFloat(vertices.size) - vertexBuffer.put(vertices).flip() - - glBufferData(GL_ARRAY_BUFFER, vertexBuffer, GL_STATIC_DRAW) - glVertexAttribPointer(0, 2, GL_FLOAT, false, 4 * 4, 0) - glVertexAttribPointer(1, 2, GL_FLOAT, false, 4 * 4, 2 * 4) - glEnableVertexAttribArray(0) - glEnableVertexAttribArray(1) - - MemoryUtil.memFree(vertexBuffer) - - textureID = glGenTextures() - glBindTexture(GL_TEXTURE_2D, textureID) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) - } - - private fun loadVolumeData(binFilePath: String) { - val file = File(binFilePath) - if (!file.exists()) { - throw IllegalArgumentException("File $binFilePath not found") - } - - val buffer = ByteBuffer.wrap(file.readBytes()) - .order(ByteOrder.LITTLE_ENDIAN) - .asShortBuffer() - - volumeData = ShortArray(width * height * depth) - buffer.get(volumeData) - - // Автоматическое определение min/max значений - minValue = volumeData.minOrNull()?.toInt() ?: 0 - maxValue = volumeData.maxOrNull()?.toInt() ?: 4096 - - println("Loaded volume data: ${volumeData.size} voxels") - println("Value range: $minValue - $maxValue") - } - - private fun updateTexture(layer: Int) { - val layerData = ByteBuffer.allocateDirect(width * height * 4) - - for (y in 0 until height) { - for (x in 0 until width) { - val value = volumeData[x + y * width + layer * width * height].toInt() - val normalized = ((value - minValue).toFloat() / (maxValue - minValue).toFloat()).coerceIn(0f, 1f) - val color = (normalized * 255).toInt() - - layerData.put(color.toByte()) - layerData.put(color.toByte()) - layerData.put(color.toByte()) - layerData.put(255.toByte()) // Alpha - } - } - - layerData.flip() - glBindTexture(GL_TEXTURE_2D, textureID) - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, layerData) - } - - private fun mainLoop() { - glClearColor(0.2f, 0.3f, 0.3f, 1.0f) - - while (!glfwWindowShouldClose(window)) { - glClear(GL_COLOR_BUFFER_BIT) - - updateTexture(currentLayer) - - glUseProgram(shaderProgram) - glBindVertexArray(vao) - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4) - - glfwSwapBuffers(window) - glfwPollEvents() - - if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) { - currentLayer = min(currentLayer + 1, depth - 1) - } - if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) { - currentLayer = max(currentLayer - 1, 0) - } - } - } - - private fun createShaderProgram(vertexShaderSource: String, fragmentShaderSource: String): Int { - val vertexShader = glCreateShader(GL_VERTEX_SHADER) - glShaderSource(vertexShader, vertexShaderSource) - glCompileShader(vertexShader) - - val fragmentShader = glCreateShader(GL_FRAGMENT_SHADER) - glShaderSource(fragmentShader, fragmentShaderSource) - glCompileShader(fragmentShader) - - val program = glCreateProgram() - glAttachShader(program, vertexShader) - glAttachShader(program, fragmentShader) - glLinkProgram(program) - - glDeleteShader(vertexShader) - glDeleteShader(fragmentShader) - - return program - } - - private fun cleanup() { - glDeleteVertexArrays(vao) - glDeleteBuffers(vbo) - glDeleteTextures(textureID) - glDeleteProgram(shaderProgram) - glfwTerminate() - } -} - -fun main() { - // Укажите путь к вашему .bin файлу - val binFilePath = "./testdata.bin" - CTVisualizer().run(binFilePath) -}*/ - import org.lwjgl.glfw.GLFW.* import org.lwjgl.opengl.GL -import org.lwjgl.opengl.GL11.glViewport +import org.lwjgl.opengl.GL11.* import org.lwjgl.system.MemoryUtil.NULL import kotlin.system.exitProcess @@ -238,21 +24,35 @@ fun main() { glViewport(0, 0, width, height) } + val form1 = Form1() + + glfwSetKeyCallback(window) { _: Long, key: Int, _: Int, action: Int, _: Int -> + if (action == GLFW_PRESS || action == GLFW_REPEAT) { + when (key) { + GLFW_KEY_LEFT -> { + if (form1.currentLayer > 0) { + form1.currentLayer-- + form1.view.needReload = true + } + } + GLFW_KEY_RIGHT -> { + if (form1.currentLayer < Bin.Z - 1) { + form1.currentLayer++ + form1.view.needReload = true + } + } + } + } + } + glfwMakeContextCurrent(window) glfwSwapInterval(1) glfwShowWindow(window) GL.createCapabilities() - val form1 = Form1() form1.run(window) glfwTerminate() exitProcess(0) } - - - - - - diff --git a/lab_2/src/main/kotlin/TransferHelper.kt b/lab_2/src/main/kotlin/TransferHelper.kt index 79d8129..46d872e 100644 --- a/lab_2/src/main/kotlin/TransferHelper.kt +++ b/lab_2/src/main/kotlin/TransferHelper.kt @@ -15,4 +15,4 @@ object TransferHelper { val newVal = Math.max(0, Math.min((value - min) * 255 / (max - min), 255)) return Color(newVal, newVal, newVal) } -} +} \ No newline at end of file diff --git a/lab_2/src/main/kotlin/View.kt b/lab_2/src/main/kotlin/View.kt index f7eff35..5d97b8f 100644 --- a/lab_2/src/main/kotlin/View.kt +++ b/lab_2/src/main/kotlin/View.kt @@ -6,6 +6,8 @@ import java.awt.image.BufferedImage import java.nio.ByteBuffer class View { + var needReload = false + fun setupView(width: Int, height: Int) { glShadeModel(GL_SMOOTH) glMatrixMode(GL_PROJECTION) @@ -15,79 +17,12 @@ class View { } fun drawQuads(layerNumber: Int) { - glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) - - glBegin(GL_QUADS) - - for (x in 0 until Bin.X - 1) { - for (y in 0 until Bin.Y - 1) { - val value1 = Bin.array[x + y * Bin.X + layerNumber * Bin.X * Bin.Y] - val value2 = Bin.array[x + (y + 1) * Bin.X + layerNumber * Bin.X * Bin.Y] - val value3 = Bin.array[x + 1 + (y + 1) * Bin.X + layerNumber * Bin.X * Bin.Y] - val value4 = Bin.array[x + 1 + y * Bin.X + layerNumber * Bin.X * Bin.Y] - - val color1 = TransferHelper.transferFunction(value1) - val color2 = TransferHelper.transferFunction(value2) - val color3 = TransferHelper.transferFunction(value3) - val color4 = TransferHelper.transferFunction(value4) - - glColor3f(color1.red / 255.0f, color1.green / 255.0f, color1.blue / 255.0f) - glVertex2f(x.toFloat(), y.toFloat()) - - glColor3f(color2.red / 255.0f, color2.green / 255.0f, color2.blue / 255.0f) - glVertex2f(x.toFloat(), (y + 1).toFloat()) - - glColor3f(color3.red / 255.0f, color3.green / 255.0f, color3.blue / 255.0f) - glVertex2f((x + 1).toFloat(), (y + 1).toFloat()) - - glColor3f(color4.red / 255.0f, color4.green / 255.0f, color4.blue / 255.0f) - glVertex2f((x + 1).toFloat(), y.toFloat()) - } + if (needReload) { + generateTextureImage(layerNumber) + load2DTexture() + needReload = false } - glEnd() - } - - fun drawQuadStrip(layerNumber: Int) { - glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) - - for (x in 0 until Bin.X - 1) { - glBegin(GL_QUAD_STRIP) - - for (y in 0 until Bin.Y) { - val value1 = Bin.array[x + y * Bin.X + layerNumber * Bin.X * Bin.Y] - val value2 = Bin.array[x + 1 + y * Bin.X + layerNumber * Bin.X * Bin.Y] - - val color1 = TransferHelper.transferFunction(value1) - val color2 = TransferHelper.transferFunction(value2) - - glColor3f(color1.red / 255.0f, color1.green / 255.0f, color1.blue / 255.0f) - glVertex2f(x.toFloat(), y.toFloat()) - - glColor3f(color2.red / 255.0f, color2.green / 255.0f, color2.blue / 255.0f) - glVertex2f((x + 1).toFloat(), y.toFloat()) - } - - glEnd() - } - } - - private lateinit var textureImage: BufferedImage - private var textureID: Int = 0 - - fun generateTextureImage(layerNumber: Int) { - textureImage = BufferedImage(Bin.X, Bin.Y, BufferedImage.TYPE_INT_ARGB) - - for (x in 0 until Bin.X) { - for (y in 0 until Bin.Y) { - val pixelNumber = x + y * Bin.X + layerNumber * Bin.X * Bin.Y - val color = TransferHelper.transferFunction(Bin.array[pixelNumber]) - textureImage.setRGB(x, y, color.rgb) - } - } - } - - fun drawTexture() { glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) glEnable(GL_TEXTURE_2D) glBindTexture(GL_TEXTURE_2D, textureID) @@ -112,6 +47,21 @@ class View { glDisable(GL_TEXTURE_2D) } + private lateinit var textureImage: BufferedImage + private var textureID: Int = 0 + + fun generateTextureImage(layerNumber: Int) { + textureImage = BufferedImage(Bin.X, Bin.Y, BufferedImage.TYPE_INT_ARGB) + + for (x in 0 until Bin.X) { + for (y in 0 until Bin.Y) { + val pixelNumber = x + y * Bin.X + layerNumber * Bin.X * Bin.Y + val color = TransferHelper.transferFunction(Bin.array[pixelNumber]) + textureImage.setRGB(x, y, color.rgb) + } + } + } + fun load2DTexture() { textureID = glGenTextures() glBindTexture(GL_TEXTURE_2D, textureID)