1 /**
2 Copyright: Copyright (c) 2016-2018 Andrey Penechko.
3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4 Authors: Andrey Penechko.
5 */
6 module railroad.rail.mesh;
7 
8 import voxelman.log;
9 import std.range;
10 import std.conv : to;
11 import voxelman.container.buffer;
12 import voxelman.math;
13 
14 import voxelman.model.vertex;
15 import voxelman.graphics;
16 import voxelman.geometry;
17 
18 import voxelman.world.mesh.chunkmesh;
19 import voxelman.world.mesh.sidemeshers.full;
20 import voxelman.world.mesh.sidemeshers.utils;
21 import voxelman.world.block;
22 import voxelman.world.blockentity.blockentityaccess;
23 import voxelman.world.blockentity.blockentitydata;
24 import voxelman.world.blockentity.utils;
25 
26 import railroad.rail.utils;
27 
28 void makeRailMesh(BlockEntityMeshingData meshingData)
29 {
30 	auto railData = RailData(meshingData.data);
31 	if (meshingData.data.type == BlockEntityType.localBlockEntity &&
32 		meshingData.entityPos == ivec3(0,0,0))
33 	{
34 		putRailMesh!MeshVertex(
35 			meshingData.output[Solidity.solid],
36 			meshingData.chunkPos,
37 			railData);
38 	}
39 
40 	if (railData.isSlope)
41 	{
42 		CubeSide sideToMesh;
43 		if (isSlopeUpSideBlock(railData, meshingData.entityPos, sideToMesh))
44 		{
45 			if (meshingData.sides & (1 << sideToMesh))
46 			{
47 				ubyte[4] occlusions = meshingData.occlusionHandler(meshingData.blockIndex, sideToMesh);
48 				SideParams sideParams = SideParams(
49 					ubvec3(meshingData.chunkPos),
50 					calcColor(meshingData.blockIndex, meshingData.color),
51 					[0,0],
52 					0,
53 					&meshingData.output[Solidity.solid]);
54 				meshFullSideOccluded(sideToMesh, occlusions, sideParams);
55 			}
56 		}
57 	}
58 
59 	if (meshingData.sides & SideMask.yneg)
60 	{
61 		ubyte[4] occlusions = meshingData.occlusionHandler(meshingData.blockIndex, CubeSide.yneg);
62 		SideParams sideParams = SideParams(
63 			ubvec3(meshingData.chunkPos),
64 			calcColor(meshingData.blockIndex, meshingData.color),
65 			[0,0],
66 			0,
67 			&meshingData.output[Solidity.solid]);
68 		meshFullSideOccluded(CubeSide.yneg, occlusions, sideParams);
69 	}
70 }
71 
72 void putRailMesh(Vert, Sink)(ref Sink sink, ivec3 chunkPos, RailData data)
73 {
74 	ivec3 tilePos = railTilePos(chunkPos);
75 	auto chunkPosF = vec3(tilePos);
76 
77 	foreach(segment; data.getSegments())
78 	{
79 		auto meshIndex = railSegmentMeshId[segment];
80 		auto mesh = railMeshes[meshIndex];
81 		ubyte rotation = railSegmentMeshRotation[segment];
82 		auto rotator = getCCWRotationShiftOriginFunction!vec3(rotation);
83 		vec3 offset = chunkPosF + vec3(railSegmentOffsets[segment]);
84 		vec3 meshSize = vec3(meshSizes[meshIndex]);
85 
86 		sink.reserve(mesh.length);
87 
88 		foreach(v; mesh)
89 		{
90 			vec3 pos = rotator(v.position, meshSize) + offset;
91 			sink.put(Vert(pos, [0,0], v.color.r));
92 		}
93 	}
94 }
95 
96 alias RailVertexT = VertexPosColor!(float, 3, ubyte, 3);
97 __gshared RailVertexT[][3] railMeshes;
98 ivec3[3] meshSizes = [
99 	ivec3(4, 1, 8),
100 	ivec3(6, 1, 6),
101 	ivec3(4, 1, 8)];
102 
103 
104 void putRailPreview(
105 	ref Buffer!ColoredVertex buffer,
106 	RailPos railPos0, RailPos railPos1,
107 	CubeSide side0, CubeSide side1,
108 	bool flipEndOffset,
109 	Colors color)
110 {
111 	assert(side0 < 4);
112 	assert(side1 < 4);
113 	vec3 startOff = vec3(railPos0.x * RAIL_TILE_SIZE, railPos0.y, railPos0.z * RAIL_TILE_SIZE);
114 	vec3 endOff = vec3(railPos1.x * RAIL_TILE_SIZE, railPos1.y, railPos1.z * RAIL_TILE_SIZE);
115 
116 	vec3[4] sideOffsets = [
117 		vec3(RAIL_TILE_SIZE/2-0.25, 0, 0), // zneg
118 		vec3(RAIL_TILE_SIZE/2-0.25, 0, RAIL_TILE_SIZE-0.5), // zpos
119 		vec3(RAIL_TILE_SIZE-0.5, 0, RAIL_TILE_SIZE/2 - 0.25), // xpos
120 		vec3(0, 0, RAIL_TILE_SIZE/2 - 0.25)]; // xneg
121 
122 	vec3[4] sideOffsetAxis = [
123 		vec3(-1, 0, 0), // zneg
124 		vec3(-1, 0, 0), // zpos
125 		vec3( 0, 0, 1), // xpos
126 		vec3( 0, 0, 1)];// xneg
127 
128 	vec3[4] getSideGeometry(CubeSide side, vec3 offset, float mult) {
129 		return [
130 		vec3(cubeVerticies[cubeSideVertIndices[side][0]]) * mult + offset, // zneg
131 		vec3(cubeVerticies[cubeSideVertIndices[side][1]]) * mult + offset, // zpos
132 		vec3(cubeVerticies[cubeSideVertIndices[side][2]]) * mult + offset, // xpos
133 		vec3(cubeVerticies[cubeSideVertIndices[side][3]]) * mult + offset];// xneg
134 	}
135 
136 	vec3[4] start0 = getSideGeometry(side0, sideOffsets[side0] + sideOffsetAxis[side0] + startOff, 0.5f);
137 	vec3[4] start1 = getSideGeometry(side0, sideOffsets[side0] - sideOffsetAxis[side0] + startOff, 0.5f);
138 
139 	vec3 endOffsetAxis = sideOffsetAxis[side1];
140 	if (flipEndOffset) endOffsetAxis = -endOffsetAxis;
141 	vec3[4] end0 = getSideGeometry(side1, sideOffsets[side1] + endOffsetAxis + endOff, 0.5f);
142 	vec3[4] end1 = getSideGeometry(side1, sideOffsets[side1] - endOffsetAxis + endOff, 0.5f);
143 
144 	const vec3[8] corners0 = [
145 		vec3(start0[1]), vec3(end0[2]), vec3(start0[2]), vec3(end0[1]),
146 		vec3(start0[0]), vec3(end0[3]), vec3(start0[3]), vec3(end0[0])];
147 	buffer.put4gonalPrismTris(corners0, vec3(0,0,0), color);
148 
149 	const vec3[8] corners1 = [
150 		vec3(start1[1]), vec3(end1[2]), vec3(start1[2]), vec3(end1[1]),
151 		vec3(start1[0]), vec3(end1[3]), vec3(start1[3]), vec3(end1[0])];
152 	buffer.put4gonalPrismTris(corners1, vec3(0,0,0), color);
153 }