HighlightSelectedBlock.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import { Block } from "../World/Block.js";
  2. import { vec3, mat4 } from "../utils/gmath.js";
  3. class HighlightSelectedBlock {
  4. constructor(world, renderer = world.renderer) {
  5. this.world = world;
  6. this.renderer = renderer;
  7. this.mvp = mat4.identity();
  8. const {ctx} = renderer;
  9. this.meshs = new Map();
  10. for (let renderType of Object.values(Block.renderType)) {
  11. let isFluid = renderType === Block.renderType.FLUID;
  12. if (isFluid) renderType = Block.renderType.NORMAL;
  13. let blockEles = Block.getElementsByRenderType(renderType);
  14. let lineVer = [], vers = Block.getVertexsByRenderType(renderType), surfaceMesh = {};
  15. for (let f in vers) {
  16. if (renderType !== Block.renderType.CACTUS || (f != "y+" && f != "y-"))
  17. lineVer.push(...vers[f]);
  18. surfaceMesh[f] = {
  19. ver: renderer.createVbo(vers[f]),
  20. ele: renderer.createIbo(blockEles[f]),
  21. col: renderer.createVbo([], ctx.DYNAMIC_DRAW),
  22. };
  23. }
  24. let lineEle = (len => {
  25. if (!len) return [];
  26. let base = [0,1, 1,2, 2,3, 3,0], out = [];
  27. for(let i = 0, j = 0; i < len; j = ++i*4)
  28. out.push(...base.map(x => x + j));
  29. return out;
  30. })(lineVer.length / 12);
  31. let defaultCol = [...Array(lineVer.length / 3 * 4)].map((_, i) => i % 4 === 3? 0.5: 1.0);
  32. if (isFluid) renderType = Block.renderType.FLUID;
  33. this.meshs.set(renderType, {
  34. line: {
  35. ver: renderer.createVbo(lineVer),
  36. ele: renderer.createIbo(lineEle),
  37. defaultCol: renderer.createVbo(defaultCol),
  38. col: renderer.createVbo([], ctx.DYNAMIC_DRAW),
  39. },
  40. surface: surfaceMesh,
  41. });
  42. }
  43. };
  44. draw() {
  45. const {world} = this, {mainPlayer} = world;
  46. if (mainPlayer.camera === null) return;
  47. let start = mainPlayer.getEyePosition(),
  48. end = mainPlayer.getDirection(20);
  49. vec3.add(start, end, end);
  50. let hit = world.rayTraceBlock(start, end, (x, y, z) => {
  51. let b = world.getBlock(x, y, z);
  52. return b && b.name !== "air";
  53. });
  54. if (hit === null) return;
  55. const {renderer} = this, {ctx} = renderer;
  56. let [bx, by, bz] = hit.blockPos,
  57. block = world.getBlock(bx, by, bz),
  58. selector = renderer.getProgram("selector").use(),
  59. linecol = [], surfaceCol = [];
  60. mat4.identity(this.mvp);
  61. mat4.translate(this.mvp, hit.blockPos, this.mvp);
  62. mat4.multiply(mainPlayer.camera.projview, this.mvp, this.mvp);
  63. selector.setUni("mvp", this.mvp);
  64. let mesh = this.meshs.get(block.renderType), lineMesh = mesh.line, surfaceMeshs = mesh.surface;
  65. switch (block.renderType) {
  66. case Block.renderType.FLUID:
  67. case Block.renderType.CACTUS:
  68. case Block.renderType.NORMAL: {
  69. if (!hit.axis) break;
  70. let [dx, dy, dz] = ({"x+":[1,0,0], "x-":[-1,0,0], "y+":[0,1,0], "y-":[0,-1,0], "z+":[0,0,1], "z-":[0,0,-1]})[hit.axis];
  71. let l = world.getLight(bx + dx, by + dy, bz + dz);
  72. linecol = [...Array(lineMesh.ver.length / 3 * 4)]
  73. .map((_, i) => i % 4 === 3? 0.4: Math.min(1, Math.pow(0.9, 15 - l) + 0.1));
  74. surfaceCol = [...Array(surfaceMeshs[hit.axis].ver.length / 3 * 4)]
  75. .map((_, i) => i % 4 === 3? 0.1: Math.min(1, Math.pow(0.9, 15 - l) + 0.1));
  76. break;}
  77. case Block.renderType.FLOWER: {
  78. let l = world.getLight(bx, by, bz);
  79. linecol = [...Array(lineMesh.ver.length / 3 * 4)]
  80. .map((_, i) => i % 4 === 3? 0.4: Math.min(1, Math.pow(0.9, 15 - l) + 0.1));
  81. surfaceCol = [...Array(surfaceMeshs.face.ver.length / 3 * 4)]
  82. .map((_, i) => i % 4 === 3? 0.1: Math.min(1, Math.pow(0.9, 15 - l) + 0.1));
  83. break;}
  84. }
  85. let lineColBO = lineMesh.defaultCol;
  86. if (linecol.length) {
  87. lineColBO = lineMesh.col;
  88. renderer.bindBoData(lineColBO, linecol, {drawType: ctx.DYNAMIC_DRAW});
  89. }
  90. // draw line
  91. ctx.enable(ctx.BLEND);
  92. ctx.blendFunc(ctx.SRC_ALPHA, ctx.ONE_MINUS_SRC_ALPHA);
  93. ctx.bindBuffer(lineMesh.ele.type, lineMesh.ele);
  94. selector.setAtt("pos", lineMesh.ver).setAtt("col", lineColBO);
  95. ctx.drawElements(ctx.LINES, lineMesh.ele.length, ctx.UNSIGNED_SHORT, 0);
  96. ctx.disable(ctx.BLEND);
  97. if (!hit.axis) return;
  98. let surfaceMesh = block.renderType === Block.renderType.FLOWER
  99. ? surfaceMeshs.face
  100. : surfaceMeshs[hit.axis],
  101. surfaceColBO = surfaceMesh.col;
  102. renderer.bindBoData(surfaceColBO, surfaceCol, {drawType: ctx.DYNAMIC_DRAW});
  103. // draw surface
  104. ctx.disable(ctx.CULL_FACE);
  105. ctx.enable(ctx.BLEND);
  106. ctx.blendFunc(ctx.SRC_ALPHA, ctx.ONE_MINUS_SRC_ALPHA);
  107. ctx.enable(ctx.POLYGON_OFFSET_FILL);
  108. ctx.polygonOffset(-1.0, -1.0);
  109. ctx.depthMask(false);
  110. ctx.bindBuffer(surfaceMesh.ele.type, surfaceMesh.ele);
  111. selector.setAtt("pos", surfaceMesh.ver).setAtt("col", surfaceColBO);
  112. ctx.drawElements(ctx.TRIANGLES, surfaceMesh.ele.length, ctx.UNSIGNED_SHORT, 0);
  113. ctx.depthMask(true);
  114. ctx.disable(ctx.POLYGON_OFFSET_FILL);
  115. ctx.disable(ctx.BLEND);
  116. ctx.enable(ctx.CULL_FACE);
  117. };
  118. dispose() {
  119. const {ctx} = this.renderer;
  120. for (let [, mesh] of this.meshs) {
  121. for (let k of ["ver", "ele", "col"]) {
  122. ctx.deleteBuffer(mesh.line[k]);
  123. Object.values(mesh.surface).forEach(surfaceMesh => ctx.deleteBuffer(surfaceMesh[k]));
  124. }
  125. ctx.deleteBuffer(mesh.line.defaultCol);
  126. }
  127. };
  128. };
  129. export {
  130. HighlightSelectedBlock,
  131. HighlightSelectedBlock as default,
  132. };