diff --git a/fcore/field.sml b/fcore/field.sml new file mode 100644 index 0000000..f68edd3 --- /dev/null +++ b/fcore/field.sml @@ -0,0 +1,26 @@ +structure Field = +struct + fun lerp (startX, startY, drawWidth, drawHeight, windowWidth, windowHeight + , r, g, b, a) : Real32.real vector = + let + val endY = windowHeight - startY + val startY = windowHeight - (startY + drawHeight) + val endX = startX + drawWidth + val windowHeight = windowHeight / 2.0 + val windowWidth = windowWidth / 2.0 + in + #[ (((startX * (1.0 - 1.0)) + (endX * 1.0)) / windowWidth) - 1.0, + (((startY * (1.0 - 0.0)) + (endY * 0.0)) / windowHeight) - 1.0, r, g, b, a, + (((startX * (1.0 - 0.0)) + (endX * 0.0)) / windowWidth) - 1.0, + (((startY * (1.0 - 0.0)) + (endY * 0.0)) / windowHeight) - 1.0, r, g, b, a, + (((startX * (1.0 - 0.0)) + (endX * 0.0)) / windowWidth) - 1.0, + (((startY * (1.0 - 1.0)) + (endY * 1.0)) / windowHeight) - 1.0, r, g, b, a, + (((startX * (1.0 - 0.0)) + (endX * 0.0)) / windowWidth) - 1.0, + (((startY * (1.0 - 1.0)) + (endY * 1.0)) / windowHeight) - 1.0, r, g, b, a, + (((startX * (1.0 - 1.0)) + (endX * 1.0)) / windowWidth) - 1.0, + (((startY * (1.0 - 1.0)) + (endY * 1.0)) / windowHeight) - 1.0, r, g, b, a, + (((startX * (1.0 - 1.0)) + (endX * 1.0)) / windowWidth) - 1.0, + (((startY * (1.0 - 0.0)) + (endY * 0.0)) / windowHeight) - 1.0, r, g, b, a + ] + end +end diff --git a/fcore/player.sml b/fcore/player.sml index 69e0d8c..d592c32 100644 --- a/fcore/player.sml +++ b/fcore/player.sml @@ -242,6 +242,9 @@ struct val size = 35 val realSize = 35.0 + val halfSize = 35 div 2 + val halfRealSize = 35.0 / 2.0 + val moveBy = 5 (* timing variables; always start at 0, @@ -659,4 +662,49 @@ struct helpGetDrawVec (x, y, realSize, width, height, attacked, mainAttack) end end + + fun getFieldVec (player: player, width, height) = + case #mainAttack player of + MAIN_NOT_ATTACKING => Vector.fromList [] + | MAIN_ATTACKING amt => + let + val {x, y, ...} = player + val wratio = width / 1920.0 + val hratio = height / 1080.0 + in + if wratio < hratio then + let + val scale = 1080.0 * wratio + val yOffset = + if height > scale then (height - scale) / 2.0 + else if height < scale then (scale - height) / 2.0 + else 0.0 + + val x = (Real32.fromInt x - halfRealSize) * wratio + val y = (Real32.fromInt y - halfRealSize) * wratio + yOffset + + val realSize = (realSize * 2.0) * wratio + val alpha = Real32.fromInt amt / Real32.fromInt mainAttackLimit + in + Field.lerp + (x, y, realSize, realSize, width, height, 0.7, 0.7, 1.0, alpha) + end + else + let + val scale = 1920.0 * hratio + val xOffset = + if width > scale then (width - scale) / 2.0 + else if width < scale then (scale - width) / 2.0 + else 0.0 + + val x = (Real32.fromInt x - halfRealSize) * hratio + xOffset + val y = (Real32.fromInt y - halfRealSize) * hratio + + val realSize = (realSize * 2.0) * hratio + val alpha = Real32.fromInt amt / Real32.fromInt mainAttackLimit + in + Field.lerp + (x, y, realSize, realSize, width, height, 0.7, 0.7, 1.0, alpha) + end + end end diff --git a/ffi/gles3-export.c b/ffi/gles3-export.c index 79e7a11..13edbaa 100644 --- a/ffi/gles3-export.c +++ b/ffi/gles3-export.c @@ -13,6 +13,8 @@ unsigned int DYNAMIC_DRAW = GL_DYNAMIC_DRAW; // OpenGL functions used below void loadGlad() { gladLoadGLLoader((GLADloadproc)glfwGetProcAddress); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } void viewport(int width, int height) { diff --git a/oms.mlb b/oms.mlb index 6c0ccdd..ede45a7 100644 --- a/oms.mlb +++ b/oms.mlb @@ -8,6 +8,7 @@ ann "allowVectorExps true" in fcore/block.sml + fcore/field.sml end fcore/wall.sml diff --git a/shell/gl-draw.sml b/shell/gl-draw.sml index 88fe137..f5eac4e 100644 --- a/shell/gl-draw.sml +++ b/shell/gl-draw.sml @@ -8,6 +8,9 @@ struct , playerVertexBuffer: Word32.word , playerProgram: Word32.word , playerLength: int + , fieldVertexBuffer: Word32.word + , fieldProgram: Word32.word + , fieldLength: int } fun createShader (shaderType, shaderString) = @@ -38,12 +41,21 @@ struct val rgbFragmentShader = createShader (Gles3.FRAGMENT_SHADER, GlShaders.rgbFragmentShaderString) + val xyrgbaVertexShader = createShader + (Gles3.VERTEX_SHADER, GlShaders.xyrgbaVertexShaderString) + + val rgbaFragmentShader = createShader + (Gles3.FRAGMENT_SHADER, GlShaders.rgbaFragmentShaderString) + (* wall here includes both walls and platforms *) val wallVertexBuffer = Gles3.createBuffer () val wallProgram = createProgram (xyrgbVertexShader, rgbFragmentShader) val playerVertexBuffer = Gles3.createBuffer () val playerProgram = createProgram (xyrgbVertexShader, rgbFragmentShader) + + val fieldVertexBuffer = Gles3.createBuffer () + val fieldProgram = createProgram (xyrgbaVertexShader, rgbaFragmentShader) in { window = window , wallVertexBuffer = wallVertexBuffer @@ -52,6 +64,9 @@ struct , playerVertexBuffer = playerVertexBuffer , playerProgram = playerProgram , playerLength = 0 + , fieldVertexBuffer = fieldVertexBuffer + , fieldProgram = fieldProgram + , fieldLength = 0 } end @@ -62,6 +77,9 @@ struct , playerVertexBuffer , playerProgram , playerLength + , fieldVertexBuffer + , fieldProgram + , fieldLength , wallVertexBuffer , wallProgram , wallLength = _ @@ -75,6 +93,9 @@ struct , playerVertexBuffer = playerVertexBuffer , playerProgram = playerProgram , playerLength = playerLength + , fieldVertexBuffer = fieldVertexBuffer + , fieldProgram = fieldProgram + , fieldLength = fieldLength , wallVertexBuffer = wallVertexBuffer , wallProgram = wallProgram , wallLength = newWallLength @@ -88,6 +109,9 @@ struct , wallVertexBuffer , wallProgram , wallLength + , fieldVertexBuffer + , fieldProgram + , fieldLength , playerVertexBuffer , playerProgram , playerLength = _ @@ -101,12 +125,47 @@ struct , wallVertexBuffer = wallVertexBuffer , wallProgram = wallProgram , wallLength = wallLength + , fieldVertexBuffer = fieldVertexBuffer + , fieldProgram = fieldProgram + , fieldLength = fieldLength , playerVertexBuffer = playerVertexBuffer , playerProgram = playerProgram , playerLength = newPlayerLength } end + fun uploadField (shellState: t, vec) = + let + val + { window + , wallVertexBuffer + , wallProgram + , wallLength + , playerVertexBuffer + , playerProgram + , playerLength + , fieldVertexBuffer + , fieldProgram + , fieldLength = _ + } = shellState + + val _ = Gles3.bindBuffer fieldVertexBuffer + val _ = Gles3.bufferData (vec, Vector.length vec, Gles3.STATIC_DRAW) + val newFieldLength = Vector.length vec div 6 + in + { window = window + , wallVertexBuffer = wallVertexBuffer + , wallProgram = wallProgram + , wallLength = wallLength + , playerVertexBuffer = playerVertexBuffer + , playerProgram = playerProgram + , playerLength = playerLength + , fieldVertexBuffer = fieldVertexBuffer + , fieldProgram = fieldProgram + , fieldLength = newFieldLength + } + end + fun drawXyrgb (vertexBuffer, program, drawLength) = if drawLength > 0 then let @@ -126,16 +185,39 @@ struct else () + fun drawXyrgba (vertexBuffer, program, drawLength) = + if drawLength > 0 then + let + val _ = Gles3.bindBuffer vertexBuffer + (* enable xy component from uploaded array *) + val _ = Gles3.vertexAttribPointer (0, 2, 6, 0) + val _ = Gles3.enableVertexAttribArray 0 + (* enable rgb component from uploaded array *) + val _ = Gles3.vertexAttribPointer (1, 4, 6, 8) + val _ = Gles3.enableVertexAttribArray 1 + + val _ = Gles3.useProgram program + val _ = Gles3.drawArrays (Gles3.TRIANGLES, 0, drawLength) + in + () + end + else + () + fun drawWall ({wallVertexBuffer, wallProgram, wallLength, ...}: t) = drawXyrgb (wallVertexBuffer, wallProgram, wallLength) fun drawPlayer ({playerVertexBuffer, playerProgram, playerLength, ...}: t) = drawXyrgb (playerVertexBuffer, playerProgram, playerLength) + fun drawField ({fieldVertexBuffer, fieldProgram, fieldLength, ...}) = + drawXyrgba (fieldVertexBuffer, fieldProgram, fieldLength) + fun draw (shellState: t) = let val _ = drawWall shellState val _ = drawPlayer shellState + val _ = drawField shellState in () end @@ -147,12 +229,6 @@ struct val _ = Gles3.clearColor (1.0, 1.0, 1.0, 1.0) val _ = Gles3.clear () - (* todo: - * - update game state - * - consume draw messages - * - finally, draw - * *) - val input = InputState.getSnapshot () val width = InputState.getWidth () val height = InputState.getHeight () @@ -167,8 +243,11 @@ struct val platVec = Platform.getDrawVec (#platforms game, width, height) val wallVec = Vector.concat [wallVec, platVec] + val fieldVec = Player.getFieldVec (#player game, width, height) + val shellState = uploadWall (shellState, wallVec) val shellState = uploadPlayer (shellState, playerVec) + val shellState = uploadField (shellState, fieldVec) val _ = draw shellState