fix(lab_2): worked
All worked 2-nd lab
This commit is contained in:
parent
be5701e4de
commit
f18d6f1025
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -31,4 +31,4 @@ class Bin {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -15,4 +15,4 @@ object TransferHelper {
|
||||
val newVal = Math.max(0, Math.min((value - min) * 255 / (max - min), 255))
|
||||
return Color(newVal, newVal, newVal)
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user