Skip to content

Commit

Permalink
add more rendering logic
Browse files Browse the repository at this point in the history
  • Loading branch information
mi-sts committed Oct 22, 2023
1 parent 7f5f918 commit 613fbc7
Show file tree
Hide file tree
Showing 23 changed files with 697 additions and 12 deletions.
5 changes: 5 additions & 0 deletions src/main/kotlin/solve/constants/ResourcesPaths.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package solve.constants

// Application icons.
const val IconsCatalogueApplyPath = "icons/catalogue/apply.png"
const val IconsCatalogueImagePath = "icons/catalogue/image.png"
const val IconsImporterCheckCirclePath = "icons/importer/check_circle.png"
Expand Down Expand Up @@ -27,3 +28,7 @@ const val IconsLayers = "/icons/sidepanel/Layers.png"
const val IconsLayersFilled = "/icons/sidepanel/LayersFilled.png"
const val IconsGrid = "/icons/sidepanel/Grid.png"
const val IconsGridSelected = "/icons/sidepanel/GridSelected.png"

// Engine shaders.
const val ShadersDefaultVertexPath = "engine/shaders/default/default.vert"
const val ShadersDefaultFragmentPath = "engine/shaders/default/default.frag"
1 change: 0 additions & 1 deletion src/main/kotlin/solve/rendering/canvas/OpenGLCanvas.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import com.huskerdev.openglfx.events.GLRenderEvent
import com.huskerdev.openglfx.events.GLReshapeEvent
import com.huskerdev.openglfx.OpenGLCanvas as OpenGLFXCanvas
import com.huskerdev.openglfx.lwjgl.LWJGLExecutor
import org.lwjgl.opengl.GL
import org.lwjgl.opengl.GL.createCapabilities
import org.lwjgl.opengl.GL11
import org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT
Expand Down
38 changes: 38 additions & 0 deletions src/main/kotlin/solve/rendering/engine/Window.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package solve.rendering.engine

import org.joml.Matrix4f
import org.joml.Vector2f
import solve.rendering.engine.camera.Camera
import solve.rendering.engine.scene.Scene

class Window(
width: Int,
height: Int,
camera: Camera = Camera(),
scene: Scene? = null
) {
var width = width
private set
var height = height
private set

var scene: Scene? = scene
private set
var camera: Camera = camera
private set

fun changeScene(newScene: Scene) {
scene = newScene
}

fun changeCamera(newCamera: Camera) {
camera = newCamera
}

fun resize(newWidth: Int, newHeight: Int) {
width = newWidth
height = newHeight
}

fun calculateProjectionMatrix() = camera.calculateProjectionMatrix(Vector2f(width.toFloat(), height.toFloat()))
}
4 changes: 4 additions & 0 deletions src/main/kotlin/solve/rendering/engine/camera/Camera.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package solve.rendering.engine.camera

import org.joml.Matrix4f
import org.joml.Vector2f
import org.joml.Vector3f
import solve.utils.times

