-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBlockStructure.h
270 lines (213 loc) · 8 KB
/
BlockStructure.h
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
#ifndef BLOCKSTRUCTURE_H_
#define BLOCKSTRUCTURE_H_
#include <cstddef> //size_t
#include <cassert> //assert
#include <fstream> //ifstream
#include <string> //string
#include <stdexcept> //runtime_error
#include <iostream> //istream
#include "Block.h"
#include "Vector4.h"
#include "Matrix44.h"
using namespace std;
/**
* @brief This class models a structure of block objects.
* @see AbstractBlock
*/
class BlockStructure
{
public:
typedef size_t size_type;
private:
enum { x, y, z, w };
size_type height, rows, columns;
GLfloat blockSize;
Vector4 base;
Block**** blocks;
public:
BlockStructure(const string filePath, GLfloat blockSize = 1.0, const Vector4& base = Vector4(0.0, 0.0, 0.0, 1.0)) : height(0.0), rows(0.0), columns(0.0), blockSize(blockSize), base(base[x], base[y], base[z], 0.0), blocks(0)
{
assert(base[w] == 1.0);
filePath >> *this;
}
~BlockStructure()
{
for(size_type i = 0; i < height; i++)
{
for(size_type j = 0; j < rows; j++)
delete[] blocks[i][j];
delete[] blocks[i];
}
delete[] blocks;
}
/**
* Draws the BlockStructure
*/
void draw() const
{
for(size_type i = 0; i < height; i++)
for(size_type j = 0; j < rows; j++)
for(size_type k = 0; k < columns; k++)
if(hasBlock(i, j, k))
blocks[i][j][k] -> draw();
}
/**
* Draws a "Shadow Volume" for use with the stenciled shadow volume algorithm
* @param lightPosition the light source which determines how edges are extruded to form the shadow volume
*/
void drawShadowVolume(const Vector4& lightPosition) const
{
for(size_type i = 0; i < height; i++)
for(size_type j = 0; j < rows; j++)
for(size_type k = 0; k < columns; k++)
if(hasBlock(i, j, k))
blocks[i][j][k] -> drawShadowVolume(lightPosition);
}
/**
* Sets the state of a particular block to "touched."
* This method throws a runtime_error if a block does not exist at the specified location.
* @see hasBlock
* @param height the height of the block in the grid
* @param row the row of the block in the grid
* @param column the column of the block in the grid
*/
void touchBlock(size_type height, size_type row, size_type column)
{
if(!hasBlock(height, row, column))
throw runtime_error("A block does not exist at the specified location.");
assert(hasBlock(height, row, column));
blocks[height][row][column] -> touch();
}
/**
* @return true if a child of AbstractBlock exists at the specified location
* @see AbstractBlock
* @param height the height in the grid
* @param row the row in the grid
* @param column the column in the grid
*/
bool hasBlock(size_type height, size_type row, size_type column) const
{
return isInBounds(height, row, column) && blocks[height][row][column] != NULL;
}
//NOTE: Why don't we make a const Block& getBlock(size_type, size_type, size_type) method?
bool hasImpenetrableBlock(size_type height, size_type row, size_type column) const
{
return isInBounds(height, row, column) && blocks[height][row][column] != NULL && blocks[height][row][column] -> isImpenetrable();
}
bool hasTouchedBlock(size_type height, size_type row, size_type column)
{
return hasBlock(height, row, column) && blocks[height][row][column] -> hasBeenTouched();
}
const Block& getBlock(size_type height, size_type row, size_type column) const
{
assert(hasBlock(height, row, column));
return *blocks[height][row][column];
}
/**
* returns a vector containing the x, y, and z coordinates of the block with respect to the standard basis
*/
const Vector4 getBlockLocation(size_type height, size_type row, size_type column) const
{
if(!hasBlock(height, row, column))
throw runtime_error("A block does not exist at the specified location.");
//NOTE: WE SHOULD BE ABLE TO REPLACE THIS WITH A CALL TO A GETLOCATION METHOD THAT RESIDES WITHIN BLOCK
//NOTE: Need to stop computing this so many times
GLfloat upperLeftCornerX = base[x] - (columns / 2) * blockSize, upperLeftCornerZ = base[z] - (rows / 2) * blockSize;
if(columns % 2 == 0)
upperLeftCornerX += blockSize / 2.0;
if(rows % 2 == 0)
upperLeftCornerZ += blockSize / 2.0;
return Vector4( upperLeftCornerX + column * blockSize,
base[y] + blockSize / 2.0 + blockSize * height,
upperLeftCornerZ + row * blockSize,
1.0);
}
/**
* @return the size of the blocks that exist within the structure
*/
const GLfloat& getBlockSize() const { return blockSize; }
/**
* @return the number of levels occupied by blocks within the structure
*/
const size_type& getHeight() const { return height; }
/**
* @return the number of rows occupied by blocks within the structure
*/
const size_type& getRows() const { return rows; }
/**
* @return the number of columns occupied by blocks within the structure
*/
const size_type& getColumns() const { return columns; }
/**
* @return A positional vector describing the location at the center of the BlockStructure's base
*/
const Vector4& getBase() const { return base; }
friend void operator >> (const string filePath, BlockStructure& blockStructure)
{
ifstream in(filePath.c_str());
if(in.fail())
throw runtime_error("The specified file '" + string(filePath) + "' does not exist.");
cout << "file exists " << filePath << endl;
//Deallocate any existing blocks
for(size_type i = 0; i < blockStructure.height; i++)
{
for(size_type j = 0; j < blockStructure.rows; j++)
delete[] blockStructure.blocks[i][j];
delete[] blockStructure.blocks[i];
}
delete[] blockStructure.blocks;
Matrix44 blockOrientation;
GLfloat upperLeftCornerX, upperLeftCornerZ;
in >> blockStructure.height;
in >> blockStructure.rows;
in >> blockStructure.columns;
cout << "height " << blockStructure.height << endl;
blockStructure.blocks = new Block ***[blockStructure.height];
upperLeftCornerX = (blockStructure.columns / 2) * -blockStructure.blockSize;
upperLeftCornerZ = (blockStructure.rows / 2) * -blockStructure.blockSize;
if(blockStructure.columns % 2 == 0)
upperLeftCornerX += blockStructure.blockSize / 2.0;
if(blockStructure.rows % 2 == 0)
upperLeftCornerZ += blockStructure.blockSize / 2.0;
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glTranslatef(blockStructure.base[x], blockStructure.base[y], blockStructure.base[z]);
for(size_type i = 0; i < blockStructure.height; i++)
{
blockStructure.blocks[i] = new Block * *[blockStructure.rows];
for(size_type j = 0; j < blockStructure.rows; j++)
{
blockStructure.blocks[i][j] = new Block * [blockStructure.columns];
for(size_type k = 0; k < blockStructure.columns; k++)
{
glPushMatrix();
glTranslatef(upperLeftCornerX + k * blockStructure.blockSize, blockStructure.blockSize / 2.0 + blockStructure.blockSize * i, upperLeftCornerZ + j * blockStructure.blockSize);
glGetFloatv(GL_MODELVIEW_MATRIX, blockOrientation);
glPopMatrix();
char blockType;
in >> blockType;
switch(blockType)
{
case 'P':
blockStructure.blocks[i][j][k] = new Block(true, blockStructure.blockSize, blockOrientation);
break;
case 'I' : blockStructure.blocks[i][j][k] = new Block(false, blockStructure.blockSize, blockOrientation);
break;
default : blockStructure.blocks[i][j][k] = NULL;
}
}
}
}
glPopMatrix();
}
private:
/**
* @param height the height in the grid
* @param row the row in the grid
* @param column the column in the grid
* @return true if the location specified is within the space occupied by the BlockStructure
*/
bool isInBounds(size_type height, size_type row, size_type column) const { return height >= 0 && height < (this -> height) && row >= 0 && row < rows && column >= 0 && column < columns; }
};
#endif /*BLOCKSTRUCTURE_H_*/