package ru.dbotthepony.kstarbound.client.render import ru.dbotthepony.kstarbound.math.FloatMatrix import ru.dbotthepony.kstarbound.math.Matrix4f import ru.dbotthepony.kstarbound.math.Matrix4fStack /** * Интерфейс для отрисовки комплексных объектов, в которых множество слоёв, который * определяет лишь один метод: [renderLayer] * * Используется вместе с другими [ILayeredRenderer], где необходимо отрисовывать комплексную сцену, * реализуя ручную сортировку геометрии. */ interface ILayeredRenderer { /** * Главный метод отрисовки данной стопки слоёв. Вызов данного метода может что-либо * отрисовать, а может вообще ничего не отрисовать. * * zLevel всегда положителен, и указывает на то, какой слой (или все слои за) надо отрисовать, * т.е. при вызове этого метода отрисовываются все слои, у которых z позиция >= [zPos] * * Возвращается zNew следующего слоя (такой, что [zPos] > zNew). * * Если следующего слоя нет, вернуть -1, и данный объект * будет считаться отрисованным. */ fun renderLayerFromStack(zPos: Int, transform: Matrix4fStack): Int /** * Возвращает наибольшее zPos в данной стопке. * * Если стопка пуста, то необходимо вернуть -1. * * В зависимости от сцены, которую необходимо отрисовать, * [renderLayerFromStack] может быть вызван сразу с этим же значением, * если этот объект имеет самый дальний слой */ fun bottomMostZLevel(): Int /** * Говорит о том, что вот-вот будет начата отрисовка в render pipeline * и будут вызываться [renderLayerFromStack]. В данном методе должна построиться * и отсортироваться стопка слоёв */ fun prepareForLayeredRender() } fun renderLayeredList(transform: Matrix4fStack, potentialRenderers: List): Int { val renderers = ArrayList(potentialRenderers.size) var bottomMost = -1 for (render in potentialRenderers) { render.prepareForLayeredRender() val zLevel = render.bottomMostZLevel() if (zLevel >= 0) { bottomMost = bottomMost.coerceAtLeast(zLevel) renderers.add(render) } } var lastBottom = bottomMost var renderCalls = 0 while (lastBottom > 0 && renderers.isNotEmpty()) { var newBottom = lastBottom for (i in renderers.size - 1 downTo 0) { val renderer = renderers[i] val newLevel = renderer.renderLayerFromStack(lastBottom, transform) renderCalls++ if (newLevel <= -1) { renderers.removeAt(i) } else { newBottom = newBottom.coerceAtMost(newLevel) } } lastBottom = newBottom } return renderCalls }