mirror of
https://github.com/SashLilac/cambridge.git
synced 2025-05-13 20:21:25 -05:00
Initial 3D blocks support
This commit is contained in:
300
tetris/components/draw_block.lua
Normal file
300
tetris/components/draw_block.lua
Normal file
@@ -0,0 +1,300 @@
|
||||
local mat4 = cpml.mat4
|
||||
local vec3 = cpml.vec3
|
||||
|
||||
local cube = {
|
||||
front = {},
|
||||
top = {},
|
||||
bottom = {},
|
||||
left = {},
|
||||
right = {}
|
||||
}
|
||||
for scale = 1,2 do
|
||||
cube.front[scale] = love.graphics.newMesh(
|
||||
{
|
||||
{ "VertexPosition", "float", 3 },
|
||||
{ "VertexTexCoord", "float", 2 },
|
||||
{ "VertexColor", "byte", 4}
|
||||
},
|
||||
{
|
||||
{
|
||||
0, 0, 0,
|
||||
0, 0,
|
||||
1, 1, 1
|
||||
},
|
||||
|
||||
{
|
||||
16*scale, 0, 0,
|
||||
1, 0,
|
||||
1, 1, 1,
|
||||
},
|
||||
|
||||
{
|
||||
0, 16*scale, 0,
|
||||
0, 1,
|
||||
1, 1, 1,
|
||||
},
|
||||
|
||||
{
|
||||
16*scale, 16*scale, 0,
|
||||
1, 1,
|
||||
1, 1, 1,
|
||||
},
|
||||
},
|
||||
"strip",
|
||||
"static"
|
||||
)
|
||||
cube.top[scale] = love.graphics.newMesh(
|
||||
{
|
||||
{ "VertexPosition", "float", 3 },
|
||||
{ "VertexTexCoord", "float", 2 },
|
||||
{ "VertexColor", "byte", 4}
|
||||
},
|
||||
{
|
||||
{
|
||||
0, 0, 0,
|
||||
0, 0,
|
||||
1, 1, 1
|
||||
},
|
||||
|
||||
{
|
||||
16*scale, 0, 0,
|
||||
1, 0,
|
||||
1, 1, 1,
|
||||
},
|
||||
|
||||
{
|
||||
0, 0, 16*scale,
|
||||
0, 1,
|
||||
1, 1, 1,
|
||||
},
|
||||
|
||||
{
|
||||
16*scale, 0, 16*scale,
|
||||
1, 1,
|
||||
1, 1, 1,
|
||||
},
|
||||
},
|
||||
"strip",
|
||||
"static"
|
||||
)
|
||||
cube.bottom[scale] = love.graphics.newMesh(
|
||||
{
|
||||
{ "VertexPosition", "float", 3 },
|
||||
{ "VertexTexCoord", "float", 2 },
|
||||
{ "VertexColor", "byte", 4}
|
||||
},
|
||||
{
|
||||
{
|
||||
0, 16*scale, 16*scale,
|
||||
0, 0,
|
||||
1, 1, 1
|
||||
},
|
||||
|
||||
{
|
||||
16*scale, 16*scale, 16*scale,
|
||||
1, 0,
|
||||
1, 1, 1,
|
||||
},
|
||||
|
||||
{
|
||||
0, 16*scale, 0,
|
||||
0, 1,
|
||||
1, 1, 1,
|
||||
},
|
||||
|
||||
{
|
||||
16*scale, 16*scale, 0,
|
||||
1, 1,
|
||||
1, 1, 1,
|
||||
},
|
||||
},
|
||||
"strip",
|
||||
"static"
|
||||
)
|
||||
cube.left[scale] = love.graphics.newMesh(
|
||||
{
|
||||
{ "VertexPosition", "float", 3 },
|
||||
{ "VertexTexCoord", "float", 2 },
|
||||
{ "VertexColor", "byte", 4}
|
||||
},
|
||||
{
|
||||
{
|
||||
0, 0, 0,
|
||||
0, 0,
|
||||
1, 1, 1
|
||||
},
|
||||
|
||||
{
|
||||
0, 16*scale, 0,
|
||||
1, 0,
|
||||
1, 1, 1,
|
||||
},
|
||||
|
||||
{
|
||||
0, 0, 16*scale,
|
||||
0, 1,
|
||||
1, 1, 1,
|
||||
},
|
||||
|
||||
{
|
||||
0, 16*scale, 16*scale,
|
||||
1, 1,
|
||||
1, 1, 1,
|
||||
},
|
||||
},
|
||||
"strip",
|
||||
"static"
|
||||
)
|
||||
cube.right[scale] = love.graphics.newMesh(
|
||||
{
|
||||
{ "VertexPosition", "float", 3 },
|
||||
{ "VertexTexCoord", "float", 2 },
|
||||
{ "VertexColor", "byte", 4}
|
||||
},
|
||||
{
|
||||
{
|
||||
16*scale, 16*scale, 16*scale,
|
||||
0, 0,
|
||||
1, 1, 1
|
||||
},
|
||||
|
||||
{
|
||||
16*scale, 0, 16*scale,
|
||||
1, 0,
|
||||
1, 1, 1,
|
||||
},
|
||||
|
||||
{
|
||||
16*scale, 16*scale, 0,
|
||||
0, 1,
|
||||
1, 1, 1,
|
||||
},
|
||||
|
||||
{
|
||||
16*scale, 0, 0,
|
||||
1, 1,
|
||||
1, 1, 1,
|
||||
},
|
||||
},
|
||||
"strip",
|
||||
"static"
|
||||
)
|
||||
end
|
||||
|
||||
local shader_no_discard = {
|
||||
shader = love.graphics.newShader(
|
||||
[[
|
||||
vec4 effect(vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords) {
|
||||
vec4 texcolor = Texel(tex, texture_coords);
|
||||
return texcolor * color;
|
||||
}
|
||||
]],
|
||||
[[
|
||||
uniform mat4 transform;
|
||||
vec4 position(mat4 transform_projection, vec4 vertex_position) {
|
||||
return transform * TransformMatrix * (vertex_position - vec4(vec2(640.0, 480.0) / 2.0, 0.0, 0.0));
|
||||
}
|
||||
]]
|
||||
),
|
||||
width = -1,
|
||||
height = -1,
|
||||
depth_3d = -1
|
||||
}
|
||||
local shader_discard = {
|
||||
shader = love.graphics.newShader(
|
||||
[[
|
||||
uniform vec4 rect;
|
||||
vec4 effect(vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords) {
|
||||
if (screen_coords.x < rect.x || screen_coords.x > rect.y || screen_coords.y < rect.z || screen_coords.y > rect.w) discard;
|
||||
vec4 texcolor = Texel(tex, texture_coords);
|
||||
return texcolor * color;
|
||||
}
|
||||
]],
|
||||
[[
|
||||
uniform mat4 transform;
|
||||
vec4 position(mat4 transform_projection, vec4 vertex_position) {
|
||||
return transform * TransformMatrix * (vertex_position - vec4(vec2(640.0, 480.0) / 2.0, 0.0, 0.0));
|
||||
}
|
||||
]]
|
||||
),
|
||||
width = -1,
|
||||
height = -1,
|
||||
depth_3d = -1
|
||||
}
|
||||
|
||||
local function set_shader_transform(shader, width, height)
|
||||
local depth = (480 / 2) / math.tan(math.rad(config.depth_3d) / 2)
|
||||
local look_at = mat4():look_at(vec3(0, 0, depth), vec3(0, 0, 0), vec3(0, 1, 0))
|
||||
local perspective = mat4.from_perspective(config.depth_3d, width / height, -0.5, 0.5)
|
||||
local tall = height / 480 > width / 640
|
||||
if tall then
|
||||
local scale_factor = (480 * width) / (640 * height)
|
||||
shader:send("transform", mat4.scale(mat4.new(), perspective * look_at, vec3(scale_factor)))
|
||||
else
|
||||
shader:send("transform", perspective * look_at)
|
||||
end
|
||||
end
|
||||
|
||||
return function(R, G, B, A, image, x, y, left, right, top, bottom, big)
|
||||
local scale = big and 2 or 1
|
||||
if config.depth_3d > 0 then
|
||||
love.graphics.setCanvas{GLOBAL_CANVAS, depth = true}
|
||||
love.graphics.push()
|
||||
love.graphics.origin()
|
||||
love.graphics.setDepthMode("lequal", true)
|
||||
local shader
|
||||
local current_width = love.graphics.getWidth()
|
||||
local current_height = love.graphics.getHeight()
|
||||
if left and right and top and bottom then
|
||||
love.graphics.setShader(shader_discard.shader)
|
||||
local scale_factor = math.min(current_width / 640, current_height / 480)
|
||||
local rect_left = (current_width - scale_factor * 640) / 2 + left * scale_factor
|
||||
local rect_right = (current_width - scale_factor * 640) / 2 + right * scale_factor
|
||||
local rect_top = (current_height - scale_factor * 480) / 2 + top * scale_factor
|
||||
local rect_bottom = (current_height - scale_factor * 480) / 2 + bottom * scale_factor
|
||||
shader_discard.shader:send("rect", {rect_left, rect_right, rect_top, rect_bottom})
|
||||
shader = shader_discard
|
||||
else
|
||||
love.graphics.setShader(shader_no_discard.shader)
|
||||
shader = shader_no_discard
|
||||
end
|
||||
if current_width ~= shader.width or current_height ~= shader.height or config.depth_3d ~= shader.depth_3d then
|
||||
set_shader_transform(shader.shader, current_width, current_height)
|
||||
shader.width = current_width
|
||||
shader.height = current_height
|
||||
shader.depth_3d = config.depth_3d
|
||||
end
|
||||
|
||||
if A ~= 1 or y > 480 / 2 then
|
||||
love.graphics.setColor(R, G, B, A)
|
||||
cube.top[scale]:setTexture(image)
|
||||
love.graphics.draw(cube.top[scale], x, y)
|
||||
end
|
||||
|
||||
love.graphics.setColor(R / 2, G / 2, B / 2, A)
|
||||
if A ~= 1 or y < 480 / 2 then
|
||||
cube.bottom[scale]:setTexture(image)
|
||||
love.graphics.draw(cube.bottom[scale], x, y)
|
||||
end
|
||||
if A ~= 1 or x > 640 / 2 then
|
||||
cube.left[scale]:setTexture(image)
|
||||
love.graphics.draw(cube.left[scale], x, y)
|
||||
end
|
||||
if A ~= 1 or x < 640 / 2 then
|
||||
cube.right[scale]:setTexture(image)
|
||||
love.graphics.draw(cube.right[scale], x, y)
|
||||
end
|
||||
|
||||
love.graphics.setColor(R, G, B, A)
|
||||
cube.front[scale]:setTexture(image)
|
||||
love.graphics.draw(cube.front[scale], x, y)
|
||||
|
||||
love.graphics.setShader()
|
||||
love.graphics.setDepthMode()
|
||||
love.graphics.pop()
|
||||
love.graphics.setCanvas(GLOBAL_CANVAS)
|
||||
else
|
||||
love.graphics.setColor(R, G, B, A)
|
||||
love.graphics.draw(image, x, y, 0, scale, scale)
|
||||
end
|
||||
end
|
||||
@@ -2,6 +2,7 @@ local Object = require 'libs.classic'
|
||||
|
||||
local Grid = Object:extend()
|
||||
|
||||
local drawBlock = require 'tetris.components.draw_block'
|
||||
local empty = { skin = "", colour = "" }
|
||||
local oob = { skin = "", colour = "" }
|
||||
local block = { skin = "2tie", colour = "A" }
|
||||
@@ -405,23 +406,47 @@ function Grid:update()
|
||||
end
|
||||
|
||||
function Grid:draw()
|
||||
is_3d = is_3d == nil and false or is_3d
|
||||
for y = 5, self.height do
|
||||
for x = 1, self.width do
|
||||
if blocks[self.grid[y][x].skin] and
|
||||
blocks[self.grid[y][x].skin][self.grid[y][x].colour] then
|
||||
if self.grid_age[y][x] < 2 then
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
love.graphics.draw(blocks[self.grid[y][x].skin]["F"], 48+x*16, y*16)
|
||||
drawBlock(1, 1, 1, 1, blocks[self.grid[y][x].skin]["F"], 48+x*16, y*16,
|
||||
48, 48+(self.width+1)*16,
|
||||
5*16, (self.height+1)*16
|
||||
)
|
||||
else
|
||||
local R, G, B, A
|
||||
if self.grid[y][x].colour == "X" then
|
||||
love.graphics.setColor(0, 0, 0, 0)
|
||||
R = 0
|
||||
G = 0
|
||||
B = 0
|
||||
A = 0
|
||||
elseif self.grid[y][x].skin == "bone" then
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
r = 1
|
||||
G = 1
|
||||
B = 1
|
||||
A = 1
|
||||
else
|
||||
love.graphics.setColor(0.5, 0.5, 0.5, 1)
|
||||
R = 0.5
|
||||
G = 0.5
|
||||
B = 0.5
|
||||
A = 1
|
||||
end
|
||||
love.graphics.draw(blocks[self.grid[y][x].skin][self.grid[y][x].colour], 48+x*16, y*16)
|
||||
drawBlock(R, G, B, A, blocks[self.grid[y][x].skin][self.grid[y][x].colour], 48+x*16, y*16,
|
||||
48, 48+(self.width+1)*16,
|
||||
5*16, (self.height+1)*16
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- everything that needs to be drawn over the blocks *must* be drawn after all blocks have been drawn, due to how 3D works
|
||||
for y = 5, self.height do
|
||||
for x = 1, self.width do
|
||||
if blocks[self.grid[y][x].skin] and
|
||||
blocks[self.grid[y][x].skin][self.grid[y][x].colour] then
|
||||
if self.grid[y][x].skin ~= "bone" and self.grid[y][x].colour ~= "X" then
|
||||
love.graphics.setColor(0.8, 0.8, 0.8, 1)
|
||||
love.graphics.setLineWidth(1)
|
||||
@@ -468,9 +493,10 @@ function Grid:drawOutline()
|
||||
end
|
||||
end
|
||||
|
||||
function Grid:drawInvisible(opacity_function, garbage_opacity_function, lock_flash, brightness)
|
||||
function Grid:drawInvisible(opacity_function, garbage_opacity_function, lock_flash, brightness, is_3d)
|
||||
lock_flash = lock_flash == nil and true or lock_flash
|
||||
brightness = brightness == nil and 0.5 or brightness
|
||||
is_3d = is_3d == nil and false or is_3d
|
||||
for y = 5, self.height do
|
||||
for x = 1, self.width do
|
||||
if self.grid[y][x] ~= empty then
|
||||
@@ -481,8 +507,17 @@ function Grid:drawInvisible(opacity_function, garbage_opacity_function, lock_fla
|
||||
else
|
||||
opacity = opacity_function(self.grid_age[y][x])
|
||||
end
|
||||
love.graphics.setColor(brightness, brightness, brightness, opacity)
|
||||
love.graphics.draw(blocks[self.grid[y][x].skin][self.grid[y][x].colour], 48+x*16, y*16)
|
||||
drawBlock(brightness, brightness, brightness, opacity, blocks[self.grid[y][x].skin][self.grid[y][x].colour], 48+x*16, y*16,
|
||||
48, 48+(self.width+1)*16,
|
||||
5*16, (self.height+1)*16
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- everything that needs to be drawn over the blocks *must* be drawn after all blocks have been drawn, due to how 3D works
|
||||
for y = 5, self.height do
|
||||
for x = 1, self.width do
|
||||
if self.grid[y][x] ~= empty then
|
||||
if lock_flash then
|
||||
if opacity > 0 and self.grid[y][x].colour ~= "X" then
|
||||
love.graphics.setColor(0.64, 0.64, 0.64)
|
||||
@@ -507,29 +542,40 @@ function Grid:drawInvisible(opacity_function, garbage_opacity_function, lock_fla
|
||||
end
|
||||
end
|
||||
|
||||
function Grid:drawCustom(colour_function, gamestate)
|
||||
--[[
|
||||
colour_function: (game, block, x, y, age) -> (R, G, B, A, outlineA)
|
||||
When called, calls the supplied function on every block passing the block itself as argument
|
||||
as well as coordinates and the grid_age value of the same cell.
|
||||
Should return a RGBA colour for the block, as well as the opacity of the stack outline (0 for no outline).
|
||||
|
||||
gamestate: the gamemode instance itself to pass in colour_function
|
||||
]]
|
||||
function Grid:drawCustom(colour_function, gamestate, is_3d)
|
||||
--[[
|
||||
colour_function: (game, block, x, y, age) -> (R, G, B, A, outlineA)
|
||||
When called, calls the supplied function on every block passing the block itself as argument
|
||||
as well as coordinates and the grid_age value of the same cell.
|
||||
Should return a RGBA colour for the block, as well as the opacity of the stack outline (0 for no outline).
|
||||
|
||||
gamestate: the gamemode instance itself to pass in colour_function
|
||||
]]
|
||||
is_3d = is_3d == nil and false or is_3d
|
||||
for y = 5, self.height do
|
||||
for x = 1, self.width do
|
||||
local block = self.grid[y][x]
|
||||
local block = self.grid[y][x]
|
||||
if block ~= empty then
|
||||
local R, G, B, A, outline = colour_function(gamestate, block, x, y, self.grid_age[y][x])
|
||||
local R, G, B, A, outline = colour_function(gamestate, block, x, y, self.grid_age[y][x])
|
||||
if self.grid[y][x].colour == "X" then
|
||||
A = 0
|
||||
end
|
||||
love.graphics.setColor(R, G, B, A)
|
||||
love.graphics.draw(blocks[self.grid[y][x].skin][self.grid[y][x].colour], 48+x*16, y*16)
|
||||
if outline > 0 and self.grid[y][x].colour ~= "X" then
|
||||
love.graphics.setColor(0.64, 0.64, 0.64, outline)
|
||||
love.graphics.setLineWidth(1)
|
||||
if y > 5 and self.grid[y-1][x] == empty or self.grid[y-1][x].colour == "X" then
|
||||
drawBlock(R, G, B, A, blocks[self.grid[y][x].skin][self.grid[y][x].colour], 48+x*16, y*16,
|
||||
48, 48+(self.width+1)*16,
|
||||
5*16, (self.height+1)*16
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- everything that needs to be drawn over the blocks *must* be drawn after all blocks have been drawn, due to how 3D works
|
||||
for y = 5, self.height do
|
||||
for x = 1, self.width do
|
||||
local block = self.grid[y][x]
|
||||
if block ~= empty then
|
||||
if outline > 0 and self.grid[y][x].colour ~= "X" then
|
||||
love.graphics.setColor(0.64, 0.64, 0.64, outline)
|
||||
love.graphics.setLineWidth(1)
|
||||
if y > 5 and self.grid[y-1][x] == empty or self.grid[y-1][x].colour == "X" then
|
||||
love.graphics.line(48.0+x*16, -0.5+y*16, 64.0+x*16, -0.5+y*16)
|
||||
end
|
||||
if y < self.height and self.grid[y+1][x] == empty or
|
||||
@@ -542,7 +588,7 @@ function Grid:drawCustom(colour_function, gamestate)
|
||||
if x < self.width and self.grid[y][x+1] == empty then
|
||||
love.graphics.line(64.5+x*16, -0.0+y*16, 64.5+x*16, 16.0+y*16)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,6 +2,8 @@ local Object = require 'libs.classic'
|
||||
|
||||
local Piece = Object:extend()
|
||||
|
||||
local drawBlock = require 'tetris.components.draw_block'
|
||||
|
||||
function Piece:new(shape, rotation, position, block_offsets, gravity, lock_delay, skin, colour, big)
|
||||
self.shape = shape
|
||||
self.rotation = rotation
|
||||
@@ -157,7 +159,6 @@ end
|
||||
function Piece:draw(opacity, brightness, grid, partial_das)
|
||||
if opacity == nil then opacity = 1 end
|
||||
if brightness == nil then brightness = 1 end
|
||||
love.graphics.setColor(brightness, brightness, brightness, opacity)
|
||||
local offsets = self:getBlockOffsets()
|
||||
local gravity_offset = 0
|
||||
if config.gamesettings.smooth_movement == 1 and
|
||||
@@ -168,16 +169,24 @@ function Piece:draw(opacity, brightness, grid, partial_das)
|
||||
for index, offset in pairs(offsets) do
|
||||
local x = self.position.x + offset.x
|
||||
local y = self.position.y + offset.y
|
||||
if self.big then
|
||||
love.graphics.draw(
|
||||
local scale = self.big and 2 or 1
|
||||
if grid ~= nil then
|
||||
drawBlock(
|
||||
brightness, brightness, brightness, opacity,
|
||||
blocks[self.skin][self.colour],
|
||||
64+x*32+partial_das*2, 16+y*32+gravity_offset*2,
|
||||
0, 2, 2
|
||||
64 + (x*16+partial_das)*scale, 16 + (y*16+gravity_offset)*scale,
|
||||
48, 48+(grid.width+1)*16,
|
||||
0, (grid.height+1)*16,
|
||||
self.big
|
||||
)
|
||||
else
|
||||
love.graphics.draw(
|
||||
drawBlock(
|
||||
brightness, brightness, brightness, opacity,
|
||||
blocks[self.skin][self.colour],
|
||||
64+x*16+partial_das, 16+y*16+gravity_offset
|
||||
64 + (x*16+partial_das)*scale, 16 + (y*16+gravity_offset)*scale,
|
||||
false, false,
|
||||
false, false,
|
||||
self.big
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,6 +5,7 @@ local playedReadySE = false
|
||||
local playedGoSE = false
|
||||
|
||||
local Grid = require 'tetris.components.grid'
|
||||
local drawBlock = require 'tetris.components.draw_block'
|
||||
local Randomizer = require 'tetris.randomizers.randomizer'
|
||||
local BagRandomizer = require 'tetris.randomizers.bag'
|
||||
local binser = require 'libs.binser'
|
||||
@@ -787,13 +788,12 @@ function GameMode:drawLineClearAnimation()
|
||||
for y, row in pairs(self.cleared_block_table) do
|
||||
for x, block in pairs(row) do
|
||||
local animation_table = self:animation(x, y, block.skin, block.colour)
|
||||
love.graphics.setColor(
|
||||
animation_table[1], animation_table[2],
|
||||
animation_table[3], animation_table[4]
|
||||
)
|
||||
love.graphics.draw(
|
||||
drawBlock(
|
||||
animation_table[1], animation_table[2], animation_table[3], animation_table[4],
|
||||
blocks[animation_table[5]][animation_table[6]],
|
||||
animation_table[7], animation_table[8]
|
||||
animation_table[7], animation_table[8],
|
||||
48, 48+(self.grid.width+1)*16,
|
||||
5*16, (self.grid.height+1)*16
|
||||
)
|
||||
end
|
||||
end
|
||||
@@ -820,7 +820,7 @@ function GameMode:drawGhostPiece(ruleset)
|
||||
local ghost_piece = self.piece:withOffset({x=0, y=0})
|
||||
ghost_piece.ghost = true
|
||||
ghost_piece:dropToBottom(self.grid)
|
||||
ghost_piece:draw(0.5)
|
||||
ghost_piece:draw(0.5, 1, self.grid)
|
||||
end
|
||||
|
||||
function GameMode:drawNextQueue(ruleset)
|
||||
@@ -837,7 +837,11 @@ function GameMode:drawNextQueue(ruleset)
|
||||
for index, offset in pairs(offsets) do
|
||||
local x = offset.x + ruleset:getDrawOffset(piece, rotation).x + ruleset.spawn_positions[piece].x
|
||||
local y = offset.y + ruleset:getDrawOffset(piece, rotation).y + 4.7
|
||||
love.graphics.draw(blocks[skin][colourscheme[piece]], pos_x+x*16, pos_y+y*16)
|
||||
drawBlock(
|
||||
1, 1, 1, 1,
|
||||
blocks[skin][colourscheme[piece]],
|
||||
pos_x+x*16, pos_y+y*16
|
||||
)
|
||||
end
|
||||
end
|
||||
for i = 1, self.next_queue_length do
|
||||
|
||||
Reference in New Issue
Block a user