/
board.c
216 lines (174 loc) · 6.16 KB
/
board.c
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
// CMPE-220, Winter 2007, final project
// Knight's Tour in Cg
// Suraj Kurapati
#include "fbo.c"
#define board__area (board__width * board__width)
GLuint board__width;
GLuint board__computeTexture;
GLuint board__displayTexture;
GLuint board__gridDisplayList;
unsigned long board__numCycles;
float* board__data;
void board_init(const GLuint aWidth, const GLuint aKnightRow, const GLuint aKnightCol)
{
board__width = aWidth;
// number of cycles it takes to finish the computation:
//
// (3 cycles per knight) * (number of knights)
//
// the -1 is because the initial knight is not determined
// at runtime, so we save one cycle of processing.
//
// see EXPORT_DELAY in the "naive.cg.erb" file for details.
//
board__numCycles = 3 * board__area;
printf("\nThe tour should take %lu cycles to complete.\n", board__numCycles);
// generate the board data
if((board__data = (float*)malloc(4*board__area*sizeof(float))) == NULL)
{
printf("\n*** out of memory allocating board__data ***\n");
exit(2);
}
unsigned addr = 0;
for(unsigned row = 0; row < board__width; row++) {
for (unsigned col = 0; col < board__width; col++) {
// red channel
board__data[addr++] = (
// set initial position of knight
row == aKnightRow &&
col == aKnightCol
) ? 1 : 0;
// green channel
board__data[addr++] = 0;
// blue channel
board__data[addr++] = 0;
// alpha channel
board__data[addr++] = 8; // 8 is MOVE_NONE (see naive.cg.erb for details); all cells should have next move = NONE initially, because only the knight makes the "next move" desicison at *runtime*
}
}
// Generate, set up, and bind the texture
texture_new(&board__computeTexture, board__width, board__width, GL_TEXTURE_RECTANGLE_ARB, GL_RGBA32F_ARB, NULL);
// initialize the FBO
fbo_init(board__width, board__width);
// Attach the texture to the framebuffer object
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, board__computeTexture, 0);
// Check the FBO for completeness
fbo_check();
// generate texture for board display
texture_new(&board__displayTexture, board__width, board__width, GL_TEXTURE_2D, GL_RGBA, NULL);
// generate OpenGL display lists to speed up rendering
board__gridDisplayList = glGenLists(1);
glNewList(board__gridDisplayList, GL_COMPILE);
// draw board outline (grid)
float step = 2.0 / board__width;
float cell;
glBegin(GL_LINES);
// draw rows
for (cell = -1 + step; cell < board__width; cell += step) {
glVertex3f(-1, cell, -1);
glVertex3f(1, cell, -1);
}
// draw columns
for (cell = -1 + step; cell < board__width; cell += step) {
glVertex3f(cell, -1, -1);
glVertex3f(cell, 1, -1);
}
glEnd();
glEndList();
}
void board_fini() {
fbo_fini();
glDeleteLists(board__gridDisplayList, 1);
glDeleteTextures(1, &board__displayTexture);
glDeleteTextures(1, &board__computeTexture);
free(board__data);
}
void board_draw()
{
glBegin(GL_QUADS);
glTexCoord2f(0, 0); glVertex2f(-1, -1);
glTexCoord2f(1, 0); glVertex2f( 1, -1);
glTexCoord2f(1, 1); glVertex2f( 1, 1);
glTexCoord2f(0, 1); glVertex2f(-1, 1);
glEnd();
}
void board_render() {
fbo_disable(); // render to screen, not the FBO
// draw board contents
texture_load_array(board__displayTexture, GL_TEXTURE_2D, board__width, board__width, board__data);
glEnable(GL_TEXTURE_2D);
board_draw();
glDisable(GL_TEXTURE_2D);
// draw board outline (grid)
glCallList(board__gridDisplayList);
fbo_enable();
}
void board_update()
{
cgGLEnableProfile(cg__fragmentProfile);
cgGLBindProgram(cg__fragmentProgram);
// transfer data to texture
texture_load_array(board__computeTexture, GL_TEXTURE_RECTANGLE_ARB, board__width, board__width, board__data);
// perform computation
CGparameter textureCg = cgGetNamedParameter(cg__fragmentProgram, "aBoard");
cgGLSetTextureParameter(textureCg, board__computeTexture);
cgGLEnableTextureParameter(textureCg);
CGparameter widthCg = cgGetNamedParameter(cg__fragmentProgram, "aWidth");
cgSetParameter1f(widthCg, board__width);
board_draw(); // GPGPU CONCEPT 4: Viewport-Sized Quad = Data Stream Generator.
cgGLDisableTextureParameter(textureCg);
cgGLDisableProfile(cg__fragmentProfile);
// Read back the results
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
// The glReadBuffer function selects a color buffer source for pixels.
// void glReadBuffer(GLenum mode); mode is a color buffer
// The glReadPixels function reads a block of pixels from the framebuffer.
glReadPixels(
0, 0, // GLint x, y The window coordinates of the first pixel that is read from the framebuffer. This location is the lower-left corner of a rectangular block of pixels
board__width, // GLsizei width
board__width, // GLsizei height
GL_RGBA, // GLenum format
GL_FLOAT, // GLenum type
board__data); // GLvoid *pixels
}
void board_display() {
board_update();
board_render();
// handle algorithm completion
static unsigned long cycle = 0;
cycle++;
if (cycle >= board__numCycles) {
printf("\nThe tour should now be complete.");
#ifdef WIN32
printf("\n\nPress the ENTER key to continue.");
fflush(stdin);
int c = getchar();
#endif
printf("\nThe Knight toured in this order:\n");
// dump out the board contents
unsigned long numSkipped = 0;
unsigned addr = 0;
for(unsigned row = 0; row < board__width; row++) {
printf("\n");
for (unsigned col = 0; col < board__width; col++) {
float step = board__data[addr];
addr += 4;
if (step == 0) {
numSkipped++;
printf(" %3c", '#');
}
else {
printf(" %3.f", step);
}
}
}
printf("\n");
if (numSkipped > 0) {
printf("\nThe Knight failed to visit %lu cells.\n", numSkipped);
exit(EXIT_FAILURE);
}
else {
exit(EXIT_SUCCESS);
}
}
}