Created
October 24, 2020 09:58
-
-
Save frakw/59f96577de7625f978598417a3f67a35 to your computer and use it in GitHub Desktop.
10/24 17:57
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/************************************************************************ | |
File: Maze.cpp | |
Author: | |
Stephen Chenney, schenney@cs.wisc.edu | |
Modifier | |
Yu-Chi Lai, yu-chi@cs.wisc.edu | |
Comment: | |
(c) 2001-2002 Stephen Chenney, University of Wisconsin at Madison | |
Class header file for Maze class. Manages the maze. | |
Platform: Visio Studio.Net 2003 (converted to 2005) | |
*************************************************************************/ | |
#include "Maze.h" | |
#include "all_cpp_std.h" | |
#include "all_fl_gl.h" | |
#include "all_glm.h" | |
#include "LineSeg.h" | |
#include <tuple> | |
#define square(x) ((x)*(x)) | |
//#define check_matrix | |
using namespace std; | |
const char Maze::X = 0; | |
const char Maze::Y = 1; | |
const char Maze::Z = 2; | |
const float Maze::BUFFER = 0.1f; | |
glm::mat4x4 global::model_view;//只能在一個CPP內初始化,其他CPP有include all_glm.h,就可存取projection | |
glm::mat4x4 global::projection;//只能在一個CPP內初始化,其他CPP有include all_glm.h,就可存取projection | |
void print_mat4x4(glm::mat4x4& m) { | |
for (int i = 0;i < 4;i++) { | |
for (int j = 0;j < 4;j++) { | |
std::cout << m[i][j] << ' '; | |
} | |
std::cout << std::endl; | |
} | |
} | |
bool cross_param(glm::vec4& result, glm::vec4& s1, glm::vec4& e1, glm::vec4& s2, glm::vec4& e2, bool se); | |
//********************************************************************** | |
// | |
// * Constructor for the maze exception | |
//====================================================================== | |
MazeException:: | |
MazeException(const char* m) | |
//====================================================================== | |
{ | |
message = new char[strlen(m) + 4]; | |
strcpy(message, m); | |
} | |
//********************************************************************** | |
// | |
// * Constructor to create the default maze | |
//====================================================================== | |
Maze:: | |
Maze(const int nx, const int ny, const float sx, const float sy) | |
//====================================================================== | |
{ | |
// Build the connectivity structure. | |
Build_Connectivity(nx, ny, sx, sy); | |
// Make edges transparent to create a maze. | |
Build_Maze(); | |
// Set the extents of the maze | |
Set_Extents(); | |
// Default values for the viewer. | |
viewer_posn[X] = viewer_posn[Y] = viewer_posn[Z] = 0.0; | |
viewer_dir = 0.0; | |
viewer_fov = 45.0; | |
// Always start on the 0th frame. | |
frame_num = 0; | |
} | |
//********************************************************************** | |
// | |
// * Construtor to read in precreated maze | |
//====================================================================== | |
Maze:: | |
Maze(const char* filename) | |
//====================================================================== | |
{ | |
char err_string[128]; | |
FILE* f; | |
int i; | |
// Open the file | |
if (!(f = fopen(filename, "r"))) | |
throw new MazeException("Maze: Couldn't open file"); | |
// Get the total number of vertices | |
if (fscanf(f, "%d", &num_vertices) != 1) | |
throw new MazeException("Maze: Couldn't read number of vertices"); | |
// Read in each vertices | |
vertices = new Vertex * [num_vertices]; | |
for (i = 0; i < num_vertices; i++) { | |
float x, y; | |
if (fscanf(f, "%g %g", &x, &y) != 2) { | |
sprintf(err_string, "Maze: Couldn't read vertex number %d", i); | |
throw new MazeException(err_string); | |
} | |
vertices[i] = new Vertex(i, x, y); | |
} | |
// Get the number of edges | |
if (fscanf(f, "%d", &num_edges) != 1) | |
throw new MazeException("Maze: Couldn't read number of edges"); | |
// read in all edges | |
edges = new Edge * [num_edges]; | |
for (i = 0; i < num_edges; i++) { | |
int vs, ve, cl, cr, o; | |
float r, g, b; | |
if (fscanf(f, "%d %d %d %d %d %g %g %g", | |
&vs, &ve, &cl, &cr, &o, &r, &g, &b) != 8) { | |
sprintf(err_string, "Maze: Couldn't read edge number %d", i); | |
throw new MazeException(err_string); | |
} | |
edges[i] = new Edge(i, vertices[vs], vertices[ve], r, g, b); | |
edges[i]->Add_Cell((Cell*)cl, Edge::LEFT); | |
edges[i]->Add_Cell((Cell*)cr, Edge::RIGHT); | |
edges[i]->opaque = o ? true : false; | |
} | |
// Read in the number of cells | |
if (fscanf(f, "%d", &num_cells) != 1) | |
throw new MazeException("Maze: Couldn't read number of cells"); | |
// Read in all cells | |
cells = new Cell * [num_cells]; | |
for (i = 0; i < num_cells; i++) { | |
int epx, epy, emx, emy; | |
if (fscanf(f, "%d %d %d %d", &epx, &epy, &emx, &emy) != 4) { | |
sprintf(err_string, "Maze: Couldn't read cell number %d", i); | |
throw new MazeException(err_string); | |
} | |
cells[i] = new Cell(i, epx >= 0 ? edges[epx] : NULL, | |
epy >= 0 ? edges[epy] : NULL, | |
emx >= 0 ? edges[emx] : NULL, | |
emy >= 0 ? edges[emy] : NULL); | |
if (cells[i]->edges[0]) { | |
if (cells[i]->edges[0]->neighbors[0] == (Cell*)i) | |
cells[i]->edges[0]->neighbors[0] = cells[i]; | |
else if (cells[i]->edges[0]->neighbors[1] == (Cell*)i) | |
cells[i]->edges[0]->neighbors[1] = cells[i]; | |
else { | |
sprintf(err_string, | |
"Maze: Cell %d not one of edge %d's neighbors", | |
i, cells[i]->edges[0]->index); | |
throw new MazeException(err_string); | |
} | |
} | |
if (cells[i]->edges[1]) { | |
if (cells[i]->edges[1]->neighbors[0] == (Cell*)i) | |
cells[i]->edges[1]->neighbors[0] = cells[i]; | |
else if (cells[i]->edges[1]->neighbors[1] == (Cell*)i) | |
cells[i]->edges[1]->neighbors[1] = cells[i]; | |
else { | |
sprintf(err_string, | |
"Maze: Cell %d not one of edge %d's neighbors", | |
i, cells[i]->edges[1]->index); | |
throw new MazeException(err_string); | |
} | |
} | |
if (cells[i]->edges[2]) { | |
if (cells[i]->edges[2]->neighbors[0] == (Cell*)i) | |
cells[i]->edges[2]->neighbors[0] = cells[i]; | |
else if (cells[i]->edges[2]->neighbors[1] == (Cell*)i) | |
cells[i]->edges[2]->neighbors[1] = cells[i]; | |
else { | |
sprintf(err_string, | |
"Maze: Cell %d not one of edge %d's neighbors", | |
i, cells[i]->edges[2]->index); | |
throw new MazeException(err_string); | |
} | |
} | |
if (cells[i]->edges[3]) { | |
if (cells[i]->edges[3]->neighbors[0] == (Cell*)i) | |
cells[i]->edges[3]->neighbors[0] = cells[i]; | |
else if (cells[i]->edges[3]->neighbors[1] == (Cell*)i) | |
cells[i]->edges[3]->neighbors[1] = cells[i]; | |
else { | |
sprintf(err_string, | |
"Maze: Cell %d not one of edge %d's neighbors", | |
i, cells[i]->edges[3]->index); | |
throw new MazeException(err_string); | |
} | |
} | |
} | |
if (fscanf(f, "%g %g %g %g %g", | |
&(viewer_posn[X]), &(viewer_posn[Y]), &(viewer_posn[Z]), | |
&(viewer_dir), &(viewer_fov)) != 5) | |
throw new MazeException("Maze: Error reading view information."); | |
// Some edges have no neighbor on one side, so be sure to set their | |
// pointers to NULL. (They were set at -1 by the save/load process.) | |
for (i = 0; i < num_edges; i++) { | |
if (edges[i]->neighbors[0] == (Cell*)-1) | |
edges[i]->neighbors[0] = NULL; | |
if (edges[i]->neighbors[1] == (Cell*)-1) | |
edges[i]->neighbors[1] = NULL; | |
} | |
fclose(f); | |
Set_Extents(); | |
// Figure out which cell the viewer is in, starting off by guessing the | |
// 0th cell. | |
Find_View_Cell(cells[0]); | |
frame_num = 0; | |
} | |
//********************************************************************** | |
// | |
// * Destructor must free all the memory allocated. | |
//====================================================================== | |
Maze:: | |
~Maze(void) | |
//====================================================================== | |
{ | |
int i; | |
for (i = 0; i < num_vertices; i++) | |
delete vertices[i]; | |
delete[] vertices; | |
for (i = 0; i < num_edges; i++) | |
delete edges[i]; | |
delete[] edges; | |
for (i = 0; i < num_cells; i++) | |
delete cells[i]; | |
delete[] cells; | |
} | |
//********************************************************************** | |
// | |
// * Randomly generate the edge's opaque and transparency for an empty maze | |
//====================================================================== | |
void Maze:: | |
Build_Connectivity(const int num_x, const int num_y, | |
const float sx, const float sy) | |
//====================================================================== | |
{ | |
int i, j, k; | |
int edge_i; | |
// Ugly code to allocate all the memory for a new maze and to associate | |
// edges with vertices and faces with edges. | |
// Allocate and position the vertices. | |
num_vertices = (num_x + 1) * (num_y + 1); | |
vertices = new Vertex * [num_vertices]; | |
k = 0; | |
for (i = 0; i < num_y + 1; i++) { | |
for (j = 0; j < num_x + 1; j++) { | |
vertices[k] = new Vertex(k, j * sx, i * sy); | |
k++; | |
} | |
} | |
// Allocate the edges, and associate them with their vertices. | |
// Edges in the x direction get the first num_x * ( num_y + 1 ) indices, | |
// edges in the y direction get the rest. | |
num_edges = (num_x + 1) * num_y + (num_y + 1) * num_x; | |
edges = new Edge * [num_edges]; | |
k = 0; | |
for (i = 0; i < num_y + 1; i++) { | |
int row = i * (num_x + 1); | |
for (j = 0; j < num_x; j++) { | |
int vs = row + j; | |
int ve = row + j + 1; | |
edges[k] = new Edge(k, vertices[vs], vertices[ve], | |
rand() / (float)RAND_MAX * 0.5f + 0.25f, | |
rand() / (float)RAND_MAX * 0.5f + 0.25f, | |
rand() / (float)RAND_MAX * 0.5f + 0.25f); | |
k++; | |
} | |
} | |
edge_i = k; | |
for (i = 0; i < num_y; i++) { | |
int row = i * (num_x + 1); | |
for (j = 0; j < num_x + 1; j++) { | |
int vs = row + j; | |
int ve = row + j + num_x + 1; | |
edges[k] = new Edge(k, vertices[vs], vertices[ve], | |
rand() / (float)RAND_MAX * 0.5f + 0.25f, | |
rand() / (float)RAND_MAX * 0.5f + 0.25f, | |
rand() / (float)RAND_MAX * 0.5f + 0.25f); | |
k++; | |
} | |
} | |
// Allocate the cells and associate them with their edges. | |
num_cells = num_x * num_y; | |
cells = new Cell * [num_cells]; | |
k = 0; | |
for (i = 0; i < num_y; i++) { | |
int row_x = i * (num_x + 1); | |
int row_y = i * num_x; | |
for (j = 0; j < num_x; j++) { | |
int px = edge_i + row_x + 1 + j; | |
int py = row_y + j + num_x; | |
int mx = edge_i + row_x + j; | |
int my = row_y + j; | |
cells[k] = new Cell(k, edges[px], edges[py], edges[mx], edges[my]); | |
edges[px]->Add_Cell(cells[k], Edge::LEFT); | |
edges[py]->Add_Cell(cells[k], Edge::RIGHT); | |
edges[mx]->Add_Cell(cells[k], Edge::RIGHT); | |
edges[my]->Add_Cell(cells[k], Edge::LEFT); | |
k++; | |
} | |
} | |
} | |
//********************************************************************** | |
// | |
// * Add edges from cell to the set that are available for removal to | |
// grow the maze. | |
//====================================================================== | |
static void | |
Add_To_Available(Cell* cell, int* available, int& num_available) | |
//====================================================================== | |
{ | |
int i, j; | |
// Add edges from cell to the set that are available for removal to | |
// grow the maze. | |
for (i = 0; i < 4; i++) { | |
Cell* neighbor = cell->edges[i]->Neighbor(cell); | |
if (neighbor && !neighbor->counter) { | |
int candidate = cell->edges[i]->index; | |
for (j = 0; j < num_available; j++) | |
if (candidate == available[j]) { | |
printf("Breaking early\n"); | |
break; | |
} | |
if (j == num_available) { | |
available[num_available] = candidate; | |
num_available++; | |
} | |
} | |
} | |
cell->counter = 1; | |
} | |
//********************************************************************** | |
// | |
// * Grow a maze by removing candidate edges until all the cells are | |
// connected. The edges are not actually removed, they are just made | |
// transparent. | |
//====================================================================== | |
void Maze:: | |
Build_Maze() | |
//====================================================================== | |
{ | |
Cell* to_expand; | |
int index; | |
int* available = new int[num_edges]; | |
int num_available = 0; | |
int num_visited; | |
int i; | |
srand(time(NULL)); | |
// Choose a random starting cell. | |
index = (int)floor((rand() / (float)RAND_MAX) * num_cells); | |
to_expand = cells[index]; | |
Add_To_Available(to_expand, available, num_available); | |
num_visited = 1; | |
// Join cells up by making edges opaque. | |
while (num_visited < num_cells && num_available > 0) { | |
int ei; | |
index = (int)floor((rand() / (float)RAND_MAX) * num_available); | |
to_expand = NULL; | |
ei = available[index]; | |
if (edges[ei]->neighbors[0] && | |
!edges[ei]->neighbors[0]->counter) | |
to_expand = edges[ei]->neighbors[0]; | |
else if (edges[ei]->neighbors[1] && | |
!edges[ei]->neighbors[1]->counter) | |
to_expand = edges[ei]->neighbors[1]; | |
if (to_expand) { | |
edges[ei]->opaque = false; | |
Add_To_Available(to_expand, available, num_available); | |
num_visited++; | |
} | |
available[index] = available[num_available - 1]; | |
num_available--; | |
} | |
for (i = 0; i < num_cells; i++) | |
cells[i]->counter = 0; | |
} | |
//********************************************************************** | |
// | |
// * Go through all the vertices looking for the minimum and maximum | |
// extents of the maze. | |
//====================================================================== | |
void Maze:: | |
Set_Extents(void) | |
//====================================================================== | |
{ | |
int i; | |
min_xp = vertices[0]->posn[Vertex::X]; | |
max_xp = vertices[0]->posn[Vertex::X]; | |
min_yp = vertices[0]->posn[Vertex::Y]; | |
max_yp = vertices[0]->posn[Vertex::Y]; | |
for (i = 1; i < num_vertices; i++) { | |
if (vertices[i]->posn[Vertex::X] > max_xp) | |
max_xp = vertices[i]->posn[Vertex::X]; | |
if (vertices[i]->posn[Vertex::X] < min_xp) | |
min_xp = vertices[i]->posn[Vertex::X]; | |
if (vertices[i]->posn[Vertex::Y] > max_yp) | |
max_yp = vertices[i]->posn[Vertex::Y]; | |
if (vertices[i]->posn[Vertex::Y] < min_yp) | |
min_yp = vertices[i]->posn[Vertex::Y]; | |
} | |
} | |
//********************************************************************** | |
// | |
// * Figure out which cell the view is in, using seed_cell as an | |
// initial guess. This procedure works by repeatedly checking | |
// whether the viewpoint is in the current cell. If it is, we're | |
// done. If not, Point_In_Cell returns in new_cell the next cell | |
// to test. The new cell is the one on the other side of an edge | |
// that the point is "outside" (meaning that it might be inside the | |
// new cell). | |
//====================================================================== | |
void Maze:: | |
Find_View_Cell(Cell* seed_cell) | |
//====================================================================== | |
{ | |
Cell* new_cell; | |
// | |
while (!(seed_cell->Point_In_Cell(viewer_posn[X], viewer_posn[Y], | |
viewer_posn[Z], new_cell))) { | |
if (new_cell == 0) { | |
// The viewer is outside the top or bottom of the maze. | |
throw new MazeException("Maze: View not in maze\n"); | |
} | |
seed_cell = new_cell; | |
} | |
view_cell = seed_cell; | |
} | |
//********************************************************************** | |
// | |
// * Move the viewer's position. This method will do collision detection | |
// between the viewer's location and the walls of the maze and prevent | |
// the viewer from passing through walls. | |
//====================================================================== | |
void Maze:: | |
Move_View_Posn(const float dx, const float dy, const float dz) | |
//====================================================================== | |
{ | |
Cell* new_cell; | |
float xs, ys, zs, xe, ye, ze; | |
// Move the viewer by the given amount. This does collision testing to | |
// prevent walking through walls. It also keeps track of which cells the | |
// viewer is in. | |
// Set up a line segment from the start to end points of the motion. | |
xs = viewer_posn[X]; | |
ys = viewer_posn[Y]; | |
zs = viewer_posn[Z]; | |
xe = xs + dx; | |
ye = ys + dy; | |
ze = zs + dz; | |
// Fix the z to keep it in the maze. | |
if (ze > 1.0f - BUFFER) | |
ze = 1.0f - BUFFER; | |
if (ze < BUFFER - 1.0f) | |
ze = BUFFER - 1.0f; | |
// Clip_To_Cell clips the motion segment to the view_cell if the | |
// segment intersects an opaque edge. If the segment intersects | |
// a transparent edge (through which it can pass), then it clips | |
// the motion segment so that it _starts_ at the transparent edge, | |
// and it returns the cell the viewer is entering. We keep going | |
// until Clip_To_Cell returns NULL, meaning we've done as much of | |
// the motion as is possible without passing through walls. | |
while ((new_cell = view_cell->Clip_To_Cell(xs, ys, xe, ye, BUFFER))) | |
view_cell = new_cell; | |
// The viewer is at the end of the motion segment, which may have | |
// been clipped. | |
viewer_posn[X] = xe; | |
viewer_posn[Y] = ye; | |
viewer_posn[Z] = ze; | |
} | |
//********************************************************************** | |
// | |
// * Set the viewer's location | |
//====================================================================== | |
void Maze:: | |
Set_View_Posn(float x, float y, float z) | |
//====================================================================== | |
{ | |
// First make sure it's in some cell. | |
// This assumes that the maze is rectangular. | |
if (x < min_xp + BUFFER) | |
x = min_xp + BUFFER; | |
if (x > max_xp - BUFFER) | |
x = max_xp - BUFFER; | |
if (y < min_yp + BUFFER) | |
y = min_yp + BUFFER; | |
if (y > max_yp - BUFFER) | |
y = max_yp - BUFFER; | |
if (z < -1.0f + BUFFER) | |
z = -1.0f + BUFFER; | |
if (z > 1.0f - BUFFER) | |
z = 1.0f - BUFFER; | |
viewer_posn[X] = x; | |
viewer_posn[Y] = y; | |
viewer_posn[Z] = z; | |
// Figure out which cell we're in. | |
Find_View_Cell(cells[0]); | |
} | |
//********************************************************************** | |
// | |
// * Set the angle in which the viewer is looking. | |
//====================================================================== | |
void Maze:: | |
Set_View_Dir(const float d) | |
//====================================================================== | |
{ | |
viewer_dir = d; | |
} | |
//********************************************************************** | |
// | |
// * Set the horizontal field of view. | |
//====================================================================== | |
void Maze:: | |
Set_View_FOV(const float f) | |
//====================================================================== | |
{ | |
viewer_fov = f; | |
} | |
//********************************************************************** | |
// | |
// * Draws the map view of the maze. It is passed the minimum and maximum | |
// corners of the window in which to draw. | |
//====================================================================== | |
void Maze:: | |
Draw_Map(int min_x, int min_y, int max_x, int max_y) | |
//====================================================================== | |
{ | |
int height; | |
float scale_x, scale_y, scale; | |
int i; | |
// Figure out scaling factors and the effective height of the window. | |
scale_x = (max_x - min_x - 10) / (max_xp - min_xp); | |
scale_y = (max_y - min_y - 10) / (max_yp - min_yp); | |
scale = scale_x > scale_y ? scale_y : scale_x; | |
height = (int)ceil(scale * (max_yp - min_yp)); | |
min_x += 5; | |
min_y += 5; | |
// Draw all the opaque edges. | |
for (i = 0; i < num_edges; i++) | |
if (edges[i]->opaque) { | |
float x1, y1, x2, y2; | |
x1 = edges[i]->endpoints[Edge::START]->posn[Vertex::X]; | |
y1 = edges[i]->endpoints[Edge::START]->posn[Vertex::Y]; | |
x2 = edges[i]->endpoints[Edge::END]->posn[Vertex::X]; | |
y2 = edges[i]->endpoints[Edge::END]->posn[Vertex::Y]; | |
fl_color((unsigned char)floor(edges[i]->color[0] * 255.0), | |
(unsigned char)floor(edges[i]->color[1] * 255.0), | |
(unsigned char)floor(edges[i]->color[2] * 255.0)); | |
fl_line_style(FL_SOLID); | |
fl_line(min_x + (int)floor((x1 - min_xp) * scale), | |
min_y + height - (int)floor((y1 - min_yp) * scale), | |
min_x + (int)floor((x2 - min_xp) * scale), | |
min_y + height - (int)floor((y2 - min_yp) * scale)); | |
} | |
} | |
void Frustum(float* matrix, float left, float right, float bottom, float top, | |
float znear, float zfar); | |
// Matrix will receive the calculated perspective matrix. | |
// You would have to upload to your shader | |
// or use glLoadMatrixf if you aren't using shaders. | |
void Perspective(float fovyInDegrees, float aspectRatio, | |
float znear, float zfar) | |
{ | |
float matrix[16]; | |
float ymax, xmax; | |
float temp, temp2, temp3, temp4; | |
ymax = znear * tanf(fovyInDegrees * M_PI / 360.0); | |
xmax = ymax * aspectRatio; | |
Frustum(matrix, -xmax, xmax, -ymax, ymax, znear, zfar); | |
#ifdef check_matrix | |
glMultMatrixf(matrix);//乘上最上面的矩陣並儲存 loadmatrix則是直接取代 | |
#else | |
global::projection = glm::make_mat4(matrix); | |
#endif // check_matrix | |
} | |
void Frustum(float* matrix, float left, float right, float bottom, float top, | |
float znear, float zfar) | |
{ | |
float temp, temp2, temp3, temp4; | |
temp = 2.0 * znear; | |
temp2 = right - left; | |
temp3 = top - bottom; | |
temp4 = zfar - znear; | |
matrix[0] = temp / temp2; | |
matrix[1] = 0.0; | |
matrix[2] = 0.0; | |
matrix[3] = 0.0; | |
matrix[4] = 0.0; | |
matrix[5] = temp / temp3; | |
matrix[6] = 0.0; | |
matrix[7] = 0.0; | |
matrix[8] = (right + left) / temp2; | |
matrix[9] = (top + bottom) / temp3; | |
matrix[10] = (-zfar - znear) / temp4; | |
matrix[11] = -1.0; | |
matrix[12] = 0.0; | |
matrix[13] = 0.0; | |
matrix[14] = (-temp * zfar) / temp4; | |
matrix[15] = 0.0; | |
} | |
void NormalizeVector(float x[3]) { | |
float Norm = sqrt(square(x[0]) + square(x[1]) + square(x[2])); | |
x[0] /= Norm; | |
x[1] /= Norm; | |
x[2] /= Norm; | |
} | |
void ComputeNormalOfPlane(float result[3], float A[3], float B[3]) { | |
result[0] = A[1] * B[2] - A[2] * B[1]; | |
result[1] = A[2] * B[0] - A[0] * B[2]; | |
result[2] = A[0] * B[1] - A[1] * B[0]; | |
} | |
void LookAt(float eyePosition3DX, float eyePosition3DY, float eyePosition3DZ, | |
float center3DX, float center3DY, float center3DZ, | |
float upVector3DX, float upVector3DY, float upVector3DZ) | |
{ | |
float forward[3], side[3], up[3]; | |
float matrix2[16]; | |
// -------------------- | |
forward[0] = center3DX - eyePosition3DX; | |
forward[1] = center3DY - eyePosition3DY; | |
forward[2] = center3DZ - eyePosition3DZ; | |
NormalizeVector(forward); | |
// -------------------- | |
// Side = forward x up 向量外積 | |
float tmp[3] = { upVector3DX ,upVector3DY, upVector3DZ }; | |
ComputeNormalOfPlane(side, forward, tmp); | |
NormalizeVector(side); | |
//-------------------- | |
// Recompute up as: up = side x forward 向量外積 | |
ComputeNormalOfPlane(up, side, forward); | |
// -------------------- | |
matrix2[0] = side[0]; | |
matrix2[4] = side[1]; | |
matrix2[8] = side[2]; | |
matrix2[12] = 0.0; | |
// -------------------- | |
matrix2[1] = up[0]; | |
matrix2[5] = up[1]; | |
matrix2[9] = up[2]; | |
matrix2[13] = 0.0; | |
// -------------------- | |
matrix2[2] = -forward[0]; | |
matrix2[6] = -forward[1]; | |
matrix2[10] = -forward[2]; | |
matrix2[14] = 0.0; | |
// -------------------- | |
matrix2[3] = matrix2[7] = matrix2[11] = 0.0; | |
matrix2[15] = 1.0; | |
// -------------------- | |
#ifdef check_matrix | |
glMultMatrixf(matrix2);//乘上最上面的矩陣並儲存 loadmatrix則是直接取代 | |
glTranslatef(-eyePosition3DX, -eyePosition3DY, -eyePosition3DZ); | |
#else | |
global::model_view = glm::make_mat4(matrix2); | |
global::model_view = glm::translate(global::model_view, glm::vec3(-eyePosition3DX, -eyePosition3DY, -eyePosition3DZ)); | |
#endif // check_matrix | |
} | |
inline float Det(float a, float b, float c, float d) | |
{ | |
return a * d - b * c; | |
} | |
///Calculate intersection of two lines. | |
///\return true if found, false if not found or error | |
bool LineLineIntersect(float x1, float y1, //Line 1 start | |
float x2, float y2, //Line 1 end | |
float x3, float y3, //Line 2 start | |
float x4, float y4, //Line 2 end | |
double& ixOut, double& iyOut) //Output | |
{ | |
//http://mathworld.wolfram.com/Line-LineIntersection.html | |
double detL1 = Det(x1, y1, x2, y2); | |
double detL2 = Det(x3, y3, x4, y4); | |
double x1mx2 = x1 - x2; | |
double x3mx4 = x3 - x4; | |
double y1my2 = y1 - y2; | |
double y3my4 = y3 - y4; | |
double xnom = Det(detL1, x1mx2, detL2, x3mx4); | |
double ynom = Det(detL1, y1my2, detL2, y3my4); | |
double denom = Det(x1mx2, y1my2, x3mx4, y3my4); | |
if (denom == 0.0)//Lines don't seem to cross | |
{ | |
ixOut = NAN; | |
iyOut = NAN; | |
return false; | |
} | |
ixOut = xnom / denom; | |
iyOut = ynom / denom; | |
if (!isfinite(ixOut) || !isfinite(iyOut)) //Probably a numerical issue | |
return false; | |
return true; //All OK | |
} | |
//********************************************************************** | |
// | |
// * Draws the first-person view of the maze. It is passed the focal distance. | |
// THIS IS THE FUINCTION YOU SHOULD MODIFY. | |
//====================================================================== | |
void Maze:: | |
Draw_View(const float focal_dist, const float aspect) | |
//====================================================================== | |
{ | |
frame_num++; | |
float my_near = 0.01; | |
float my_far = 200.0f; | |
glMatrixMode(GL_PROJECTION); | |
glLoadIdentity(); | |
glMatrixMode(GL_MODELVIEW); | |
glLoadIdentity(); | |
global::model_view = glm::mat4(1);//填1才會是identity matrix | |
global::projection = glm::mat4(1);//填1才會是identity matrix | |
glClear(GL_DEPTH_BUFFER_BIT); | |
Perspective(viewer_fov, aspect, my_near, my_far); | |
float viewer_pos[3] = {viewer_posn[Maze::Y], 0.0f, viewer_posn[Maze::X] }; | |
LookAt(viewer_pos[Maze::X], viewer_pos[Maze::Y], viewer_pos[Maze::Z], | |
viewer_pos[Maze::X] + sin(Maze::To_Radians(viewer_dir)), | |
viewer_pos[Maze::Y], | |
viewer_pos[Maze::Z] + cos(Maze::To_Radians(viewer_dir)), | |
0.0, 1.0, 0.0); | |
//print_mat4x4(global::projection); | |
//print_mat4x4(global::model_view); | |
#ifdef check_matrix | |
glEnable(GL_DEPTH_TEST); | |
for (int i = 0; i < (int)this->num_edges; i++) { | |
float edge_start[2] = { | |
this->edges[i]->endpoints[Edge::START]->posn[Vertex::X], | |
this->edges[i]->endpoints[Edge::START]->posn[Vertex::Y] }; | |
float edge_end[2] = { | |
this->edges[i]->endpoints[Edge::END]->posn[Vertex::X], | |
this->edges[i]->endpoints[Edge::END]->posn[Vertex::Y] }; | |
float color[3] = { this->edges[i]->color[0], this->edges[i]->color[1], this->edges[i]->color[2] }; | |
if (this->edges[i]->opaque) | |
matrix_test_draw_wall(edge_start, edge_end, color); | |
} | |
glMatrixMode(GL_PROJECTION);//回歸單位矩陣,避免被上次影響 | |
glLoadIdentity(); | |
glMatrixMode(GL_MODELVIEW); | |
glLoadIdentity(); | |
#else | |
cout << viewer_fov; | |
frustum view(Vertex(my_near * tan(To_Radians(viewer_fov * 0.5)), my_near), Vertex(-my_near * tan(To_Radians(viewer_fov * 0.5)), my_near), Vertex(-my_far * tan(To_Radians(viewer_fov * 0.5)), my_far), Vertex(my_far * tan(To_Radians(viewer_fov * 0.5)), my_far)); | |
//frustum view(Vertex(my_near*tan(viewer_fov*0.5), my_near), Vertex(-my_near * tan(viewer_fov * 0.5), my_near), Vertex(-my_far * tan(viewer_fov * 0.5), my_far), Vertex(my_far * tan(viewer_fov * 0.5), my_far)); | |
//draw_cell(camera_cell_index, view); | |
for (int i = 0;i < num_edges;i++) { | |
if (!edges[i]->opaque) continue; | |
LineSeg edge_line(edges[i]); | |
glm::vec4 start(edge_line.start[1], 1.0f, edge_line.start[0], 1.0f), end(edge_line.end[1], 1.0f, edge_line.end[0], 1.0f); | |
start =/* global::projection* */global::model_view * start; | |
end = /*global::projection **/ global::model_view * end; | |
if (start[3] < 0 || end[3] < 0) { | |
} | |
bool draw_edge = true; | |
//if() | |
//start /= start[3]; | |
//end /= end[3]; | |
for (int j = 0;j < 4;j++) {//跑視錐的四個邊 | |
char s = view.which_edge(j).Point_Side(start[0], start[2]); | |
char e = view.which_edge(j).Point_Side(end[0], end[2]); | |
if (s == Edge::LEFT && e == Edge::LEFT) | |
{ | |
//在視錐外 | |
//continue; | |
cout << "out out" << endl; | |
draw_edge = false; | |
break; | |
} | |
else if (s == Edge::RIGHT && e == Edge::LEFT) | |
{ | |
//pair<glm::vec4, glm::vec4> frustum_line = view.pair_vec4_which_side(j); | |
//if(cross_param(end, start, end, frustum_line.first, frustum_line.second, false)) | |
float percent = view.which_line(j).Cross_Param(LineSeg(start,end)); | |
if (percent < 1.0e20f && percent>0 && percent < 1) { | |
draw_edge = true; | |
end[0] = start[0] + (end[0] - start[0]) * percent; | |
end[2] = start[2] + (end[2] - start[2]) * percent; | |
} | |
cout << "cut end" << endl; | |
} | |
else if (s == Edge::LEFT && e == Edge::RIGHT) | |
{ | |
//pair<glm::vec4, glm::vec4> frustum_line = view.pair_vec4_which_side(j); | |
//if(cross_param(start,start, end, frustum_line.first, frustum_line.second, true))draw_edge = true; | |
float percent = view.which_line(j).Cross_Param(LineSeg(start, end)); | |
if (percent < 1.0e20f && percent>0 && percent < 1) { | |
draw_edge = true; | |
start[0] = start[0] + (end[0] - start[0]) * percent; | |
start[2] = start[2] + (end[2] - start[2]) * percent; | |
} | |
cout << "cut start" << endl; | |
} | |
//else { | |
// draw_edge = true; | |
//} | |
} | |
//if (!draw_edge) continue; | |
start = global::projection * start; | |
end = global::projection * end; | |
if (/*start[2] < 0 || end[2] < 0 ||*/ start[3] <0 || end[3] <0) continue; | |
if (edges[i]->opaque) | |
{ | |
//start /= abs(start[3]); | |
//end /= abs(end[3]); | |
start /=start[3]; | |
end /= end[3]; | |
glBegin(GL_POLYGON); | |
glColor3fv(edges[i]->color); | |
//cout << start[0] << ' ' << start[1] << endl; | |
//cout << end[0] << ' ' << end[1] << endl; | |
cout << "----------------------------" << endl; | |
//if (start[0] < -1) { | |
// | |
//} | |
//else if (start[0] > 1) { | |
// | |
//} | |
//if (start[1] < -1) start[1] = -1; | |
//else if (start[1] > 1) start[1] = 1; | |
//if (end[0] < -1) end[0] = -1; | |
//else if (end[0] > 1) end[0] = 1; | |
//if (end[1] < -1) end[1] = -1; | |
//else if (end[1] > 1) end[1] = 1; | |
glVertex2f(start[0], start[1]); | |
glVertex2f(end[0], end[1]); | |
glVertex2f(end[0], -end[1]); | |
glVertex2f(start[0], -start[1]); | |
glEnd(); | |
} | |
} | |
#endif | |
} | |
void Maze:: | |
matrix_test_draw_wall(const float start[2], const float end[2], const float color[3]) { | |
float edge0[3] = { start[Y], 0.0f, start[X] }; | |
float edge1[3] = { end[Y], 0.0f, end[X] }; | |
glBegin(GL_POLYGON); | |
glColor3fv(color); | |
glVertex4f(edge0[X], 1.0f, edge0[Z], 1); | |
glVertex4f(edge1[X], 1.0f, edge1[Z], 1); | |
glVertex4f(edge1[X], -1.0f, edge1[Z], 1); | |
glVertex4f(edge0[X], -1.0f, edge0[Z], 1); | |
glEnd(); | |
} | |
//char side(float ax, float ay, float bx, float by, float xp, float yp){ | |
// float d = (xp - ax) * (by - ay) - (yp - ay) * (bx - ax); | |
// return d < 0 ? Edge::LEFT : Edge::RIGHT; | |
//} | |
bool cross_param(glm::vec4& result,glm::vec4& s1, glm::vec4& e1,glm::vec4& s2, glm::vec4& e2,bool se) { | |
float dx1, dy1, dx2, dy2; | |
float denom, s; | |
// This computation comes from writing each segment in parametric form, | |
// and solving a simulataneous equation to determine the parameter | |
// value of the intersection point on this LineSeg. | |
dx1 = e2[0] - s2[0]; | |
dy1 = e2[2] - s2[2]; | |
dx2 = e1[0] - s1[0]; | |
dy2 = e1[2] - s1[2]; | |
if ((denom = dx2 * dy1 - dy2 * dx1) == 0.0) return false; | |
// Parallel segments. | |
s = (s2[0] - s1[0]) * dy1 - (s2[2] - s1[2]) * dx1; | |
float percent = s / denom; | |
if (se) { | |
result = glm::vec4(s1[0] + percent * (e1[0] - s1[0]), s1[1], s1[2] + percent * (e1[2] - s1[2]), s1[3]); | |
} | |
else { | |
result = glm::vec4(s1[0] + percent * (e1[0] - s1[0]), e1[1], s1[2] + percent * (e1[2] - s1[2]), e1[3]); | |
} | |
return true; | |
} | |
void Maze::Draw_Wall(float sx, float sy, float ex, float ey, float rr, float gg, float bb) { | |
} | |
void Maze::draw_cell(int camera_cell_index,frustum view) { | |
//Cell* now = cells[camera_cell_index]; | |
//for (int i = 0;i < 4;i++) {//跑四面牆 | |
// if (!now->edges[i]->opaque) continue; | |
// LineSeg edge_line(now->edges[i]); | |
// glm::vec4 start(edge_line.start[1], 1.0f, edge_line.start[0], 1.0f), end(edge_line.end[1], 1.0f, edge_line.end[0], 1.0f); | |
// start = global::model_view * start; | |
// end = global::model_view * end; | |
// bool draw_edge = false; | |
// for (int j = 0;j < 4;j++) {//跑視錐的四個邊 | |
// char s = view.which_side(j).Point_Side(start[0],start[2]); | |
// char e = view.which_side(j).Point_Side(end[0], end[2]); | |
// if (s == Edge::LEFT && e == Edge::LEFT) | |
// { | |
// //在視錐外 | |
// continue; | |
// } | |
// else if (s == Edge::RIGHT && e == Edge::LEFT) | |
// { | |
// draw_edge = true; | |
// pair<glm::vec4, glm::vec4> frustum_line = view.pair_vec4_which_side(j); | |
// end = cross_param(frustum_line.first, frustum_line.second, start, end); | |
// } | |
// else if (s == Edge::LEFT && e == Edge::RIGHT) | |
// { | |
// draw_edge = true; | |
// pair<glm::vec4, glm::vec4> frustum_line = view.pair_vec4_which_side(j); | |
// start = cross_param(frustum_line.first, frustum_line.second, start, end); | |
// } | |
// } | |
// //if (!draw_edge) continue; | |
// start = global::projection * start; | |
// end = global::projection * end; | |
// if (now->edges[i]->opaque) | |
// { | |
// //start /= start[3]; | |
// //end /= end[3]; | |
// glBegin(GL_POLYGON); | |
// glColor3fv(now->edges[i]->color); | |
// cout << start[0] << ' ' << start[1] << endl; | |
// cout << end[0] << ' ' << end[1] << endl; | |
// cout << "----------------------------"<<endl; | |
// glVertex2f(start[0]/start[3], start[1] / start[3]); | |
// glVertex2f(end[0] / end[3], end[1]/end[3]); | |
// glVertex2f(end[0]/ end[3], -end[1]/ end[3]); | |
// glVertex2f(start[0] / start[3], -start[1] / start[3]); | |
// glEnd(); | |
// } | |
//} | |
//Cell* now = cells[camera_cell_index]; | |
//vector<tuple<glm::vec4, glm::vec4, float*> > all_draw; | |
//for (int i = 0;i < 4;i++) { | |
// if (!now->edges[i]->opaque) continue; | |
// all_draw.push_back(make_tuple( | |
// glm::vec4(now->edges[i]->endpoints[Edge::START]->posn[Y], 1.0f, now->edges[i]->endpoints[Edge::START]->posn[X], 1.0f), | |
// glm::vec4(now->edges[i]->endpoints[Edge::END]->posn[Y], 1.0f, now->edges[i]->endpoints[Edge::END]->posn[X], 1.0f), now->edges[i]->color)); | |
// get<0>(all_draw.back()) = global::model_view * get<0>(all_draw.back()); | |
// get<1>(all_draw.back()) = global::model_view * get<1>(all_draw.back()); | |
//} | |
//for (int i = 0;i < 4;i++) {//跑視錐的四個邊 | |
// for (int j = 0;j < all_draw.size();j++) {//跑四面牆 | |
// char s = view.which_side(i).Point_Side(get<0>(all_draw[j])[0], get<0>(all_draw[j])[2]); | |
// char e = view.which_side(i).Point_Side(get<1>(all_draw[j])[0], get<1>(all_draw[j])[2]); | |
// if (s == Edge::LEFT && e == Edge::LEFT) | |
// { | |
// //在視錐外 | |
// all_draw.erase(all_draw.begin()+j); | |
// j--; | |
// continue; | |
// } | |
// else if (s == Edge::RIGHT && e == Edge::LEFT) | |
// { | |
// pair<glm::vec4, glm::vec4> frustum_line = view.pair_vec4_which_side(i); | |
// get<1>(all_draw[j]) = cross_param(frustum_line.first, frustum_line.second, get<0>(all_draw[j]), get<1>(all_draw[j])); | |
// } | |
// else if (s == Edge::LEFT && e == Edge::RIGHT) | |
// { | |
// pair<glm::vec4, glm::vec4> frustum_line = view.pair_vec4_which_side(i); | |
// get<0>(all_draw[j]) = cross_param(frustum_line.first, frustum_line.second, get<0>(all_draw[j]), get<1>(all_draw[j])); | |
// } | |
// } | |
// //if (!draw_edge) continue; | |
//} | |
//for (int j = 0;j < all_draw.size();j++) { | |
// get<0>(all_draw[j]) = global::projection * get<0>(all_draw[j]); | |
// get<1>(all_draw[j]) = global::projection * get<1>(all_draw[j]); | |
// //start /= start[3]; | |
// //end /= end[3]; | |
// glBegin(GL_POLYGON); | |
// glColor3fv(get<2>(all_draw[j])); | |
// cout << get<0>(all_draw[j])[0] << ' ' << get<0>(all_draw[j])[1] << endl; | |
// cout << get<1>(all_draw[j])[0] << ' ' << get<1>(all_draw[j])[1] << endl; | |
// cout << "----------------------------" << endl; | |
// glVertex2f(get<0>(all_draw[j])[0] / get<0>(all_draw[j])[3], get<0>(all_draw[j])[1] / get<0>(all_draw[j])[3]); | |
// glVertex2f(get<1>(all_draw[j])[0] / get<1>(all_draw[j])[3], get<1>(all_draw[j])[1] / get<1>(all_draw[j])[3]); | |
// glVertex2f(get<1>(all_draw[j])[0] / get<1>(all_draw[j])[3], -get<1>(all_draw[j])[1] / get<1>(all_draw[j])[3]); | |
// glVertex2f(get<0>(all_draw[j])[0] / get<0>(all_draw[j])[3], -get<0>(all_draw[j])[1] / get<0>(all_draw[j])[3]); | |
// glEnd(); | |
//} | |
} | |
//********************************************************************** | |
// | |
// * Draws the frustum on the map view of the maze. It is passed the | |
// minimum and maximum corners of the window in which to draw. | |
//====================================================================== | |
void Maze:: | |
Draw_Frustum(int min_x, int min_y, int max_x, int max_y) | |
//====================================================================== | |
{ | |
int height; | |
float scale_x, scale_y, scale; | |
float view_x, view_y; | |
// Draws the view frustum in the map. Sets up all the same viewing | |
// parameters as draw(). | |
scale_x = (max_x - min_x - 10) / (max_xp - min_xp); | |
scale_y = (max_y - min_y - 10) / (max_yp - min_yp); | |
scale = scale_x > scale_y ? scale_y : scale_x; | |
height = (int)ceil(scale * (max_yp - min_yp)); | |
min_x += 5; | |
min_y += 5; | |
view_x = (viewer_posn[X] - min_xp) * scale; | |
view_y = (viewer_posn[Y] - min_yp) * scale; | |
fl_line(min_x + (int)floor(view_x + | |
cos(To_Radians(viewer_dir + viewer_fov / 2.0)) * scale), | |
min_y + height - | |
(int)floor(view_y + | |
sin(To_Radians(viewer_dir + viewer_fov / 2.0)) * | |
scale), | |
min_x + (int)floor(view_x), | |
min_y + height - (int)floor(view_y)); | |
fl_line(min_x + (int)floor(view_x + | |
cos(To_Radians(viewer_dir - viewer_fov / 2.0)) * | |
scale), | |
min_y + height - | |
(int)floor(view_y + sin(To_Radians(viewer_dir - viewer_fov / 2.0)) * | |
scale), | |
min_x + (int)floor(view_x), | |
min_y + height - (int)floor(view_y)); | |
} | |
//********************************************************************** | |
// | |
// * Draws the viewer's cell and its neighbors in the map view of the maze. | |
// It is passed the minimum and maximum corners of the window in which | |
// to draw. | |
//====================================================================== | |
void Maze:: | |
Draw_Neighbors(int min_x, int min_y, int max_x, int max_y) | |
//====================================================================== | |
{ | |
int height; | |
float scale_x, scale_y, scale; | |
int i, j; | |
// Draws the view cell and its neighbors in the map. This works | |
// by drawing just the neighbor's edges if there is a neighbor, | |
// otherwise drawing the edge. Every edge is shared, so drawing the | |
// neighbors' edges also draws the view cell's edges. | |
scale_x = (max_x - min_x - 10) / (max_xp - min_xp); | |
scale_y = (max_y - min_y - 10) / (max_yp - min_yp); | |
scale = scale_x > scale_y ? scale_y : scale_x; | |
height = (int)ceil(scale * (max_yp - min_yp)); | |
min_x += 5; | |
min_y += 5; | |
for (i = 0; i < 4; i++) { | |
Cell* neighbor = view_cell->edges[i]->Neighbor(view_cell); | |
if (neighbor) { | |
for (j = 0; j < 4; j++) { | |
Edge* e = neighbor->edges[j]; | |
if (e->opaque) { | |
float x1, y1, x2, y2; | |
x1 = e->endpoints[Edge::START]->posn[Vertex::X]; | |
y1 = e->endpoints[Edge::START]->posn[Vertex::Y]; | |
x2 = e->endpoints[Edge::END]->posn[Vertex::X]; | |
y2 = e->endpoints[Edge::END]->posn[Vertex::Y]; | |
fl_color((unsigned char)floor(e->color[0] * 255.0), | |
(unsigned char)floor(e->color[1] * 255.0), | |
(unsigned char)floor(e->color[2] * 255.0)); | |
fl_line_style(FL_SOLID); | |
fl_line(min_x + (int)floor((x1 - min_xp) * scale), | |
min_y + height - (int)floor((y1 - min_yp) * scale), | |
min_x + (int)floor((x2 - min_xp) * scale), | |
min_y + height - (int)floor((y2 - min_yp) * scale)); | |
} | |
} | |
} | |
else { | |
Edge* e = view_cell->edges[i]; | |
if (e->opaque) { | |
float x1, y1, x2, y2; | |
x1 = e->endpoints[Edge::START]->posn[Vertex::X]; | |
y1 = e->endpoints[Edge::START]->posn[Vertex::Y]; | |
x2 = e->endpoints[Edge::END]->posn[Vertex::X]; | |
y2 = e->endpoints[Edge::END]->posn[Vertex::Y]; | |
fl_color((unsigned char)floor(e->color[0] * 255.0), | |
(unsigned char)floor(e->color[1] * 255.0), | |
(unsigned char)floor(e->color[2] * 255.0)); | |
fl_line_style(FL_SOLID); | |
fl_line(min_x + (int)floor((x1 - min_xp) * scale), | |
min_y + height - (int)floor((y1 - min_yp) * scale), | |
min_x + (int)floor((x2 - min_xp) * scale), | |
min_y + height - (int)floor((y2 - min_yp) * scale)); | |
} | |
} | |
} | |
} | |
//********************************************************************** | |
// | |
// * Save the maze to a file of the given name. | |
//====================================================================== | |
bool Maze:: | |
Save(const char* filename) | |
//====================================================================== | |
{ | |
FILE* f = fopen(filename, "w"); | |
int i; | |
// Dump everything to a file of the given name. Returns false if it | |
// couldn't open the file. True otherwise. | |
if (!f) { | |
return false; | |
} | |
fprintf(f, "%d\n", num_vertices); | |
for (i = 0; i < num_vertices; i++) | |
fprintf(f, "%g %g\n", vertices[i]->posn[Vertex::X], | |
vertices[i]->posn[Vertex::Y]); | |
fprintf(f, "%d\n", num_edges); | |
for (i = 0; i < num_edges; i++) | |
fprintf(f, "%d %d %d %d %d %g %g %g\n", | |
edges[i]->endpoints[Edge::START]->index, | |
edges[i]->endpoints[Edge::END]->index, | |
edges[i]->neighbors[Edge::LEFT] ? | |
edges[i]->neighbors[Edge::LEFT]->index : -1, | |
edges[i]->neighbors[Edge::RIGHT] ? | |
edges[i]->neighbors[Edge::RIGHT]->index : -1, | |
edges[i]->opaque ? 1 : 0, | |
edges[i]->color[0], edges[i]->color[1], edges[i]->color[2]); | |
fprintf(f, "%d\n", num_cells); | |
for (i = 0; i < num_cells; i++) | |
fprintf(f, "%d %d %d %d\n", | |
cells[i]->edges[0] ? cells[i]->edges[0]->index : -1, | |
cells[i]->edges[1] ? cells[i]->edges[1]->index : -1, | |
cells[i]->edges[2] ? cells[i]->edges[2]->index : -1, | |
cells[i]->edges[3] ? cells[i]->edges[3]->index : -1); | |
fprintf(f, "%g %g %g %g %g\n", | |
viewer_posn[X], viewer_posn[Y], viewer_posn[Z], | |
viewer_dir, viewer_fov); | |
fclose(f); | |
return true; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment