Protogestling Mockup
This is the ProtoGestling test video. It speaks a pseudo-language called "blipsqueak", and has its face constructed using the protogestling drawing primitive.
This is the script that generates the video. It's prototype code so things are... quite messy. But, it does enough to get a sense of what a gestling could feel like, what's currently possible, and what can potentially be improved.
<<protogestling_mockup.lua>>=
blipsqueak = require("blipsqueak/blipsqueak")
val = valutil
-- setup audio
lil("blkset 49")
-- lil("valnew mouth")
-- lil("grab mouth")
-- lil("biscale [sine 0.2 1] 0 1")
-- lil("tog [metro 2]")
-- lil("valset2 zz zz")
-- lil("drop")
local bs = blipsqueak
comp = bs.components(bs.load_components())
bs.load_data(comp)
phrase = {"HELLO", "IAM", "PLEASED", "WELCOME"}
-- I updated the morpheme duration scaler, so this ended
-- up breaking (the scaling values were too high).
-- I don't think it really worked to begin with
-- pitchseq = "h1/ k2~ h1/ d h i2~ h4_"
-- temposeq = "d1/ f d4 c"
pitchseq = "h1_"
temposeq = "d1/ c"
bs.speak(comp, phrase, pitchseq, temposeq)
lil("mul zz [dblin -6]")
lil([[
dup; dup;
bigverb zz zz 0.8 8000
drop;
dcblocker zz
mul zz [dblin -20];
add zz zz
]])
os.execute("mkdir -p tmp res")
lil("wavout zz tmp/protogestling.wav")
lil("gfxnew gfx 200 320")
lil("grab gfx")
lil("gfxopen tmp/protogestling.h264")
lil([[
grab gfx
gfxclrset 1 0.0 0.0 0.0
gfxclrset 0 1.0 1.0 1.0
]])
lil([[
bpnew bp 200 320
# face
bpset [grab bp] 0 0 0 200 260
# text
bpset [grab bp] 1 0 260 200 60
# main
bpset [grab bp] 2 0 0 200 320
# bpoutline [bpget [grab bp] 0] 1
# bpoutline [bpget [grab bp] 1] 1
bpline [bpget [grab bp] 1] 0 0 200 0 1
bproundrect [bpget [grab bp] 2] 0 0 200 320 16 1
]])
lil("bpget [grab bp] 0")
face_reg = pop()
lil("bpfnt_default font")
lil("bpget [grab bp] 1")
msgbox_reg = pop()
lil("grab font")
font = pop()
lines = {
"Why Hello there!",
"I am a Proto-Gestling.",
"Pleased to meet you.",
"Welcome to Cauldronia!",
}
total_length = 0
for _,ln in pairs(lines) do
total_length = total_length + #ln
end
function protoface(reg, shape)
mouth = shape[1]
left_eye = shape[2]
right_eye = shape[3]
protogestling.face(reg,
mouth[1], mouth[2],
left_eye[1], left_eye[2],
right_eye[1], right_eye[2])
end
wide_mouth = {0.9, 0.3}
thin_mouth = {0.9, 0.1}
small_mouth = {0.1, 0.1}
big_eye = {0.3, 0.9}
round_eye = {0.3, 0.3}
thin_eye = {0.1, 0.9}
mouth_shapes = {
-- 0
{wide_mouth, big_eye, big_eye},
-- 1
{thin_mouth, round_eye, round_eye},
-- 2
{small_mouth, big_eye, round_eye},
-- 3
{wide_mouth, round_eye, big_eye},
-- 4
{thin_mouth, round_eye, big_eye},
-- 5
{small_mouth, thin_eye, thin_eye},
-- 6
{wide_mouth, round_eye, big_eye},
-- 7
{thin_mouth, round_eye, thin_eye},
-- 8
{small_mouth, thin_eye, round_eye},
}
test_shape = 0
prev_face = nil
function lerp(curval, target)
local speed = 0.2
curval = curval + ((target - curval) * speed)
return curval
end
function lerp_face(curface, target)
mouthlerp = {
lerp(curface[1][1], target[1][1]),
lerp(curface[1][2], target[1][2]),
}
leyelerp = {
lerp(curface[2][1], target[2][1]),
lerp(curface[2][2], target[2][2]),
}
reyelerp = {
lerp(curface[3][1], target[3][1]),
lerp(curface[3][2], target[3][2]),
}
return {
mouthlerp, leyelerp, reyelerp
}
end
local curface = nil
function draw_face()
local shape = math.floor(val.get("mouth")) + 1
-- local shape = test_shape + 1
lil("bpfill [bpget [grab bp] 0] 0")
if (curface == nil) then
curface = mouth_shapes[shape]
end
curface = lerp_face(curface, mouth_shapes[shape])
protoface(face_reg, curface)
-- protogestling.face(face_reg, 0.9, 0.3, 0.3, 0.9, 0.3, 0.9)
-- protogestling.face(face_reg, 0.9, 0.3, 0.3, 0.9, 0.3, 0.9)
end
function draw_textblock(lines, textpos)
for pos, ln in pairs(lines) do
local lnsz = #ln
if textpos < lnsz then
lnsz = textpos
end
protogestling.textline(msgbox_reg, font, 10, 10 + 10*(pos -1), ln, 1, 1, lnsz)
textpos = textpos - lnsz
if textpos <= 0 then
return pos, lnsz
end
end
end
function get_next_char(lines, lpos, cpos)
cpos = cpos + 1
if cpos > #lines[lpos] then
lpos = lpos + 1
cpos = 1
end
if lpos > #lines then
return nil
end
return string.char(string.byte(lines[lpos], cpos))
end
speed = 5
pause = 30
timer = speed
txtpos = 0
nframes = 60 * 10
fpos = 0
for n=1,nframes do
if fpos == 0 then
print(n)
fpos = 60
test_shape = test_shape + 1
test_shape = test_shape % 9
end
fpos = fpos - 1
lil("compute 15")
draw_face()
local lpos, cpos = draw_textblock(lines, txtpos)
lil("bproundrect [bpget [grab bp] 2] 0 0 200 320 16 1")
lil("grab gfx")
lil("gfxfill 0")
lil("bptr [grab bp] 0 0 200 320 0 0 1")
lil("grab gfx")
lil("gfxtransfer; dup")
lil("gfxappend")
timer = timer - 1
if timer <= 0 then
local nc = get_next_char(lines, lpos, cpos)
if nc == '!' or nc == '.' then
timer = pause
else
timer = speed
end
txtpos = txtpos + 1
if txtpos > total_length then
txtpos = total_length
end
end
end
lil("gfxclose")
lil("gfxmp4 tmp/protogestling.h264 tmp/protogestling.mp4")
os.execute("ffmpeg -y -i tmp/protogestling.mp4 -i tmp/protogestling.wav -pix_fmt yuv420p -acodec aac res/protogestling.mp4")