forked from Vogtinator/crafti
-
Notifications
You must be signed in to change notification settings - Fork 0
/
doorrenderer.cpp
164 lines (140 loc) · 7.24 KB
/
doorrenderer.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#include "doorrenderer.h"
constexpr GLFix DoorRenderer::door_depth; //As small as possible, a opened door shouldn't be much of an obstacle
constexpr uint8_t DoorRenderer::DOOR_TOP, DoorRenderer::DOOR_OPEN, DoorRenderer::DOOR_FORCE_OPEN; //FORCE_OPEN: Opened by hand, not redstone
//If the door is open, this array maps the side of the closed door to the side of an open door and vice-versa
static const BLOCK_SIDE door_side_map[] {
BLOCK_RIGHT,
BLOCK_LEFT,
BLOCK_BACK,
BLOCK_FRONT
};
void DoorRenderer::renderSpecialBlock(const BLOCK_WDATA block, GLFix x, GLFix y, GLFix z, Chunk &c)
{
BLOCK_SIDE side = static_cast<BLOCK_SIDE>(getBLOCKDATA(block) & BLOCK_SIDE_BITS);
const TextureAtlasEntry &tex = terrain_atlas[1][(getBLOCKDATA(block) & DOOR_TOP) ? 5 : 6].current;
const GLFix door_offset = door_depth;
switch(side)
{
case BLOCK_FRONT:
c.addUnalignedVertex({x, y, z + door_offset, tex.left, tex.bottom, TEXTURE_TRANSPARENT | TEXTURE_DRAW_BACKFACE});
c.addUnalignedVertex({x, y + BLOCK_SIZE, z + door_offset, tex.left, tex.top, TEXTURE_TRANSPARENT | TEXTURE_DRAW_BACKFACE});
c.addUnalignedVertex({x + BLOCK_SIZE, y + BLOCK_SIZE, z + door_offset, tex.right, tex.top, TEXTURE_TRANSPARENT | TEXTURE_DRAW_BACKFACE});
c.addUnalignedVertex({x + BLOCK_SIZE, y, z + door_offset, tex.right, tex.bottom, TEXTURE_TRANSPARENT | TEXTURE_DRAW_BACKFACE});
break;
case BLOCK_BACK:
c.addUnalignedVertex({x + BLOCK_SIZE, y, z - door_offset + BLOCK_SIZE, tex.left, tex.bottom, TEXTURE_TRANSPARENT | TEXTURE_DRAW_BACKFACE});
c.addUnalignedVertex({x + BLOCK_SIZE, y + BLOCK_SIZE, z - door_offset + BLOCK_SIZE, tex.left, tex.top, TEXTURE_TRANSPARENT | TEXTURE_DRAW_BACKFACE});
c.addUnalignedVertex({x, y + BLOCK_SIZE, z - door_offset + BLOCK_SIZE, tex.right, tex.top, TEXTURE_TRANSPARENT | TEXTURE_DRAW_BACKFACE});
c.addUnalignedVertex({x, y, z - door_offset + BLOCK_SIZE, tex.right, tex.bottom, TEXTURE_TRANSPARENT | TEXTURE_DRAW_BACKFACE});
break;
case BLOCK_LEFT:
c.addUnalignedVertex({x + door_offset, y, z + BLOCK_SIZE, tex.left, tex.bottom, TEXTURE_TRANSPARENT | TEXTURE_DRAW_BACKFACE});
c.addUnalignedVertex({x + door_offset, y + BLOCK_SIZE, z + BLOCK_SIZE, tex.left, tex.top, TEXTURE_TRANSPARENT | TEXTURE_DRAW_BACKFACE});
c.addUnalignedVertex({x + door_offset, y + BLOCK_SIZE, z, tex.right, tex.top, TEXTURE_TRANSPARENT | TEXTURE_DRAW_BACKFACE});
c.addUnalignedVertex({x + door_offset, y, z, tex.right, tex.bottom, TEXTURE_TRANSPARENT | TEXTURE_DRAW_BACKFACE});
break;
case BLOCK_RIGHT:
c.addUnalignedVertex({x - door_offset + BLOCK_SIZE, y, z, tex.left, tex.bottom, TEXTURE_TRANSPARENT | TEXTURE_DRAW_BACKFACE});
c.addUnalignedVertex({x - door_offset + BLOCK_SIZE, y + BLOCK_SIZE, z, tex.left, tex.top, TEXTURE_TRANSPARENT | TEXTURE_DRAW_BACKFACE});
c.addUnalignedVertex({x - door_offset + BLOCK_SIZE, y + BLOCK_SIZE, z + BLOCK_SIZE, tex.right, tex.top, TEXTURE_TRANSPARENT | TEXTURE_DRAW_BACKFACE});
c.addUnalignedVertex({x - door_offset + BLOCK_SIZE, y, z + BLOCK_SIZE, tex.right, tex.bottom, TEXTURE_TRANSPARENT | TEXTURE_DRAW_BACKFACE});
default:
break;
}
}
AABB DoorRenderer::getAABB(const BLOCK_WDATA block, GLFix x, GLFix y, GLFix z)
{
BLOCK_SIDE side = static_cast<BLOCK_SIDE>((getBLOCKDATA(block) & BLOCK_SIDE_BITS));
switch(side)
{
case BLOCK_FRONT:
return {x, y, z, x + BLOCK_SIZE, y + BLOCK_SIZE, z + door_depth};
break;
case BLOCK_RIGHT:
return {x + BLOCK_SIZE - door_depth, y, z, x + BLOCK_SIZE, y + BLOCK_SIZE, z + BLOCK_SIZE};
break;
case BLOCK_LEFT:
return {x, y, z, x + door_depth, y + BLOCK_SIZE, z + BLOCK_SIZE};
break;
case BLOCK_BACK:
return {x, y, z + BLOCK_SIZE - door_depth, x + BLOCK_SIZE, y + BLOCK_SIZE, z + BLOCK_SIZE};
break;
default:
return {};
break;
}
}
void DoorRenderer::drawPreview(const BLOCK_WDATA /*block*/, TEXTURE &dest, int x, int y)
{
drawTexture(*door_preview, dest, 0, 0, 16, 32, x + 4, y, 16, 32);
}
bool DoorRenderer::action(const BLOCK_WDATA block, const int local_x, const int local_y, const int local_z, Chunk &c)
{
bool door_open = getBLOCKDATA(block) & DOOR_OPEN;
toggleState(block, local_x, local_y, local_z, c, door_open ? 0 : (DOOR_OPEN | DOOR_FORCE_OPEN));
return true;
}
void DoorRenderer::tick(const BLOCK_WDATA block, int local_x, int local_y, int local_z, Chunk &c)
{
//Only the bottom reacts
if(getBLOCKDATA(block) & DOOR_TOP)
return;
//A manually opened door doesn't change state by itself
if(getBLOCKDATA(block) & DOOR_FORCE_OPEN)
return;
bool redstone_state = c.isBlockPowered(local_x, local_y, local_z)
|| c.isBlockPowered(local_x, local_y + 1, local_z);
bool door_open = getBLOCKDATA(block) & DOOR_OPEN;
if(redstone_state == door_open)
return;
toggleState(block, local_x, local_y, local_z, c, redstone_state ? DOOR_OPEN : 0);
}
void DoorRenderer::addedBlock(const BLOCK_WDATA block, int local_x, int local_y, int local_z, Chunk &c)
{
if(getBLOCKDATA(block) & DOOR_TOP)
{
if(getBLOCK(c.getGlobalBlockRelative(local_x, local_y - 1, local_z)) != BLOCK_AIR)
c.setLocalBlock(local_x, local_y, local_z, BLOCK_AIR);
else
c.setGlobalBlockRelative(local_x, local_y - 1, local_z, getBLOCKWDATA(getBLOCK(block), getBLOCKDATA(block) ^ DOOR_TOP));
}
else
{
if(getBLOCK(c.getGlobalBlockRelative(local_x, local_y + 1, local_z)) != BLOCK_AIR)
c.setLocalBlock(local_x, local_y, local_z, BLOCK_AIR);
else
c.setGlobalBlockRelative(local_x, local_y + 1, local_z, getBLOCKWDATA(getBLOCK(block), getBLOCKDATA(block) ^ DOOR_TOP));
}
}
void DoorRenderer::removedBlock(const BLOCK_WDATA block, int local_x, int local_y, int local_z, Chunk &c)
{
if(getBLOCKDATA(block) & DOOR_TOP)
{
if(getBLOCK(c.getGlobalBlockRelative(local_x, local_y - 1, local_z)) == BLOCK_DOOR)
c.setGlobalBlockRelative(local_x, local_y - 1, local_z, BLOCK_AIR);
}
else
{
if(getBLOCK(c.getGlobalBlockRelative(local_x, local_y + 1, local_z)) == BLOCK_DOOR)
c.setGlobalBlockRelative(local_x, local_y + 1, local_z, BLOCK_AIR);
}
}
PowerState DoorRenderer::powersSide(const BLOCK_WDATA /*block*/, BLOCK_SIDE /*side*/)
{
return PowerState::NotPowered;
}
const char *DoorRenderer::getName(const BLOCK_WDATA /*block*/)
{
return "Door";
}
void DoorRenderer::toggleState(const BLOCK_WDATA block, int local_x, int local_y, int local_z, Chunk &c, const uint8_t open_state)
{
BLOCK_SIDE side = static_cast<BLOCK_SIDE>(getBLOCKDATA(block) & BLOCK_SIDE_BITS);
uint8_t new_data = door_side_map[side] | open_state | (getBLOCKDATA(block) & DOOR_TOP);
c.setLocalBlock(local_x, local_y, local_z, getBLOCKWDATA(getBLOCK(block), new_data));
//Change the other door part as well
if(getBLOCKDATA(block) & DOOR_TOP) //If top
c.setGlobalBlockRelative(local_x, local_y - 1, local_z, getBLOCKWDATA(getBLOCK(block), new_data ^ DOOR_TOP));
else
c.setGlobalBlockRelative(local_x, local_y + 1, local_z, getBLOCKWDATA(getBLOCK(block), new_data ^ DOOR_TOP));
}