main.lua 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. -- "Second screen experience" demo
  2. -- Click grid on desktop screen to build a scene simultaneously visible in VR space
  3. -- NOTE: does not currently work properly with the simluator driver, since lovr.mirror clears the window
  4. --
  5. -- Sample contributed by andi mcc
  6. local shader = require 'shader'
  7. local mirror = lovr.mirror -- Backup lovr.mirror before it is overwritten
  8. local font = lovr.graphics.newFont(24) -- Font appropriate for screen-space usage
  9. font:setPixelDensity(1)
  10. -- Simple 2D triangle mesh
  11. local triangle = lovr.graphics.newBuffer(
  12. {{'VertexPosition', 'vec3'}},
  13. {{0,-1,0}, {0.75,1,0}, {-0.75,1,0}})
  14. -- Constants
  15. local pixwidth = lovr.system.getWindowWidth() -- Window pixel width and height
  16. local pixheight = lovr.system.getWindowHeight()
  17. local aspect = pixwidth/pixheight -- Window aspect ratio
  18. local height = 2 -- Window width and height in screen coordinates
  19. local width = aspect*2 -- ( We will pick the coordinate system [[-1,1],[-aspect,aspect]] )
  20. local topmargin = 0.2 -- Space between top of screen and top of grid
  21. local cells = 7 -- Number of cells in grid (per side)
  22. local towerscalexz = 2 -- How wide is one block in 3D space?
  23. local towerscaley = 3 -- How tall (maximum) is one block in 3D space?
  24. -- Derived constants
  25. local gridheight = (height-topmargin*2) -- Height of grid
  26. local gridspan = gridheight/2 -- Half height of grid
  27. local cellheight = gridheight/cells -- Height of one grid cell
  28. local cellspan = cellheight/2 -- Half height of one grid cell
  29. local bannedcell = math.ceil(cells/2) -- Do not allow clicks at this x,y coordinate
  30. local fontscale = height/pixheight -- Scale argument to screen-space print() functions
  31. -- Screen-space coordinate system
  32. local matrix = lovr.math.newMat4():orthographic(-aspect, aspect, -1, 1, -64, 64)
  33. -- State: We will store the blocks to draw as a 2D array of heights (nil for no block)
  34. local grid = {}
  35. for x=1,cells do grid[x] = {} end
  36. function lovr.mousepressed(x, y, b)
  37. local inx = x * width / pixwidth - width/2 -- Convert pixel x,y to our coordinate system
  38. local iny = y * height / pixheight - height/2
  39. local gridorigin = -gridspan - cellheight -- Upper left of grid ()
  40. local gx = (inx - gridorigin) / cellheight -- Convert coordinate system to grid cells
  41. local gy = (iny - gridorigin) / cellheight
  42. local fx = math.floor(gx)
  43. local fy = math.floor(gy)
  44. if fx >= 1 and fy >= 1 and fx <= cells and fy <= cells -- If the click was within the grid
  45. and not (fx == bannedcell and fy == bannedcell) then -- and was not the banned center cell
  46. if grid[fx][fy] then
  47. grid[fx][fy] = nil -- toggle off
  48. else
  49. grid[fx][fy] = lovr.math.random() -- toggle on (random height)
  50. end
  51. end
  52. end
  53. local function drawGrid(pass)
  54. -- Draw cell backgrounds (where present)
  55. for _x=1,cells do for _y=1,cells do
  56. local gray = grid[_x][_y]
  57. if gray then
  58. local x = -gridspan + _x * cellheight - cellspan -- Center of cell
  59. local y = -gridspan + _y * cellheight - cellspan
  60. pass:setColor(gray,gray,gray,1)
  61. pass:plane(x, y, 0, cellheight, cellheight)
  62. end
  63. end end
  64. -- Draw grid lines
  65. pass:setColor(1,1,1,1)
  66. for c=0,cells do
  67. local x = -gridspan + c * cellheight
  68. local y = -gridspan + c * cellheight
  69. pass:line(-gridspan, y, 0, gridspan, y, 0)
  70. pass:line(x, -gridspan, 0, x, gridspan, 0)
  71. end
  72. -- Draw a red triangle indicating the position and orientation of the headset player
  73. pass:push()
  74. local x, y, z, angle, ax, ay, az = lovr.headset.getPose()
  75. -- Flatten the 3-space current rotation of the headset into just its xz axis
  76. -- Equation from: http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToEuler/index.htm
  77. local s = math.sin(angle)
  78. local c = math.cos(angle)
  79. local t = 1-c;
  80. local xzangle = math.atan2(ay*s - ax*az*t , 1 - (ay*ay + az*az) * t);
  81. pass:setColor(1,0,0,1)
  82. pass:translate(x / towerscalexz, z / towerscalexz, 0)
  83. pass:scale(cellheight*0.5*0.75)
  84. pass:rotate(-xzangle, 0, 0, 1)
  85. pass:mesh(triangle)
  86. pass:pop()
  87. end
  88. -- Draw HUD overlay
  89. local function mirror(pass)
  90. pass:origin()
  91. pass:setViewPose(1, mat4())
  92. pass:setProjection(1, matrix) -- Switch to screen space coordinates
  93. pass:setDepthTest() -- Depth buffer will be full of garbage after drawing scene
  94. drawGrid(pass)
  95. -- Draw instructions
  96. pass:setColor(1,1,1,1)
  97. pass:setFont(font)
  98. pass:text("Instructions: Click the grid to create or remove blocks.", 0, (gridheight+cellheight)/2, 0, fontscale)
  99. end
  100. -- Draw one block
  101. local function floorbox(pass,_x,_y,gray)
  102. local x = -gridspan + _x * cellheight - cellspan
  103. local z = -gridspan + _y * cellheight - cellspan
  104. local height = gray * towerscaley
  105. pass:box(x*towerscalexz, height/2, z*towerscalexz, cellheight*towerscalexz, height, cellheight*towerscalexz)
  106. end
  107. -- Draw 3D scene
  108. local function draw(pass)
  109. pass:setShader(shader)
  110. pass:setColor(0,1,1)
  111. for x=1,cells do for y=1,cells do
  112. local gray = grid[x][y]
  113. if gray then floorbox(pass,x,y,gray) end
  114. end end
  115. pass:setShader()
  116. end
  117. -- Handle LOVR
  118. function lovr.draw(pass)
  119. draw(pass) -- Headset contents
  120. end
  121. local originalMirror = lovr.mirror -- By default, LOVR will have given us a mirror that displays the headset
  122. function lovr.mirror(pass)
  123. originalMirror(pass) -- Headset texture (note: this will fill the depth buffer with z=0)
  124. mirror(pass) -- Mirror contents
  125. end