rev |
line source |
nuclear@1
|
1 #include <stdio.h>
|
nuclear@1
|
2 #include <stdlib.h>
|
nuclear@1
|
3 #include <float.h>
|
nuclear@1
|
4
|
nuclear@1
|
5 #include <GL/glew.h>
|
nuclear@1
|
6
|
nuclear@1
|
7 #include <assimp/assimp.h>
|
nuclear@1
|
8 #include <assimp/aiScene.h>
|
nuclear@1
|
9 #include <assimp/aiPostProcess.h>
|
nuclear@1
|
10
|
nuclear@1
|
11 #include <imago2.h>
|
nuclear@1
|
12
|
nuclear@1
|
13 #include "scene.h"
|
nuclear@1
|
14
|
nuclear@1
|
15 static void color(float *dest, float r, float g, float b);
|
nuclear@1
|
16 static struct mesh *create_mesh(const struct aiScene *aiscn, struct aiMesh *aim);
|
nuclear@1
|
17 static unsigned int create_buffer(unsigned int type, void *data, size_t sz);
|
nuclear@1
|
18 static unsigned int load_texture(const char *fname);
|
nuclear@1
|
19
|
nuclear@1
|
20
|
nuclear@1
|
21 int load_scene(struct scene *scn, const char *fname)
|
nuclear@1
|
22 {
|
nuclear@1
|
23 int i, j;
|
nuclear@1
|
24 const struct aiScene *aiscn;
|
nuclear@1
|
25 unsigned int proc_flags = aiProcess_JoinIdenticalVertices |
|
nuclear@1
|
26 aiProcess_PreTransformVertices | aiProcess_Triangulate |
|
nuclear@1
|
27 aiProcess_GenNormals | aiProcess_SortByPType;
|
nuclear@1
|
28
|
nuclear@1
|
29 if(!(aiscn = aiImportFile(fname, proc_flags))) {
|
nuclear@1
|
30 fprintf(stderr, "failed to load: %s\n", fname);
|
nuclear@1
|
31 return -1;
|
nuclear@1
|
32 }
|
nuclear@1
|
33
|
nuclear@1
|
34 scn->meshes = 0;
|
nuclear@1
|
35 scn->lights = 0;
|
nuclear@1
|
36
|
nuclear@1
|
37 scn->bbox.min[0] = scn->bbox.min[1] = scn->bbox.min[2] = FLT_MAX;
|
nuclear@1
|
38 scn->bbox.max[0] = scn->bbox.max[1] = scn->bbox.max[2] = -FLT_MAX;
|
nuclear@1
|
39
|
nuclear@1
|
40 for(i=0; i<aiscn->mNumMeshes; i++) {
|
nuclear@1
|
41 struct mesh *m;
|
nuclear@1
|
42
|
nuclear@1
|
43 if(!(m = create_mesh(aiscn, aiscn->mMeshes[i]))) {
|
nuclear@1
|
44 return -1;
|
nuclear@1
|
45 }
|
nuclear@1
|
46
|
nuclear@1
|
47 for(j=0; j<3; j++) {
|
nuclear@1
|
48 if(m->bbox.min[j] < scn->bbox.min[j]) {
|
nuclear@1
|
49 scn->bbox.min[j] = m->bbox.min[j];
|
nuclear@1
|
50 }
|
nuclear@1
|
51 if(m->bbox.max[j] > scn->bbox.max[j]) {
|
nuclear@1
|
52 scn->bbox.max[j] = m->bbox.max[j];
|
nuclear@1
|
53 }
|
nuclear@1
|
54 }
|
nuclear@1
|
55
|
nuclear@1
|
56 m->next = scn->meshes;
|
nuclear@1
|
57 scn->meshes = m;
|
nuclear@1
|
58 }
|
nuclear@1
|
59
|
nuclear@1
|
60 printf("scene bounds: %.2f %.2f %.2f -> %.2f %.2f %.2f\n", scn->bbox.min[0], scn->bbox.min[1],
|
nuclear@1
|
61 scn->bbox.min[2], scn->bbox.max[0], scn->bbox.max[1], scn->bbox.max[2]);
|
nuclear@1
|
62
|
nuclear@1
|
63 aiReleaseImport(aiscn);
|
nuclear@1
|
64 return 0;
|
nuclear@1
|
65 }
|
nuclear@1
|
66
|
nuclear@1
|
67 static void color(float *dest, float r, float g, float b)
|
nuclear@1
|
68 {
|
nuclear@1
|
69 dest[0] = r;
|
nuclear@1
|
70 dest[1] = g;
|
nuclear@1
|
71 dest[2] = b;
|
nuclear@1
|
72 dest[3] = 1.0;
|
nuclear@1
|
73 }
|
nuclear@1
|
74
|
nuclear@1
|
75 static struct mesh *create_mesh(const struct aiScene *aiscn, struct aiMesh *aim)
|
nuclear@1
|
76 {
|
nuclear@1
|
77 int i, j;
|
nuclear@1
|
78 struct mesh *m;
|
nuclear@1
|
79 struct aiMaterial *mat = aiscn->mMaterials[aim->mMaterialIndex];
|
nuclear@1
|
80 float sstr = 1.0;
|
nuclear@1
|
81 unsigned int sz, *idxarr, *dptr;
|
nuclear@1
|
82 struct aiVector3D *vptr;
|
nuclear@1
|
83 struct aiString tex_name;
|
nuclear@1
|
84
|
nuclear@1
|
85 if(!(m = calloc(1, sizeof *m))) {
|
nuclear@1
|
86 perror("failed to allocate mesh");
|
nuclear@1
|
87 return 0;
|
nuclear@1
|
88 }
|
nuclear@1
|
89
|
nuclear@1
|
90 /* default material */
|
nuclear@1
|
91 color(m->mat.kd, 1, 1, 1);
|
nuclear@1
|
92 color(m->mat.ks, 0, 0, 0);
|
nuclear@1
|
93 m->mat.shin = 60.0;
|
nuclear@1
|
94
|
nuclear@1
|
95 aiGetMaterialColor(mat, AI_MATKEY_COLOR_DIFFUSE, (void*)m->mat.kd);
|
nuclear@1
|
96 aiGetMaterialColor(mat, AI_MATKEY_COLOR_SPECULAR, (void*)m->mat.ks);
|
nuclear@1
|
97 sz = 1;
|
nuclear@1
|
98 aiGetMaterialFloatArray(mat, AI_MATKEY_SHININESS, &m->mat.shin, &sz);
|
nuclear@1
|
99 sz = 1;
|
nuclear@1
|
100 aiGetMaterialFloatArray(mat, AI_MATKEY_SHININESS_STRENGTH, &sstr, &sz);
|
nuclear@1
|
101 color(m->mat.ks, m->mat.ks[0] * sstr, m->mat.ks[1] * sstr, m->mat.ks[2] * sstr);
|
nuclear@1
|
102
|
nuclear@1
|
103 if(aiGetMaterialString(mat, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0), &tex_name) == 0) {
|
nuclear@1
|
104 m->mat.tex = load_texture(tex_name.data);
|
nuclear@1
|
105 }
|
nuclear@1
|
106
|
nuclear@1
|
107 m->num_verts = aim->mNumVertices;
|
nuclear@1
|
108 m->num_faces = aim->mNumFaces;
|
nuclear@1
|
109
|
nuclear@1
|
110 m->bbox.min[0] = m->bbox.min[1] = m->bbox.min[2] = FLT_MAX;
|
nuclear@1
|
111 m->bbox.max[0] = m->bbox.max[1] = m->bbox.max[2] = -FLT_MAX;
|
nuclear@1
|
112
|
nuclear@1
|
113 vptr = aim->mVertices;
|
nuclear@1
|
114 for(i=0; i<m->num_verts; i++) {
|
nuclear@1
|
115 if(vptr->x < m->bbox.min[0]) m->bbox.min[0] = vptr->x;
|
nuclear@1
|
116 if(vptr->y < m->bbox.min[1]) m->bbox.min[1] = vptr->y;
|
nuclear@1
|
117 if(vptr->z < m->bbox.min[2]) m->bbox.min[2] = vptr->z;
|
nuclear@1
|
118 if(vptr->x > m->bbox.max[0]) m->bbox.max[0] = vptr->x;
|
nuclear@1
|
119 if(vptr->y > m->bbox.max[1]) m->bbox.max[1] = vptr->y;
|
nuclear@1
|
120 if(vptr->z > m->bbox.max[2]) m->bbox.max[2] = vptr->z;
|
nuclear@1
|
121 vptr++;
|
nuclear@1
|
122 }
|
nuclear@1
|
123
|
nuclear@1
|
124 m->vert_buf = create_buffer(GL_ARRAY_BUFFER, aim->mVertices, m->num_verts * sizeof *aim->mVertices);
|
nuclear@1
|
125 if(aim->mNormals) {
|
nuclear@1
|
126 m->norm_buf = create_buffer(GL_ARRAY_BUFFER, aim->mNormals, m->num_verts * sizeof *aim->mNormals);
|
nuclear@1
|
127 }
|
nuclear@1
|
128 if(aim->mTextureCoords) {
|
nuclear@1
|
129 m->tex_buf = create_buffer(GL_ARRAY_BUFFER, aim->mTextureCoords, m->num_verts * sizeof *aim->mTextureCoords);
|
nuclear@1
|
130 }
|
nuclear@1
|
131
|
nuclear@1
|
132 /* indices are scattered all over the fucking place... map the buffer and collect them there directly */
|
nuclear@1
|
133 m->idx_buf = create_buffer(GL_ELEMENT_ARRAY_BUFFER, 0, m->num_faces * 3 * sizeof *aim->mFaces[0].mIndices);
|
nuclear@1
|
134 dptr = idxarr = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
|
nuclear@1
|
135
|
nuclear@1
|
136 for(i=0; i<m->num_faces; i++) {
|
nuclear@1
|
137 for(j=0; j<3; j++) {
|
nuclear@1
|
138 *dptr++ = aim->mFaces[i].mIndices[j];
|
nuclear@1
|
139 }
|
nuclear@1
|
140 }
|
nuclear@1
|
141 glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
|
nuclear@1
|
142 return m;
|
nuclear@1
|
143 }
|
nuclear@1
|
144
|
nuclear@1
|
145 static unsigned int create_buffer(unsigned int type, void *data, size_t sz)
|
nuclear@1
|
146 {
|
nuclear@1
|
147 unsigned int vbo;
|
nuclear@1
|
148 glGenBuffers(1, &vbo);
|
nuclear@1
|
149 glBindBuffer(type, vbo);
|
nuclear@1
|
150 glBufferData(type, sz, data, GL_STATIC_DRAW);
|
nuclear@1
|
151 return vbo;
|
nuclear@1
|
152 }
|
nuclear@1
|
153
|
nuclear@1
|
154 static unsigned int load_texture(const char *fname)
|
nuclear@1
|
155 {
|
nuclear@1
|
156 unsigned int tex;
|
nuclear@1
|
157 void *pixels;
|
nuclear@1
|
158 int xsz, ysz;
|
nuclear@1
|
159
|
nuclear@1
|
160 if(!(pixels = img_load_pixels(fname, &xsz, &ysz, IMG_FMT_RGBA32))) {
|
nuclear@1
|
161 fprintf(stderr, "failed to load image: %s\n", fname);
|
nuclear@1
|
162 return 0;
|
nuclear@1
|
163 }
|
nuclear@1
|
164
|
nuclear@1
|
165 glGenTextures(1, &tex);
|
nuclear@1
|
166 glBindTexture(GL_TEXTURE_2D, tex);
|
nuclear@1
|
167 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
nuclear@1
|
168 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
nuclear@1
|
169 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
nuclear@1
|
170 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
nuclear@1
|
171 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, xsz, ysz, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
nuclear@1
|
172
|
nuclear@1
|
173 img_free_pixels(pixels);
|
nuclear@1
|
174 return tex;
|
nuclear@1
|
175 }
|
nuclear@1
|
176
|
nuclear@1
|
177 void render_scene(struct scene *scn)
|
nuclear@1
|
178 {
|
nuclear@1
|
179 struct mesh *m = scn->meshes;
|
nuclear@1
|
180 while(m) {
|
nuclear@1
|
181 render_mesh(m);
|
nuclear@1
|
182 m = m->next;
|
nuclear@1
|
183 }
|
nuclear@1
|
184 }
|
nuclear@1
|
185
|
nuclear@1
|
186 void render_mesh(struct mesh *m)
|
nuclear@1
|
187 {
|
nuclear@1
|
188 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, m->mat.kd);
|
nuclear@1
|
189 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, m->mat.ks);
|
nuclear@1
|
190 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, m->mat.shin);
|
nuclear@1
|
191
|
nuclear@1
|
192 if(m->mat.tex) {
|
nuclear@1
|
193 glEnable(GL_TEXTURE_2D);
|
nuclear@1
|
194 glBindTexture(GL_TEXTURE_2D, m->mat.tex);
|
nuclear@1
|
195 }
|
nuclear@1
|
196
|
nuclear@1
|
197 /* TODO texture */
|
nuclear@1
|
198
|
nuclear@1
|
199 glBindBuffer(GL_ARRAY_BUFFER, m->vert_buf);
|
nuclear@1
|
200 glVertexPointer(3, GL_FLOAT, 0, 0);
|
nuclear@1
|
201 glEnableClientState(GL_VERTEX_ARRAY);
|
nuclear@1
|
202
|
nuclear@1
|
203 if(m->norm_buf) {
|
nuclear@1
|
204 glBindBuffer(GL_ARRAY_BUFFER, m->norm_buf);
|
nuclear@1
|
205 glNormalPointer(GL_FLOAT, 0, 0);
|
nuclear@1
|
206 glEnableClientState(GL_NORMAL_ARRAY);
|
nuclear@1
|
207 }
|
nuclear@1
|
208 if(m->tex_buf) {
|
nuclear@1
|
209 glBindBuffer(GL_ARRAY_BUFFER, m->tex_buf);
|
nuclear@1
|
210 glTexCoordPointer(3, GL_FLOAT, 0, 0);
|
nuclear@1
|
211 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
nuclear@1
|
212 }
|
nuclear@1
|
213
|
nuclear@1
|
214 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->idx_buf);
|
nuclear@1
|
215 glDrawElements(GL_TRIANGLES, m->num_faces * 3, GL_UNSIGNED_INT, 0);
|
nuclear@1
|
216
|
nuclear@1
|
217 glDisableClientState(GL_VERTEX_ARRAY);
|
nuclear@1
|
218 glDisableClientState(GL_NORMAL_ARRAY);
|
nuclear@1
|
219 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
nuclear@1
|
220
|
nuclear@1
|
221 if(m->mat.tex) {
|
nuclear@1
|
222 glDisable(GL_TEXTURE_2D);
|
nuclear@1
|
223 }
|
nuclear@1
|
224 }
|