project.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. // https://codeburst.io/dynamic-modules-with-vuex-and-vue-b9c481ca792
  2. // https://www.brophy.org/post/instance-aware-vuex-modules-1/
  3. // import qs from 'querystring'
  4. // import { REST } from 'api/rest-axios'
  5. import { GRAPHQL } from 'api/graphql-axios'
  6. import Query from 'graphql-query-builder'
  7. import * as THREE from 'three'
  8. import { ThreeBSP } from 'three-js-csg-es6'
  9. export default {
  10. namespaced: true,
  11. // initial state
  12. state: {
  13. obj3d: null,
  14. size: { x: 0, y: 0, z: 0 },
  15. position: { x: 0, y: 0, z: 0 },
  16. walls3dObj: null,
  17. wallsPos: null,
  18. top3dObj: null,
  19. topPos: null,
  20. topColor: null,
  21. floor3dObj: null,
  22. floorPos: null,
  23. florrColor: null,
  24. levels3dObj: null,
  25. levelsPos: null,
  26. wall: {
  27. wallW: 0.001,
  28. // dig windows on face and back
  29. winW: 2 + Math.random() * 2,
  30. winH: 4 + Math.random() * 4,
  31. margin: 2,
  32. nbrWinX: 0,
  33. paddingX: 0,
  34. nbrWinY: 0,
  35. paddingY: 0,
  36. nbrWinZ: 0,
  37. paddingZ: 0
  38. },
  39. contents: {},
  40. contents_size_factor: 2, // factor to get the contents (grid) size proportional to windows
  41. contentTypes: ['visible', 'context', 'process', 'concept'],
  42. grid: { visible: [], context: [], process: [], concept: [] },
  43. gridContentPlaced: {},
  44. activeLevel: 'visibles'
  45. },
  46. // getters
  47. getters: {
  48. position: (state) => {
  49. return state.position
  50. },
  51. size: (state) => {
  52. return state.size
  53. },
  54. createGradientCanvas: (state) => (c1, c2) => {
  55. var ctx = document.createElement('canvas').getContext('2d')
  56. ctx.canvas.width = 1024
  57. ctx.canvas.height = 1024
  58. var lingrad = ctx.createLinearGradient(0, 0, 0, 1024)
  59. lingrad.addColorStop(0, c1)
  60. lingrad.addColorStop(1, c2)
  61. ctx.fillStyle = lingrad
  62. ctx.fillRect(0, 0, 1024, 1024)
  63. return ctx.canvas
  64. }
  65. },
  66. // mutations
  67. mutations: {
  68. setSize: (state, size) => {
  69. state.size = size
  70. },
  71. setPosition: (state, pos) => {
  72. state.position = pos
  73. },
  74. setWalls3dObj: (state, obj) => { state.walls3dObj = obj },
  75. setWallsPos: (state, pos) => { state.wallsPos = pos },
  76. setTop3dObj: (state, obj) => { state.top3dObj = obj },
  77. setTopPos: (state, pos) => { state.topPos = pos },
  78. setFloor3dObj: (state, obj) => { state.floor3dObj = obj },
  79. setFloorPos: (state, pos) => { state.floorPos = pos },
  80. setTopColor: (state, col) => { state.topColor = col },
  81. setFloorColor: (state, col) => { state.floorColor = col },
  82. setLevels3dObj: (state, obj) => { state.levels3dObj = obj },
  83. setLevelsPos: (state, pos) => { state.levelsPos = pos },
  84. setContents: (state, contents) => { state.contents = contents },
  85. setGrid: (state, grid) => { state.grid = grid },
  86. shiftGrid: (state, c) => {
  87. let p = state.grid[c.type].shift()
  88. if (!state.gridContentPlaced[c.type]) {
  89. state.gridContentPlaced[c.type] = {}
  90. }
  91. state.gridContentPlaced[c.type][c.id] = p
  92. },
  93. setActiveLevel: (state, l) => {
  94. state.activeLevel = l
  95. }
  96. },
  97. // actions
  98. actions: {
  99. init ({ dispatch, commit, state, rootGetters }) {
  100. console.log(`Init Project module ${state.id}`, state)
  101. dispatch('sizingBuilding')
  102. dispatch('build3dObjs')
  103. },
  104. sizingBuilding ({ dispatch, commit, state, rootGetters }) {
  105. console.log('sizingBuilding, state', state)
  106. let totalW = rootGetters['Projects/totalW']
  107. // console.log('totalW', totalW)
  108. let margin = rootGetters['Projects/marginBetweenBuildings']
  109. // console.log('margin', margin)
  110. // positioning buildings on x regarding the widths
  111. // & setting up the window sizing
  112. // & setting up the content grid
  113. // let wall, a
  114. // let grid
  115. // X POS
  116. let x
  117. if (state.index === 0) {
  118. // if it's the first
  119. x = -1 * totalW / 2 + state.size.x / 2
  120. } else {
  121. // else get the precedent pos
  122. let prevProjID = rootGetters['Projects/projectID'](state.index - 1)
  123. // console.log('prevProjID', prevProjID)
  124. let prevProjPos = rootGetters[`project:${prevProjID}/position`]
  125. // console.log(`project:${prevProjID}/position.x`, prevProjPos.x)
  126. let prevProjSize = rootGetters[`project:${prevProjID}/size`]
  127. // console.log(`project:${prevProjID}/size.x`, prevProjSize.x)
  128. // console.log('state.size.x', state.size.x)
  129. // prev X + alf of prev size x + margin + half of current size x
  130. x = prevProjPos.x + prevProjSize.x / 2 + margin + state.size.x / 2
  131. }
  132. // console.log('x', x)
  133. commit('setPosition', {
  134. x: x,
  135. // y: -1 * state.size.y / 2 + 10 + Math.random() * 30, // -10 + Math.random() * this.size.y / 2
  136. y: -state.size.y / 4,
  137. z: 0// -10 + Math.random() * 10
  138. })
  139. // WINDOWS
  140. let a = 0
  141. state.wall.nbrWinX = Math.floor((state.size.x - 2 * state.wall.margin) / state.wall.winW)
  142. // removing windows on X until padding is enough
  143. while (state.wall.paddingX < 0.4) {
  144. state.wall.nbrWinX -= a
  145. state.wall.paddingX = (state.size.x - 2 * state.wall.margin - state.wall.winW * state.wall.nbrWinX) / (state.wall.nbrWinX - 1)
  146. a++
  147. }
  148. a = 0
  149. state.wall.nbrWinY = Math.floor((state.size.y - 2 * state.wall.margin) / state.wall.winH)
  150. // removing windows on Y until padding is enough
  151. while (state.wall.paddingY < 0.4) {
  152. state.wall.nbrWinY -= a
  153. state.wall.paddingY = (state.size.y - 2 * state.wall.margin - state.wall.winH * state.wall.nbrWinY) / (state.wall.nbrWinY - 1)
  154. a++
  155. }
  156. // CONTENTS GRID
  157. a = 0
  158. state.wall.nbrWinZ = Math.floor((state.size.z - 2 * state.wall.margin) / state.wall.winW)
  159. while (state.wall.paddingZ < 0.4) {
  160. state.wall.nbrWinZ -= a
  161. state.wall.paddingZ = (state.size.z - 2 * state.wall.margin - state.wall.winW * state.wall.nbrWinZ) / (state.wall.nbrWinZ - 1)
  162. a++
  163. }
  164. let grid = {}
  165. let rows = state.wall.nbrWinY / state.contents_size_factor
  166. let cols = state.wall.nbrWinZ / state.contents_size_factor
  167. let t
  168. for (var m = 0; m < rows; m++) { // rows
  169. if (m > rows / 4 * 3) {
  170. t = state.contentTypes[0]
  171. } else if (m > rows / 4 * 2) {
  172. t = state.contentTypes[1]
  173. } else if (m > rows / 4) {
  174. t = state.contentTypes[2]
  175. } else {
  176. t = state.contentTypes[3]
  177. }
  178. if (!grid[t]) {
  179. grid[t] = []
  180. }
  181. for (var l = 0; l < cols; l++) { // cols
  182. grid[t].push({
  183. z: margin + state.wall.winW * state.contents_size_factor * l,
  184. y: margin + state.wall.winH * state.contents_size_factor * m
  185. })
  186. }
  187. }
  188. console.log('grid', grid)
  189. // shuffle the grids
  190. for (var i = 0; i < state.contentTypes.length; i++) {
  191. for (let n = grid[state.contentTypes[i]].length - 1; n > 0; n--) {
  192. const o = Math.floor(Math.random() * n)
  193. const temp = grid[state.contentTypes[i]][n]
  194. grid[state.contentTypes[i]][n] = grid[state.contentTypes[i]][o]
  195. grid[state.contentTypes[i]][o] = temp
  196. }
  197. }
  198. console.log('shuffeld grid', grid)
  199. commit('setGrid', grid)
  200. console.log('state.grid', state.grid)
  201. },
  202. build3dObjs ({ dispatch, commit, state, getters, rootGetters }) {
  203. console.log('build3dObjs')
  204. // http://learningthreejs.com/blog/2011/12/10/constructive-solid-geometry-with-csg-js/
  205. let frontGeom = new THREE.BoxGeometry(state.size.x, state.size.y, state.wall.wallW)
  206. let frontMesh = new THREE.Mesh(frontGeom)
  207. frontMesh.position.z = 0.5 * state.size.z
  208. let frontBSP = new ThreeBSP(frontMesh)
  209. // https://medium.com/techtrument/multithreading-javascript-46156179cf9a
  210. let winGeom = new THREE.BoxGeometry(state.wall.winW, state.wall.winH, state.wall.wallW)
  211. let winMesh = new THREE.Mesh(winGeom)
  212. let windowsGeom = new THREE.Geometry()
  213. for (var i = 0; i < state.wall.nbrWinX; i++) {
  214. for (var j = 0; j < state.wall.nbrWinY; j++) {
  215. winMesh.position.z = 0.5 * state.size.z
  216. winMesh.position.x = -0.5 * state.size.x + state.wall.margin + state.wall.winW * 0.5 + i * (state.wall.winW + state.wall.paddingX)
  217. winMesh.position.y = 0.5 * state.size.y - state.wall.margin - state.wall.winH * 0.5 - j * (state.wall.winH + state.wall.paddingY)
  218. // winMesh.updateMatrix()
  219. windowsGeom.mergeMesh(winMesh)
  220. }
  221. }
  222. let windowsBSP = new ThreeBSP(windowsGeom)
  223. let frontWindowedBSP = frontBSP.subtract(windowsBSP)
  224. // console.log('state.Faces_opaques', state.Faces_opaques)
  225. let backWindowedMesh
  226. if (state.Faces_opaques === 3) {
  227. backWindowedMesh = frontMesh.clone()
  228. } else {
  229. let frontWindowedMesh = frontWindowedBSP.toMesh()
  230. backWindowedMesh = frontWindowedMesh.clone()
  231. }
  232. backWindowedMesh.position.z = -0.5 * state.size.z
  233. let backWindowedBSP = new ThreeBSP(backWindowedMesh)
  234. let rightGeom = new THREE.BoxGeometry(state.wall.wallW, state.size.y, state.size.z)
  235. let rightMesh = new THREE.Mesh(rightGeom)
  236. rightMesh.position.x = 0.5 * state.size.x
  237. // rightMesh.position.z = 0.5 * state.size.z
  238. let rightBSP = new ThreeBSP(rightMesh)
  239. let leftMesh = rightMesh.clone()
  240. leftMesh.position.x = -0.5 * state.size.x
  241. // leftMesh.position.z = 0.5 * state.size.z
  242. let leftBSP = new ThreeBSP(leftMesh)
  243. let buildingBSP = frontWindowedBSP.union(rightBSP)
  244. buildingBSP = buildingBSP.union(backWindowedBSP)
  245. buildingBSP = buildingBSP.union(leftBSP)
  246. // convert back to three.js mesh
  247. let building = buildingBSP.toMesh()
  248. // create a classical material for building
  249. // let topColor = `hsla(201, 100%, 95%, 1)`
  250. let hTop = Math.round(190 + Math.random() * 20)
  251. let sTop = Math.round(20 + Math.random() * 60)
  252. let lTop = Math.round(75)
  253. // let hFloor = Math.round(205 + Math.random() * 10)
  254. let hFloor = hTop
  255. // let sFloor = Math.round(30 + Math.random() * 40)
  256. let sFloor = sTop
  257. // let lFloor = Math.round(10 + Math.random() * 20)
  258. let lFloor = Math.round(10)
  259. let topColor = `hsla(${hTop}, ${sTop}%, ${lTop}%, 1)`
  260. commit('setTopColor', topColor)
  261. let floorColor = `hsla(${hFloor}, ${sFloor}%, ${lFloor}%, 1)`
  262. commit('setFloorColor', floorColor)
  263. let gradientTexture = new THREE.CanvasTexture(getters.createGradientCanvas(topColor, floorColor))
  264. let materialOpts = {
  265. color: 0xffffff,
  266. side: THREE.DoubleSide,
  267. shininess: 30,
  268. map: gradientTexture
  269. }
  270. building.material = new THREE.MeshPhongMaterial(materialOpts)
  271. // commiting walls
  272. commit('setWalls3dObj', building)
  273. let buildingPos = { ...state.position, ...{ z: state.position.z + 0.5 * state.size.z } }
  274. commit('setWallsPos', buildingPos)
  275. // TOP & FLOOR
  276. let topGeom = new THREE.BoxGeometry(state.size.x, state.wall.wallW, state.size.z)
  277. let topOpts = {
  278. color: new THREE.Color(`hsl(${hTop}, ${sTop}%, ${lTop}%)`),
  279. shininess: 30
  280. }
  281. let topMat = new THREE.MeshPhongMaterial(topOpts)
  282. let topMesh = new THREE.Mesh(topGeom, topMat)
  283. commit('setTop3dObj', topMesh)
  284. let topPosition = { ...state.position, ...{ y: state.position.y + 0.5 * state.size.y } }
  285. commit('setTopPos', topPosition)
  286. let floorOpts = {
  287. color: new THREE.Color(`hsl(${hFloor}, ${sFloor}%, ${lFloor}%)`),
  288. shininess: 10
  289. }
  290. let floorMat = new THREE.MeshPhongMaterial(floorOpts)
  291. let floorMesh = new THREE.Mesh(topGeom, floorMat)
  292. commit('setFloor3dObj', floorMesh)
  293. let floorPosition = { ...state.position, ...{ y: state.position.y - 0.5 * state.size.y } }
  294. commit('setFloorPos', floorPosition)
  295. // LEVELS
  296. let levelGeom = new THREE.BoxGeometry(state.size.x - state.wall.wallW * 2, 0.1, state.size.z - state.wall.wallW * 2)
  297. let levelMesh = new THREE.Mesh(levelGeom)
  298. let levelBSP = new ThreeBSP(levelMesh)
  299. let levelHoleGeom = new THREE.BoxGeometry(state.size.x - state.wall.wallW * 2 - 3, 0.1, state.size.z - state.wall.wallW * 2 - 3)
  300. let levelHoleMesh = new THREE.Mesh(levelHoleGeom)
  301. let levelHoleBSP = new ThreeBSP(levelHoleMesh)
  302. levelBSP = levelBSP.subtract(levelHoleBSP)
  303. levelMesh = levelBSP.toMesh()
  304. let levelsGeom = new THREE.Geometry()
  305. for (var k = -1; k < 2; k++) {
  306. levelMesh.position.y = k * state.size.y * 0.25
  307. levelsGeom.mergeMesh(levelMesh)
  308. }
  309. let levelsOpts = {
  310. color: new THREE.Color(`hsl(${hTop}, ${sTop}%, ${lTop}%)`),
  311. shininess: 10
  312. }
  313. let levelsMat = new THREE.MeshPhongMaterial(levelsOpts)
  314. let levelsMesh = new THREE.Mesh(levelsGeom, levelsMat)
  315. commit('setLevels3dObj', levelsMesh)
  316. let levelsPos = { ...state.position }
  317. commit('setLevelsPos', levelsPos)
  318. // // repère
  319. // let repGeom = new THREE.BoxGeometry(1, 1, 1)
  320. // let repMesh = new THREE.Mesh(repGeom)
  321. // let repOpts = {
  322. // color: 0x0000ff,
  323. // shininess: 30
  324. // }
  325. // repMesh.material = new THREE.MeshPhongMaterial(repOpts)
  326. // repMesh.position = { ...state.position, ...{ y: 0 } }
  327. // commit('setRep3dObj', levelsMesh)
  328. },
  329. loadContents ({ dispatch, commit, state }) {
  330. console.log('loadContents')
  331. let contentsQuery = new Query('project', { id: state.id })
  332. let visiblesQuery = new Query('visibles')
  333. visiblesQuery.filter({ Published: true })
  334. visiblesQuery.find(['id', 'Name', 'Text2', 'Vimeo', 'Url', 'categories'])
  335. contentsQuery.find([visiblesQuery])
  336. console.log('contentsQuery', `${contentsQuery}`)
  337. GRAPHQL.post('', { query: `query {
  338. project(id: "${state.id}") {
  339. visibles(where: { Published: "true" }){
  340. id
  341. Name
  342. Media {
  343. url
  344. size
  345. }
  346. Text2
  347. Vimeo
  348. Url
  349. categories
  350. }
  351. contexts(where: { Published: "true" }){
  352. id
  353. Name
  354. Images {
  355. url
  356. size
  357. }
  358. Text2
  359. Vimeo
  360. Url
  361. }
  362. processes(where: { Published: "true" }){
  363. id
  364. Name
  365. Media {
  366. url
  367. size
  368. }
  369. Text2
  370. Vimeo
  371. Url
  372. }
  373. concepts(where: { Published: "true" }){
  374. id
  375. Name
  376. Images {
  377. url
  378. size
  379. }
  380. Text2
  381. Vimeo
  382. }
  383. }
  384. }` })
  385. .then(({ data: { data: { project } = null } }) => {
  386. console.log('graphql contents', project)
  387. commit('setContents', project)
  388. // dispatch('computeProjects', projects)
  389. })
  390. .catch((error) => {
  391. console.warn('Issue with getProjects', error)
  392. Promise.reject(error)
  393. })
  394. }
  395. // getGridPos ({ state, commit }) {
  396. // let p = state.grid[0]
  397. // commit('shiftGrid')
  398. // Promise.resolve(p)
  399. // }
  400. }
  401. }