class Camera(var position: Vector2f = Vector2f(), zoom: Float = 1f) {
Expand Down Expand Up @@ -42,5 +43,8 @@ class Camera(var position: Vector2f = Vector2f(), zoom: Float = 1f) {
companion object {
private const val ProjectionOrthoZNear = 0.01f
private const val ProjectionOrthoZFar = 100f

private val cameraFrontVector = Vector3f(0f, 0f, -1f)
private val cameraUpVector = Vector3f(0f, 1f, 0f)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package solve.rendering.engine.structure
package solve.rendering.engine.components

open class Component(private val gameObject: GameObject) {
import solve.rendering.engine.scene.GameObject

abstract class Component(val gameObject: GameObject) {
open fun start() { }

open fun update(deltaTime: Float) { }
Expand Down
36 changes: 36 additions & 0 deletions src/main/kotlin/solve/rendering/engine/components/Sprite.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package solve.rendering.engine.components

import org.joml.Vector2f
import solve.rendering.engine.rendering.texture.Texture

class Sprite(val texture: Texture, uvCoordinates: List<Vector2f> = defaultUVCoordinates) {
val uvCoordinates: List<Vector2f>

val width: Int
get() = texture.width
val height: Int
get() = texture.height

init {
if (uvCoordinates.count() != UVCoordinatesNumber) {
println("The number of the uv coordinates is incorrect!")
this.uvCoordinates = defaultUVCoordinates
} else {
this.uvCoordinates = uvCoordinates
}
}

fun setTexture(texture: Texture) {

}

companion object {
private const val UVCoordinatesNumber = 4
private val defaultUVCoordinates = listOf(
Vector2f(0f, 0f),
Vector2f(0f, 1f),
Vector2f(1f, 1f),
Vector2f(1f, 0f)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package solve.rendering.engine.components

import solve.rendering.engine.rendering.texture.Texture
import solve.rendering.engine.scene.GameObject
import solve.rendering.engine.structures.Color

class SpriteRenderer(gameObject: GameObject) : Component(gameObject) {
var color = Color.white
private set
var sprite: Sprite? = null
private set

fun setColor(color: Color) {
this.color = color
}

fun setTexture(texture: Texture) {
if (sprite?.texture != texture) {
sprite = Sprite(texture)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package solve.rendering.engine.rendering.batch

import org.lwjgl.opengl.GL11.GL_LINES

import org.lwjgl.opengl.GL11.GL_POINTS
import org.lwjgl.opengl.GL11.GL_TRIANGLES

enum class PrimitiveType(
val verticesNumber: Int,
val openGLPrimitive: Int,
val verticesDrawingOrder: List<Int>
) {
Point(1, GL_POINTS, listOf(0)),
Line(2, GL_LINES, listOf(0, 1)),
Triangle(3, GL_TRIANGLES, listOf(0, 1, 2)),
Quad(4, GL_TRIANGLES, listOf(3, 2, 0, 0, 2, 1));

val drawingOrderElementsNumber = verticesDrawingOrder.count()
}
136 changes: 136 additions & 0 deletions src/main/kotlin/solve/rendering/engine/rendering/batch/RenderBatch.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package solve.rendering.engine.rendering.batch

import org.lwjgl.opengl.GL15.GL_ARRAY_BUFFER
import org.lwjgl.opengl.GL15.GL_DYNAMIC_DRAW
import org.lwjgl.opengl.GL15.GL_ELEMENT_ARRAY_BUFFER
import org.lwjgl.opengl.GL15.GL_STATIC_DRAW
import org.lwjgl.opengl.GL15.glBindBuffer
import org.lwjgl.opengl.GL15.glBufferData
import org.lwjgl.opengl.GL15.glBufferSubData
import org.lwjgl.opengl.GL15.glDeleteBuffers
import org.lwjgl.opengl.GL15.glGenBuffers
import org.lwjgl.opengl.GL20.glEnableVertexAttribArray
import org.lwjgl.opengl.GL20.glVertexAttribPointer
import org.lwjgl.opengl.GL30.glBindVertexArray
import org.lwjgl.opengl.GL30.glDeleteVertexArrays
import org.lwjgl.opengl.GL30.glGenVertexArrays
import solve.rendering.engine.rendering.texture.Texture
import solve.rendering.engine.shader.ShaderAttributeType

open class RenderBatch(
private val maxBatchSize: Int,
val zIndex: Int,
val primitiveType: PrimitiveType,
private val attributes: List<ShaderAttributeType>
) {
var isFull = false
private set

private var vboID = 0
private var vaoID = 0
private var eboID = 0

private val textureIDs = mutableListOf<Int>()
private val textures = mutableListOf<Texture>()

private val attributesNumber = attributes.sumOf { it.number }
private val attributesTotalSize = attributes.sumOf { it.size }

private val verticesDataBuffer = FloatArray(maxBatchSize * primitiveType.verticesNumber * attributesNumber)
private var verticesDataBufferIndexPointer = 0

init {
initializeBuffers()
initializeAttributes()
}

fun bind() {
glBindVertexArray(vaoID)
textures.forEachIndexed { index, texture -> texture.bindToSlot(index + 1) }
}

fun unbind() {
textures.forEach { it.unbind() }
glBindVertexArray(0)
}

fun rebuffer() {
glBindBuffer(GL_ARRAY_BUFFER, vboID)
glBufferSubData(GL_ARRAY_BUFFER, 0, verticesDataBuffer)
}

fun deleteBuffers() {
glDeleteBuffers(vboID)
glDeleteBuffers(eboID)
glDeleteVertexArrays(vaoID)
}

fun addTexture(texture: Texture): Int {
var textureID = 0
if (textures.contains(texture)) {
textureID = textures.indexOf(texture) + 1
} else {
textures.add(texture)
textureID = textures.lastIndex + 1

if (textures.count() >= maxBatchSize)
isFull = true
}

return textureID
}

fun removeTexture(texture: Texture): Boolean = textures.remove(texture)

fun containsTexture(texture: Texture) = textures.contains(texture)

fun getVerticesNumber(): Int {
if (verticesDataBufferIndexPointer % attributesNumber != 0)
println("The vertices data buffer seems to not have correct amount of data!")

return (verticesDataBufferIndexPointer * primitiveType.drawingOrderElementsNumber /
(attributesNumber * primitiveType.verticesNumber))
}

private fun initializeBuffers() {
vaoID = glGenVertexArrays()
glBindVertexArray(vaoID)

vboID = glGenBuffers()
glBindBuffer(GL_ARRAY_BUFFER, vboID)
val verticesBufferSize = (verticesDataBuffer.size * Float.SIZE_BYTES).toLong()
glBufferData(GL_ARRAY_BUFFER, verticesBufferSize, GL_DYNAMIC_DRAW)

eboID = glGenBuffers()
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboID)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, generateElementsIndices(), GL_STATIC_DRAW)
}

private fun initializeAttributes() {
var attributesSizeOffset = 0L
for (i in 0 until attributes.count()) {
val attribute = attributes[i]
glVertexAttribPointer(
i,
attribute.number,
attribute.openGLType,
false,
attributesTotalSize,
attributesSizeOffset
)
glEnableVertexAttribArray(i)
attributesSizeOffset += attribute.size
}
}

private fun generateElementsIndices(): IntArray {
val elementsBuffer = IntArray(maxBatchSize * primitiveType.verticesNumber)
for (i in 0 until maxBatchSize) {
primitiveType.verticesDrawingOrder.forEach { vertexIndex ->
elementsBuffer[i * primitiveType.verticesNumber] = i + vertexIndex
}
}

return elementsBuffer
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package solve.rendering.engine.rendering.renderers

import org.lwjgl.opengl.GL11.GL_UNSIGNED_INT
import org.lwjgl.opengl.GL11.glDrawElements
import solve.rendering.engine.Window
import solve.rendering.engine.rendering.batch.RenderBatch
import solve.rendering.engine.shader.ShaderProgram
import solve.rendering.engine.scene.GameObject
import solve.rendering.engine.scene.Scene

abstract class Renderer(protected val window: Window) {
protected var needToRebuffer = true
private lateinit var shaderProgram: ShaderProgram
private val batches = mutableListOf<RenderBatch>()

init {
initialize()
}

open fun render() {
beforeRender()
shaderProgram.use()
uploadUniforms(shaderProgram)

if (needToRebuffer) {
updateBatchesData()
rebufferBatches()
}

batches.forEach { batch ->
batch.bind()
glDrawElements(batch.primitiveType.openGLPrimitive, batch.getVerticesNumber(), GL_UNSIGNED_INT, 0)
batch.unbind()
}
shaderProgram.detach()
}

fun cleanup() {
batches.forEach { it.deleteBuffers() }
}

protected open fun beforeRender() { }

protected abstract fun createShaderProgram(): ShaderProgram

protected abstract fun createNewBatch(zIndex: Int): RenderBatch

protected abstract fun uploadUniforms(shaderProgram: ShaderProgram)

protected abstract fun updateBatchesData()

protected abstract fun addGameObject(gameObject: GameObject)

protected abstract fun removeGameObject(gameObject: GameObject): Boolean

private fun initialize() {
shaderProgram = createShaderProgram()
}

private fun rebufferBatches() {
batches.forEach { it.rebuffer() }
}
}
Loading

0 comments on commit 613fbc7

Please sign in to comment.