Skip to content

Instantly share code, notes, and snippets.

@GlueBalloon
Last active September 11, 2015 16:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save GlueBalloon/9d81558f78f984ca30b1 to your computer and use it in GitHub Desktop.
Save GlueBalloon/9d81558f78f984ca30b1 to your computer and use it in GitHub Desktop.
YojimboDrawWithDice
--# Main
-- MakeDice
function setup()
colorPicker = SwipeColorPicker()
colorPicker.position.x, colorPicker.position.y = 50, 50
makeDice = MakeDice()
usingMiniBufferAndOverlay = false
texture = makeDice.mesh.texture
colorCoordinates = {}
if usingMiniBufferAndOverlay then
overlayImage = image(WIDTH/4, HEIGHT/4)
else
overlayImage = image(WIDTH,HEIGHT)
end
setUpBufferDisplay()
profiler.init()
local newX = 400
tween( 90, makeDice.rotate, { x = newX }, { easing = tween.easing.linear, loop = tween.loop.pingpong } )
textMode(CORNER)
planeShader = shader(PlaneShader.v, PlaneShader.f)
end
function setUpBufferDisplay()
if usingMiniBufferAndOverlay then
bufferImage = image(WIDTH/4, HEIGHT/4)
else
bufferImage = image(WIDTH, HEIGHT)
end
local bufferFract = 1 / 6
cameoSize = vec2(WIDTH * bufferFract, HEIGHT * bufferFract)
camoPos = vec2((cameoSize.x/2)+20, (cameoSize.y/2)+20)
setContext(bufferImage) --fill image with yellow for visibility
strokeWidth(0)
fill(220, 210, 122, 255)
rect(0,0,WIDTH,HEIGHT)
setContext()
end
function draw()
-- backingMode(STANDARD)
background(69, 119, 104, 255)
drawPlane()
draw2D()
profiler.draw()
end
function drawPlane()
pushMatrix()
-- makeDice:setupPerspective()
if touching then
toggleShader(true)
drawClipToBufferPosition(touching)
toggleShader(false)
-- touching = nil
end
-- pushMatrix()
makeDice:draw()
popMatrix()
end
function draw2D()
ortho()
viewMatrix(matrix())
-- if #colorCoordinates > 0 then
if touching then
drawTouchesToTexture()
touching = nil
end
if usingMiniBufferAndOverlay then
sprite(overlayImage, WIDTH/2, HEIGHT/2, WIDTH, HEIGHT)
sprite(bufferImage, camoPos.x, camoPos.y, cameoSize.x, cameoSize.y)
end
colorPicker:draw()
end
function drawTouchesToTexture()
local textureX, textureY, baseX, baseY, marker, intCoord, fX, fY
textureX, textureY = 0, 0
-- for i in ipairs(colorCoordinates) do
-- coord = colorCoordinates[i] * 0.25
if usingMiniBufferAndOverlay then
coord = touching * 0.25
else
coord = touching
end
intCoord = vec2(math.floor(coord.x), math.floor(coord.y))
baseX, baseY, marker = bufferImage:get(intCoord.x, intCoord.y)
if marker == 1 then
fX, fY = baseX / 255, baseY / 255
textureX = texture.width * fX
textureY = texture.height * fY
lastTexX = lastTexX or textureX
lastTexY = lastTexY or textureY
setContext(texture)
stroke(colorPicker.color)
strokeWidth(2)
line(textureX, textureY, lastTexX, lastTexY)
-- ellipse(textureX, textureY, 25)
setContext()
lastTexX, lastTexY = textureX, textureY
end
-- end
-- text("x: "..textureX..", y: "..math.floor(textureY, 10, 10))
-- end
-- colorCoordinates = {}
end
function touched(touch)
if usingMiniBufferAndOverlay then
setContext(overlayImage)
fill(227, 255, 0, 255)
ellipse(touch.x/4, touch.y/4, 3)
setContext()
end
touching = vec2(touch.x, touch.y)
if touch.state == ENDED then
touching, lastTexX, lastTexY = nil,nil, nil
end
--[[
if touch.state == MOVING then
touching = vec2(touch.x, touch.y)
-- table.insert(colorCoordinates, vec2(touch.x, touch.y))
else
toggleShader(false)
end
]]
colorPicker:touched(touch)
end
function drawClipToBufferPosition(touch)
setContext(bufferImage)
pushMatrix()
if usingMiniBufferAndOverlay then
clip((touch.x*0.25) - 10, (touch.y*0.25) - 10, 20, 20)
else
clip(touch.x - 5, touch.y - 5, 10, 10)
end
makeDice:draw()
clip()
popMatrix()
setContext()
end
function toggleShader(onOrOff)
if onOrOff == true then
makeDice.mesh.shader = planeShader
else
makeDice.mesh.shader = nil
end
end
profiler={}
function profiler.init(silent)
profiler.del=0
profiler.c=0
profiler.fps=0
profiler.mem=0
if not silent then
parameter.watch("profiler.fps")
parameter.watch("profiler.mem")
end
end
function profiler.draw()
profiler.del = profiler.del + DeltaTime
profiler.c = profiler.c + 1
if profiler.c==10 then
profiler.fps=profiler.c/profiler.del
profiler.del=0
profiler.c=0
profiler.mem=collectgarbage("count", 2)
end
end
--# MakeDice
MakeDice = class()
function MakeDice:init()
self:createDiceMesh()
end
function MakeDice:draw()
self:setupPerspective()
self.mesh:draw()
end
function MakeDice:createDiceMesh()
self.mesh=Mesh7().blk.mesh
self.centre=vec3(0,0,0)
self.rotate=vec3(45,0,20)
self.size=vec2(6,6,0)
strokeWidth(10)
stroke(255, 0, 0, 255)
self.img=self.mesh.texture
self.shaderImg=image(self.img.width, self.img.height)
end
function MakeDice:setupPerspective()
perspective()
camera(0,0,900,0,0,-1)
scale(self.size.x, self.size.y,0)
translate(self.centre.x, self.centre.y, self.centre.z)
rotate(self.rotate.x,1,0,0)
rotate(self.rotate.y,0,1,0)
rotate(self.rotate.z,0,0,1)
end
PlaneShader = {
v = [[
uniform mat4 modelViewProjection;
attribute vec4 position;
attribute vec2 texCoord;
varying highp vec2 vTexCoord;
void main()
{
vTexCoord = texCoord;
gl_Position = modelViewProjection * position;
}
]],
f = [[
precision highp float;
varying highp vec2 vTexCoord;
void main()
{
lowp float marker = 1.0 /255.0;
gl_FragColor = vec4(vTexCoord.x,vTexCoord.y,marker,1.0);
}
]]}
--# Mesh7_aka_IgnatzDice
--Mesh7
--[[
In this demo, I've added a texture from the internet to make the dice more interesting
I've also added a fake highlight to the dice spots to give them some depth
Changes are marked CHANGED
No changes to Block, so I just used Block3 from the previous demo
--]]
Mesh7 = class()
function Mesh7:init(x)
self.FieldOfView=45
self.CamHeight=300
self.Angle=0
local sideSize=50
local imgData={0,0,1,1/6, 0,1/6,1,2/6, 0,2/6,1,3/6, 0,3/6,1,4/6, 0,4/6,1,5/6, 0,5/6,1,1}
local largerImage = image(WIDTH/2,HEIGHT/2)
setContext(largerImage)
sprite("Cargo Bot:Opening Background", WIDTH/4, HEIGHT/4, WIDTH/2, HEIGHT/2)
setContext()
local img2 = largerImage
self.blk=Block3(sideSize,sideSize,sideSize,img2,imgData)
end
function Mesh7:draw()
-- First arg is FOV, second is aspect
perspective(self.FieldOfView, WIDTH/HEIGHT)
-- Position the camera up and back, look at origin
camera(0,self.CamHeight,-300, 0,0,0, 0,1,0)
pushMatrix()
rotate(self.Angle,0,1,0)
self.blk:draw()
popMatrix()
end
function Mesh7:touched(touch)
local xx,yy=math.floor(touch.x*3/WIDTH),math.floor(touch.y*3/HEIGHT)
if xx==0 then self.Angle=self.Angle-15 elseif xx==2 then self.Angle=self.Angle+15 end
if yy==0 then self.CamHeight=self.CamHeight-50 elseif yy==2 then self.CamHeight=self.CamHeight+50 end
end
--Block3
--[[
This class creates a rectangular 3D block with 12 triangles covered with a single texture
This is about as simple as it gets, and there is still a lot of code
We tell the class how big we want the block to be, ie width, depth and height
We also give it either
(a) a texture based on an image, so it is visible
(b) a table of colors, one color per side
In the case of (a), we don't always want to use the whole image, so we provide an optional array (parameter r below) that lets the user specify the start and end x,y position
eg if you only want to use the part of the image from x=0.2 to .6, and y=0.1 to .9, then you
pass in an array {0.2,0.1,0.6,0.9} ie starting x,y position, then ending x,y position
If you omit this array then the range 0,1 will be used
NB this has been extended to you can specify the part of the image to use for each face separately.In this case, you need to specify four numbers per face, or 24 in total
--]]
Block3 = class() --taken from 3D lab project
--t=either string name of image, or an array of 6 colors, one per block face
function Block3:init(w,h,d,t,r) --width,height,depth,texture/colors, (optional) texture range (see above)
self.width=w
self.height=h
self.depth=d
if type(t)=="string" or type(t)=="userdata" then --CHANGED to trap cases where we provide an actual image
self.type="Image" --CHANGED
self.tex=t --string name of an image in the library, or the image itself
--if no limits specified on which part of image to draw, set to 0,1
if r~=nil then self.texR=r else self.texR={0,0,1,1} end
else --we are given a table of colors, one per face
self.type="Colors" --CHANGED
self.colrs=t
end
self.mesh=self:createBlock()
end
function Block3:createBlock()
-- all the unique vertices that make up a block
--There are only 8 corners in a cube - we define them as vertices
--all measurements are taken from the centre of the block
--so bottom left front has x of -1/2 width, y of -1/2 height, and z of 1/2 depth
local w,h,d=self.width,self.height,self.depth
local v = {
vec3(-0.5*w, -0.5*h, 0.5*d), -- Left bottom front
vec3( 0.5*w, -0.5*h, 0.5*d), -- Right bottom front
vec3( 0.5*w, 0.5*h, 0.5*d), -- Right top front
vec3(-0.5*w, 0.5*h, 0.5*d), -- Left top front
vec3(-0.5*w, -0.5*h, -0.5*d), -- Left bottom back
vec3( 0.5*w, -0.5*h, -0.5*d), -- Right bottom back
vec3( 0.5*w, 0.5*h, -0.5*d), -- Right top back
vec3(-0.5*w, 0.5*h, -0.5*d), -- Left top back
}
-- now construct a block out of the vertices above
--there are 6 sides, each made up of 2 triangles, each with 3 vertices
--so we need to assign 36 vertices in total
--the 8 vectors are assigned to the 8 corners as follows
--1,2,3,4 anticlockwise round front starting bottom left
--5,6,7,8 clockwise round back starting bottom right (assuming you are looking at the back)
--the first three vectors below use vectors 1,2 and 3. If you look above, you'll
--see those are for left and right of bottom front, plus right top of front
--so this is the right hand triangle for the front side
local cubeverts = {
-- Front, Right, Back, Left, Top, Bottom
v[1], v[2], v[3], v[1], v[3], v[4],
v[2], v[6], v[7], v[2], v[7], v[3],
v[6], v[5], v[8], v[6], v[8], v[7],
v[5], v[1], v[4], v[5], v[4], v[8],
v[4], v[3], v[7], v[4], v[7], v[8],
v[5], v[6], v[2], v[5], v[2], v[1],
}
-- add texture or colors
if self.type=="Image" then --texture --CHANGED
if #self.texR==4 then
--create vectors to be assigned to four corners of each face
local BL=vec2(self.texR[1],self.texR[2]) --bottom left
local BR=vec2(self.texR[3],self.texR[2]) --bottom right
local TR=vec2(self.texR[3],self.texR[4]) --top right
local TL=vec2(self.texR[1],self.texR[4]) --top left
-- apply the texture coordinates to each triangle
--we need to add them to each of the vertexes in the same order as above
--that means on each face we need to add them in the order BL, BR, TR, BL, TR, TL
self.texCoords = {}
for i=1,6 do
table.insert(self.texCoords,BL)
table.insert(self.texCoords,BR)
table.insert(self.texCoords,TR)
table.insert(self.texCoords,BL)
table.insert(self.texCoords,TR)
table.insert(self.texCoords,TL)
end
else --user has specified image fractions for each face
self.texCoords = {}
local u=0
for i=1,6 do
local BL=vec2(self.texR[u+1],self.texR[u+2]) --bottom left
local BR=vec2(self.texR[u+3],self.texR[u+2]) --bottom right
local TR=vec2(self.texR[u+3],self.texR[u+4]) --top right
local TL=vec2(self.texR[u+1],self.texR[u+4]) --top left
u = u + 4
table.insert(self.texCoords,BL)
table.insert(self.texCoords,BR)
table.insert(self.texCoords,TR)
table.insert(self.texCoords,BL)
table.insert(self.texCoords,TR)
table.insert(self.texCoords,TL)
end
end
else --colors, one per face
self.texColrs={}
for i=1,6 do
for j=1,6 do
table.insert(self.texColrs,self.colrs[i])
end
end
end
--put it all together
local ms = mesh()
ms.vertices = cubeverts
ms.texture = self.tex
if self.texCoords~=nil then ms.texCoords = self.texCoords end
ms:setColors(255,255,255,255)
if self.texColrs~=nil then ms.colors=self.texColrs end
return ms
end
function Block3:draw()
self.mesh:draw()
end
--# SwipeColorPicker
SwipeColorPicker = class()
function SwipeColorPicker:init(x)
self.hsv = vec4(0.5,1.0,1.0,1.0)
self.color = self:updateRGB()
self.size = 80
self.position = vec2(200,200)
self.active = false
end
function SwipeColorPicker:swipeHorizontal(amount)
amount = amount / WIDTH
self:hsvShift(amount, 0)
end
function SwipeColorPicker:hsvShift(h,v)
self.hsv.x = self.hsv.x + h
if self.hsv.y < 1 then
self.hsv.y = self.hsv.y - v
if self.hsv.y < 0 then
self.hsv.y = 0
end
if self.hsv.y > 1 then
self.hsv.z = self.hsv.z - math.fmod(self.hsv.y, 1)
self.hsv.y = 1
end
else
self.hsv.z = self.hsv.z + v
if self.hsv.z > 1 then
self.hsv.y = self.hsv.y - math.fmod(self.hsv.z, 1)
self.hsv.z = 1
end
end
self:updateRGB()
end
function SwipeColorPicker:swipeVertical(amount)
amount = amount / HEIGHT * 3
self:hsvShift(0, amount)
end
function SwipeColorPicker:draw()
-- Codea does not automatically call this method
-- background(self.color)
pushStyle()
ellipseMode(CENTER)
if self.active then
fill(197, 167, 167, 109)
ellipse(self.position.x, self.position.y-0.5, self.size+6)
ellipse(self.position.x, self.position.y+1.5, self.size+6)
end
-- the bezels
fill(self.color)
ellipse(self.position.x, self.position.y + 2, self.size)
fill(0, 0, 0, 179)
ellipse(self.position.x, self.position.y + 2, self.size)
fill(self.color)
ellipse(self.position.x, self.position.y - 2, self.size)
fill(255, 255, 255, 145)
ellipse(self.position.x, self.position.y - 2, self.size)
-- the color
fill(self.color)
ellipse(self.position.x, self.position.y, self.size)
popStyle()
end
function SwipeColorPicker:touched(touch)
local insideCircle
if touch.state == BEGAN then
local radius = self.size * 0.5
local closeEnoughX = math.abs(touch.x-self.position.x) < radius
local closeEnoughY = math.abs(touch.y-self.position.y) < radius
if closeEnoughX and closeEnoughY then
self.active = true
end
end
if self.active then
if math.abs(touch.deltaX) > math.abs(touch.deltaY) then
self:swipeHorizontal(touch.deltaX)
else
self:swipeVertical(touch.deltaY)
end
if touch.state == ENDED then
self.active = false
end
end
end
function SwipeColorPicker:updateRGB()
self.color = color(self:hsvToRGB(self.hsv.x, self.hsv.y,self.hsv.z))
return self.color
end
function SwipeColorPicker:hsvToRGB(h, s, v)
--thanks to SkyTheCoder on the Codea forums
local r, g, b
local i = math.floor(h * 6)
local f = h * 6 - i
local p = v * (1 - s)
local q = v * (1 - f * s)
local t = v * (1 - (1 - f) * s)
local switch = i % 6
if switch == 0 then
r = v
g = t
b = p
elseif switch == 1 then
r = q
g = v
b = p
elseif switch == 2 then
r = p
g = v
b = t
elseif switch == 3 then
r = p
g = q
b = v
elseif switch == 4 then
r = t
g = p
b = v
elseif switch == 5 then
r = v
g = p
b = q
end
return math.floor(r * 255), math.floor(g * 255), math.floor(b * 255)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment