Skip to content

Commit

Permalink
Add Paths batching
Browse files Browse the repository at this point in the history
  • Loading branch information
Your Name committed Jan 16, 2025
1 parent cfa9e03 commit 0019b76
Show file tree
Hide file tree
Showing 19 changed files with 958 additions and 159 deletions.
2 changes: 2 additions & 0 deletions worldwind/src/commonMain/kotlin/earth/worldwind/WorldWind.kt
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ open class WorldWind @JvmOverloads constructor(
* The number of bits in the depth buffer associated with this WorldWind.
*/
protected var depthBits = 0
protected var frameIndex = 0L
private val scratchModelview = Matrix4()
private val scratchProjection = Matrix4()
private val scratchPoint = Vec3()
Expand Down Expand Up @@ -444,6 +445,7 @@ open class WorldWind @JvmOverloads constructor(
)
rc.renderResourceCache = renderResourceCache
rc.verticalExaggeration = verticalExaggeration
rc.frameIndex = frameIndex++
rc.densityFactor = densityFactor
rc.atmosphereAltitude = atmosphereAltitude
rc.globeState = globe.state
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,50 +5,49 @@ import earth.worldwind.geom.Vec3
import earth.worldwind.render.Color
import earth.worldwind.render.Texture
import earth.worldwind.render.buffer.AbstractBufferObject
import earth.worldwind.render.buffer.FloatBufferObject
import earth.worldwind.render.program.TriangleShaderProgram
import earth.worldwind.render.VertexState

open class DrawShapeState internal constructor() {
companion object {
const val MAX_DRAW_ELEMENTS = 4
}

var program: TriangleShaderProgram? = null
var vertexBuffer: FloatBufferObject? = null
var elementBuffer: AbstractBufferObject? = null
val vertexOrigin = Vec3()
var vertexStride = 0
var enableCullFace = true
var enableDepthTest = true
var enableDepthWrite = true
var depthOffset = 0.0
var isLine = false
var isStatic = false
val vertexState = VertexState()
var pickIdOffset = 0
protected val color = Color()
protected var opacity = 1.0f
protected var lineWidth = 1f
protected var texture: Texture? = null
protected val texCoordMatrix = Matrix3()
private val texCoordAttrib = VertexAttrib()
internal var primCount = 0
internal val prims = Array(MAX_DRAW_ELEMENTS) { DrawElements() }

open fun reset() {
program = null
vertexBuffer = null
vertexState.reset()
elementBuffer = null
vertexOrigin.set(0.0, 0.0, 0.0)
vertexStride = 0
enableCullFace = true
enableDepthTest = true
isLine = false
isStatic = false
depthOffset = 0.0
color.set(1f, 1f, 1f, 1f)
pickIdOffset = 0
opacity = 1.0f
lineWidth = 1f
texture = null
texCoordMatrix.setToIdentity()
texCoordAttrib.size = 0
texCoordAttrib.offset = 0
primCount = 0
for (idx in 0 until MAX_DRAW_ELEMENTS) prims[idx].texture = null
}
Expand All @@ -63,11 +62,6 @@ open class DrawShapeState internal constructor() {

fun texCoordMatrix(matrix: Matrix3) = apply { texCoordMatrix.copy(matrix) }

fun texCoordAttrib(size: Int, offset: Int) = apply {
texCoordAttrib.size = size
texCoordAttrib.offset = offset
}

open fun drawElements(mode: Int, count: Int, type: Int, offset: Int) {
val prim = prims[primCount++]
prim.mode = mode
Expand All @@ -79,8 +73,6 @@ open class DrawShapeState internal constructor() {
prim.lineWidth = lineWidth
prim.texture = texture
prim.texCoordMatrix.copy(texCoordMatrix)
prim.texCoordAttrib.size = texCoordAttrib.size
prim.texCoordAttrib.offset = texCoordAttrib.offset
}

internal open class DrawElements {
Expand All @@ -93,11 +85,5 @@ open class DrawShapeState internal constructor() {
var lineWidth = 0f
var texture: Texture? = null
val texCoordMatrix = Matrix3()
val texCoordAttrib = VertexAttrib()
}

internal open class VertexAttrib {
var size = 0
var offset = 0
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ open class DrawableLines protected constructor(): Drawable {
// Disable texturing.
program.enableTexture(false)

// Ensure program is in triangles mode
program.enableOneVertexMode(false)
// Ensure program is in lines mode
program.enableLinesMode(true)
program.enableVertexColorAndWidth(false)

// Use the leader's color.
program.loadColor(color)
Expand All @@ -78,8 +79,8 @@ open class DrawableLines protected constructor(): Drawable {
if (!enableDepthTest) dc.gl.disable(GL_DEPTH_TEST)

// Use the leader line as the vertex point attribute.
dc.gl.enableVertexAttribArray(1 /*value*/)
dc.gl.enableVertexAttribArray(2 /*value*/)
dc.gl.enableVertexAttribArray(1 /*pointB*/)
dc.gl.enableVertexAttribArray(2 /*pointC*/)

// Use the shape's vertex point attribute and vertex texture coordinate attribute.
dc.gl.vertexAttribPointer(0 /*pointA*/, 4, GL_FLOAT, false, 20, offset + 0)
Expand All @@ -92,7 +93,7 @@ open class DrawableLines protected constructor(): Drawable {
// Restore the default WorldWind OpenGL state.
if (!enableDepthTest) dc.gl.enable(GL_DEPTH_TEST)

dc.gl.disableVertexAttribArray(1 /*value*/)
dc.gl.disableVertexAttribArray(2 /*value*/)
dc.gl.disableVertexAttribArray(1 /*pointB*/)
dc.gl.disableVertexAttribArray(2 /*pointC*/)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import earth.worldwind.geom.Matrix4
import earth.worldwind.util.Pool
import earth.worldwind.util.kgl.GL_CULL_FACE
import earth.worldwind.util.kgl.GL_DEPTH_TEST
import earth.worldwind.util.kgl.GL_FLOAT
import earth.worldwind.util.kgl.GL_LINES
import earth.worldwind.util.kgl.GL_LINE_LOOP
import earth.worldwind.util.kgl.GL_LINE_STRIP
import earth.worldwind.util.kgl.GL_TEXTURE0
import kotlin.jvm.JvmStatic

Expand Down Expand Up @@ -32,7 +34,7 @@ open class DrawableShape protected constructor(): Drawable {
// TODO shape batching
val program = drawState.program ?: return // program unspecified
if (!program.useProgram(dc)) return // program failed to build
if (drawState.vertexBuffer?.bindBuffer(dc) != true) return // vertex buffer unspecified or failed to bind
if (!drawState.vertexState.bind(dc)) return
if (drawState.elementBuffer?.bindBuffer(dc) != true) return // element buffer unspecified or failed to bind

// Use the draw context's pick mode.
Expand All @@ -41,10 +43,8 @@ open class DrawableShape protected constructor(): Drawable {
// Use the draw context's modelview projection matrix, transformed to shape local coordinates.
if (drawState.depthOffset != 0.0) {
mvpMatrix.copy(dc.projection).offsetProjectionDepth(drawState.depthOffset)
program.loadClipDistance((mvpMatrix.m[11] / (mvpMatrix.m[10] - 1.0)).toFloat() / 2.0f) // nearPlane / 2.0f
mvpMatrix.multiplyByMatrix(dc.modelview)
} else {
program.loadClipDistance((dc.projection.m[11] / (dc.projection.m[10] - 1.0)).toFloat() / 2.0f) // nearPlane / 2.0f
mvpMatrix.copy(dc.modelviewProjection)
}
mvpMatrix.multiplyByTranslation(
Expand All @@ -53,6 +53,7 @@ open class DrawableShape protected constructor(): Drawable {
drawState.vertexOrigin.z
)
program.loadModelviewProjection(mvpMatrix)
program.loadPickIdOffset(drawState.pickIdOffset)

// Disable triangle back face culling if requested.
if (!drawState.enableCullFace) dc.gl.disable(GL_CULL_FACE)
Expand All @@ -66,48 +67,30 @@ open class DrawableShape protected constructor(): Drawable {
// Make multi-texture unit 0 active.
dc.activeTextureUnit(GL_TEXTURE0)

// Use the shape's vertex point attribute and vertex texture coordinate attribute.
dc.gl.enableVertexAttribArray(1 /*vertexTexCoord*/)
dc.gl.enableVertexAttribArray(2 /*vertexTexCoord*/)
dc.gl.enableVertexAttribArray(3 /*vertexTexCoord*/)
program.enableLinesMode(drawState.isLine)
program.enableVertexColorAndWidth(drawState.isStatic)
if (drawState.isLine) program.loadScreen(
dc.viewport.width.toFloat(),
dc.viewport.height.toFloat()
)

if (drawState.isLine) {
program.enableOneVertexMode(false)
program.loadScreen(dc.viewport.width.toFloat(), dc.viewport.height.toFloat())
dc.gl.vertexAttribPointer(0 /*pointA*/, 4, GL_FLOAT, false, 20, 0)
dc.gl.vertexAttribPointer(1 /*pointB*/, 4, GL_FLOAT, false, 20, 80)
dc.gl.vertexAttribPointer(2 /*pointC*/, 4, GL_FLOAT, false, 20, 160)
dc.gl.vertexAttribPointer(3 /*texCoord*/, 1, GL_FLOAT, false, 20, 96)
} else {
program.enableOneVertexMode(true)
dc.gl.vertexAttribPointer(0 /*vertexPoint*/, 3, GL_FLOAT, false, drawState.vertexStride, 0)
dc.gl.vertexAttribPointer(1 /*vertexPoint*/, 3, GL_FLOAT, false, drawState.vertexStride, 0)
dc.gl.vertexAttribPointer(2 /*vertexPoint*/, 3, GL_FLOAT, false, drawState.vertexStride, 0)
}
// Draw the specified primitives.
for (idx in 0 until drawState.primCount) {
val prim = drawState.prims[idx]
program.loadColor(prim.color)
program.loadOpacity(prim.opacity)
if (!drawState.isStatic) {
program.loadColor(prim.color)
program.loadLineWidth(prim.lineWidth)
}
if (prim.texture?.bindTexture(dc) == true) {
program.loadTexCoordMatrix(prim.texCoordMatrix)
program.enableTexture(true)
} else {
program.enableTexture(false)
}
if (drawState.isLine) {
program.loadLineWidth(prim.lineWidth)
} else {
dc.gl.vertexAttribPointer(
3 /*vertexTexCoord*/,
prim.texCoordAttrib.size,
GL_FLOAT,
false,
drawState.vertexStride,
prim.texCoordAttrib.offset
)
dc.gl.lineWidth(prim.lineWidth)
}
if (prim.mode == GL_LINES || prim.mode == GL_LINE_STRIP || prim.mode == GL_LINE_LOOP) dc.gl.lineWidth(
prim.lineWidth
)
dc.gl.drawElements(prim.mode, prim.count, prim.type, prim.offset)
}

Expand All @@ -117,8 +100,6 @@ open class DrawableShape protected constructor(): Drawable {
if (!drawState.enableDepthWrite) dc.gl.depthMask(true)
dc.gl.lineWidth(1f)
dc.gl.enable(GL_CULL_FACE)
dc.gl.disableVertexAttribArray(1 /*vertexTexCoord*/)
dc.gl.disableVertexAttribArray(2 /*vertexTexCoord*/)
dc.gl.disableVertexAttribArray(3 /*vertexTexCoord*/)
drawState.vertexState.unbind(dc)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,6 @@ open class DrawableSurfaceShape protected constructor(): Drawable {
// Make multi-texture unit 0 active.
dc.activeTextureUnit(GL_TEXTURE0)

// Set up to use vertex tex coord attributes.
dc.gl.enableVertexAttribArray(1 /*vertexTexCoord*/)
dc.gl.enableVertexAttribArray(2 /*vertexTexCoord*/)
dc.gl.enableVertexAttribArray(3 /*vertexTexCoord*/)

// Accumulate shapes in the draw context's scratch list.
// TODO accumulate in a geospatial quadtree
val scratchList = dc.scratchList
Expand Down Expand Up @@ -75,10 +70,6 @@ open class DrawableSurfaceShape protected constructor(): Drawable {
} finally {
// Clear the accumulated shapes.
scratchList.clear()
// Restore the default WorldWind OpenGL state.
dc.gl.disableVertexAttribArray(1 /*vertexTexCoord*/)
dc.gl.disableVertexAttribArray(2 /*vertexTexCoord*/)
dc.gl.disableVertexAttribArray(3 /*vertexTexCoord*/)
}
}

Expand Down Expand Up @@ -126,9 +117,11 @@ open class DrawableSurfaceShape protected constructor(): Drawable {
// Get the shape.
val shape = element as DrawableSurfaceShape
if (shape.offset != terrain.offset || !shape.sector.intersectsOrNextTo(terrainSector)) continue
if (shape.drawState.vertexBuffer?.bindBuffer(dc) != true) continue // vertex buffer unspecified or failed to bind
if (!shape.drawState.vertexState.bind(dc)) continue
if (shape.drawState.elementBuffer?.bindBuffer(dc) != true) continue // element buffer unspecified or failed to bind

program.enableLinesMode(shape.drawState.isLine)
program.enableVertexColorAndWidth(shape.drawState.isStatic)
// Transform local shape coordinates to texture fragments appropriate for the terrain sector.
mvpMatrix.copy(textureMvpMatrix)
mvpMatrix.multiplyByTranslation(
Expand All @@ -137,47 +130,32 @@ open class DrawableSurfaceShape protected constructor(): Drawable {
shape.drawState.vertexOrigin.z
)
program.loadModelviewProjection(mvpMatrix)
program.enableOneVertexMode(!shape.drawState.isLine)
if (shape.drawState.isLine) {
dc.gl.vertexAttribPointer(0 /*pointA*/, 4, GL_FLOAT, false, 20, 0)
dc.gl.vertexAttribPointer(1 /*pointB*/, 4, GL_FLOAT, false, 20, 80)
dc.gl.vertexAttribPointer(2 /*pointC*/, 4, GL_FLOAT, false, 20, 160)
dc.gl.vertexAttribPointer(3 /*vertexTexCoord*/, 1, GL_FLOAT, false, 20, 96)
} else {
// Use the shape's vertex point attribute.
dc.gl.vertexAttribPointer(0 /*vertexPoint*/, 3, GL_FLOAT, false, shape.drawState.vertexStride, 0)
dc.gl.vertexAttribPointer(1 /*vertexPoint*/, 3, GL_FLOAT, false, shape.drawState.vertexStride, 0)
dc.gl.vertexAttribPointer(2 /*vertexPoint*/, 3, GL_FLOAT, false, shape.drawState.vertexStride, 0)
}
program.loadPickIdOffset(shape.drawState.pickIdOffset)

// Draw the specified primitives to the framebuffer texture.
for (primIdx in 0 until shape.drawState.primCount) {
val prim = shape.drawState.prims[primIdx]
program.loadColor(prim.color)
program.loadOpacity(prim.opacity)
if (!drawState.isStatic) {
program.loadColor(prim.color)
program.loadLineWidth(prim.lineWidth)
}
if (prim.texture?.bindTexture(dc) == true) {
program.loadTexCoordMatrix(prim.texCoordMatrix)
program.enableTexture(true)
} else {
program.enableTexture(false)
}
if (shape.drawState.isLine) {
program.loadLineWidth(prim.lineWidth)
} else {
dc.gl.vertexAttribPointer(
3 /*vertexTexCoord*/,
prim.texCoordAttrib.size,
GL_FLOAT,
false,
shape.drawState.vertexStride,
prim.texCoordAttrib.offset
)
dc.gl.lineWidth(prim.lineWidth)
}
if (prim.mode == GL_LINES || prim.mode == GL_LINE_STRIP || prim.mode == GL_LINE_LOOP) dc.gl.lineWidth(
prim.lineWidth
)
dc.gl.drawElements(prim.mode, prim.count, prim.type, prim.offset)
}

// Accumulate the number of shapes drawn into the texture.
shapeCount++

shape.drawState.vertexState.unbind(dc)
}
} finally {
// Restore the default WorldWind OpenGL state.
Expand All @@ -192,22 +170,26 @@ open class DrawableSurfaceShape protected constructor(): Drawable {
protected open fun drawTextureToTerrain(dc: DrawContext, terrain: DrawableTerrain) {
val program = drawState.program ?: return
try {
dc.gl.enableVertexAttribArray(3 /*vertexTexCoord*/)
if (!terrain.useVertexPointAttrib(dc, 0 /*vertexPoint*/)) return // terrain vertex attribute failed to bind
if (!terrain.useVertexPointAttrib(dc, 1 /*vertexPoint*/)) return // terrain vertex attribute failed to bind
if (!terrain.useVertexPointAttrib(dc, 2 /*vertexPoint*/)) return // terrain vertex attribute failed to bind
if (!terrain.useVertexTexCoordAttrib(dc, 3 /*vertexTexCoord*/)) return // terrain vertex attribute failed to bind

val colorAttachment = dc.scratchFramebuffer.getAttachedTexture(GL_COLOR_ATTACHMENT0)
if (!colorAttachment.bindTexture(dc)) return // framebuffer texture failed to bind

// Configure the program to draw texture fragments unmodified and aligned with the terrain.
// TODO consolidate pickMode and enableTexture into a single textureMode
// TODO it's confusing that pickMode must be disabled during surface shape render-to-texture
program.enableOneVertexMode(true)
program.enableLinesMode(false)
program.enableVertexColorAndWidth(false)
program.enablePickMode(false)
program.enableTexture(true)
program.loadTexCoordMatrix(identityMatrix3)
program.loadColor(color)
program.loadOpacity(opacity)
program.loadPickIdOffset(0)
program.loadScreen(dc.viewport.width.toFloat(), dc.viewport.height.toFloat())

// Use the draw context's modelview projection matrix, transformed to terrain local coordinates.
Expand All @@ -220,6 +202,7 @@ open class DrawableSurfaceShape protected constructor(): Drawable {
// Draw the terrain as triangles.
terrain.drawTriangles(dc)
} finally {
dc.gl.disableVertexAttribArray(3 /*vertexTexCoord*/)
// Unbind color attachment texture to avoid feedback loop
dc.bindTexture(KglTexture.NONE)
}
Expand Down
Loading

0 comments on commit 0019b76

Please sign in to comment.