stray "strong" tag support
[xreader.git] / xmodel.d
blob77577b89b1450566724dd9a9466c991a7a1bb554
1 /* Written by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
2 * Understanding is not required. Only obedience.
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 module xmodel;
19 import iv.glbinds;
20 import iv.vfs;
21 import iv.vmath;
24 // ////////////////////////////////////////////////////////////////////////// //
25 final class EliteModel {
26 public:
27 static align(1) struct UV {
28 align(1):
29 float u, v;
32 static struct Texture {
33 uint width, height;
34 ubyte* data;
35 uint tid;
38 static:
39 T* xalloc(T) (uint count) {
40 import core.stdc.stdlib : malloc;
41 import core.stdc.string : memset;
42 assert(count > 0);
43 auto res = malloc(T.sizeof*count);
44 if (res is null) assert(0, "out of memory");
45 memset(res, 0, T.sizeof*count);
46 return cast(T*)res;
49 void xfree(T) (ref T* ptr) {
50 if (ptr !is null) {
51 import core.stdc.stdlib : free;
52 free(ptr);
53 ptr = null;
57 public:
58 vec3[2] bbox;
60 uint texCount;
61 Texture* texts;
63 uint faceCount;
64 uint* mids; // face material array
65 vec3* verts;
66 vec3* norms;
67 UV* uvs;
68 uint* inds; // just a big array of indexes
69 uint subCount; // submodels
70 uint* subfcs; // faces in each submodel
71 ubyte* subsms; // smoothness
73 // exhaust
74 uint exCount;
75 vec3* exPos;
76 vec3* exSize;
78 string name;
79 string idName;
80 string dispName;
82 public:
83 this (const(char)[] fname) { load(fname); }
84 this (VFile fl) { load(fl); }
86 // don't unload textures here, as OpenGL context may be already destroyed
87 ~this () { freeData(); }
89 void freeData () {
90 if (texCount > 0) {
91 foreach (immutable idx; 0..texCount) xfree(texts[idx].data);
92 xfree(texts);
93 texCount = 0;
95 xfree(mids);
96 xfree(verts);
97 xfree(norms);
98 xfree(uvs);
99 xfree(inds);
100 xfree(subfcs);
101 xfree(subsms);
102 xfree(exPos);
103 xfree(exSize);
104 subCount = 0;
105 exCount = 0;
106 name = null;
107 idName = null;
108 dispName = null;
111 void freeImages () {
112 import core.stdc.stdlib : free;
113 foreach (immutable idx; 0..texCount) xfree(texts[idx].data);
116 void glUnload () {
117 glBindTexture(GL_TEXTURE_2D, 0);
118 foreach (immutable idx; 0..texCount) {
119 if (texts[idx].tid) {
120 glDeleteTextures(1, &texts[idx].tid);
121 texts[idx].tid = 0;
126 void glUpload () {
127 foreach (immutable idx; 0..texCount) {
128 if (texts[idx].tid) continue;
129 if (texts[idx].data is null) continue;
131 uint wrapOpt = GL_REPEAT;
132 uint filterOpt = GL_LINEAR;
134 glGenTextures(1, &texts[idx].tid);
135 glBindTexture(GL_TEXTURE_2D, texts[idx].tid);
136 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapOpt);
137 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapOpt);
138 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filterOpt);
139 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filterOpt);
140 //float[4] bclr = 0.0;
141 //glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, bclr.ptr);
142 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texts[idx].width, texts[idx].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texts[idx].data);
146 static uint glClearFlags () { pragma(inline, true); return (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); }
148 // setup model and view matrices before calling this
149 // also, setup lighting
150 void glDraw () {
151 if (texCount == 0) return;
153 glEnable(GL_TEXTURE_2D);
154 glEnable(GL_DEPTH_TEST);
155 //glDisable(GL_LIGHTING);
156 glDisable(GL_DITHER);
157 glDisable(GL_BLEND);
159 glEnable(GL_RESCALE_NORMAL);
160 glDisable(GL_SCISSOR_TEST);
161 glDisable(GL_STENCIL_TEST);
162 glDisable(GL_COLOR_MATERIAL);
164 glDepthFunc(GL_LEQUAL);
165 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
167 glEnable(GL_CULL_FACE);
168 //glCullFace(GL_FRONT);
169 glCullFace(GL_BACK);
170 glFrontFace(GL_CCW);
172 glDisable(GL_CULL_FACE); // this way we can draw any model
174 glEnableClientState(GL_VERTEX_ARRAY);
175 glEnableClientState(GL_NORMAL_ARRAY);
176 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
178 glVertexPointer(3, GL_FLOAT, 0, verts);
179 glNormalPointer(GL_FLOAT, 0, norms);
180 glTexCoordPointer(2, GL_FLOAT, 0, uvs);
182 uint s = 0;
183 foreach (immutable smidx, uint len; subfcs[0..subCount]) {
184 auto end = s+len;
185 glShadeModel(subsms[smidx] ? GL_SMOOTH : GL_FLAT);
186 while (s < faceCount && s < end) {
187 uint tid = mids[s];
188 uint e = s;
189 while (e < faceCount && e < end && mids[e] == tid) ++e;
190 glBindTexture(GL_TEXTURE_2D, texts[tid].tid);
191 glDrawElements(GL_TRIANGLES, (e-s)*3, GL_UNSIGNED_INT, inds+s*3);
192 s = e;
196 glBindTexture(GL_TEXTURE_2D, 0);
197 glDisableClientState(GL_VERTEX_ARRAY);
198 glDisableClientState(GL_NORMAL_ARRAY);
199 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
202 void glDrawExhaust () {
203 // "12.87 -6.34 -54.9 7.45 7.46 6"
204 // "-12.87 -6.34 -54.9 7.45 7.46 6"
206 glEnable(GL_TEXTURE_2D);
207 glEnable(GL_DEPTH_TEST);
208 //glDisable(GL_LIGHTING);
209 glDisable(GL_DITHER);
210 glEnable(GL_COLOR_MATERIAL);
212 glEnable(GL_BLEND);
213 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
215 glDepthFunc(GL_LEQUAL);
216 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
218 glEnable(GL_CULL_FACE);
219 //glCullFace(GL_FRONT);
220 glCullFace(GL_BACK);
221 glFrontFace(GL_CCW);
223 glDisable(GL_CULL_FACE); // this way we can draw any model
224 glShadeModel(GL_FLAT);
226 void drawTri() (in auto ref vec3 p0, in auto ref vec3 p1, in auto ref vec3 p2) {
227 // calculate normal
228 vec3 n = (p1-p0).cross(p2-p0).normalized;
229 glBegin(GL_TRIANGLES);
230 glNormal3f(n.x, n.y, n.z);
231 glVertex3f(p0.x, p0.y, p0.z);
232 glVertex3f(p1.x, p1.y, p1.z);
233 glVertex3f(p2.x, p2.y, p2.z);
234 glEnd();
237 void drawCone() (/*in auto ref*/ vec3 pos, /*in auto ref*/ vec3 size) {
238 //float zlen = size.z;
239 //if (zlen < 0) zlen = -zlen;
240 auto zlen = bbox[1].z-bbox[0].z;
241 if (zlen < 0) zlen = -zlen;
242 zlen /= 3.0;
243 //zlen *= 2.0;
244 glColor4f(0, 0.5, 0.8, 0.2);
245 //pos *= 0.5;
246 size *= 0.5;
247 drawTri(
248 pos-vec3(size.x, size.y, 0),
249 pos-vec3(0, 0, -zlen),
250 pos-vec3(size.x, -size.y, 0),
252 drawTri(
253 pos-vec3(-size.x, -size.y, 0),
254 pos-vec3(0, 0, -zlen),
255 pos-vec3(-size.x, size.y, 0),
257 drawTri(
258 pos-vec3(-size.x, size.y, 0),
259 pos-vec3(0, 0, -zlen),
260 pos-vec3(size.x, size.y, 0),
262 drawTri(
263 pos-vec3(size.x, -size.y, 0),
264 pos-vec3(0, 0, -zlen),
265 pos-vec3(-size.x, -size.y, 0),
269 //drawCone(vec3(12.87, -6.34, 54.9), vec3(7.45, 7.46, 6));
270 foreach (immutable ei; 0..exCount) {
271 drawCone(exPos[ei], exSize[ei]);
274 glColor4f(1, 1, 1, 1);
275 glDisable(GL_CULL_FACE); // this way we can draw any model
276 glDisable(GL_BLEND);
279 private:
280 void load (const(char)[] fname) {
281 import std.path;
282 load(VFile(fname));
283 if (name.length == 0) {
284 name = fname.baseName.stripExtension.idup;
285 if (name.length > 3 && name[0..4] == "oxm:") name = name[4..$];
287 if (idName.length == 0) idName = name;
288 if (dispName.length == 0) dispName = name;
291 void load (VFile fl) {
292 scope(failure) freeData();
293 // signature
294 char[4] sign;
295 fl.rawReadExact(sign[]);
297 if (sign == "EMD1") {
298 // old model format
299 // number of faces
300 auto fcount = fl.readNum!ushort;
301 if (fcount == 0) throw new Exception("invalid model file");
302 // number of textures
303 auto tcount = fl.readNum!ushort;
304 if (tcount == 0 || tcount > fcount) throw new Exception("invalid model file");
305 faceCount = fcount;
306 mids = xalloc!uint(fcount);
307 verts = xalloc!vec3(fcount*3);
308 norms = xalloc!vec3(fcount*3);
309 uvs = xalloc!UV(fcount*3);
310 inds = xalloc!uint(fcount*3);
311 subCount = 1;
312 subfcs = xalloc!uint(fcount);
313 subfcs[0] = fcount;
314 subsms = xalloc!ubyte(fcount);
315 subsms[0] = 1;
316 foreach (immutable idx, ref n; inds[0..fcount*3]) n = cast(uint)idx; // yep
317 exCount = 0;
318 // faces
319 foreach (immutable fidx; 0..fcount) {
320 // texture id
321 mids[fidx] = fl.readNum!ushort;
322 if (mids[fidx] >= tcount) throw new Exception("invalid model file");
323 // three vertices
324 foreach (immutable vn; 0..3) {
325 // uv
326 uvs[fidx*3+vn].u = fl.readNum!float;
327 uvs[fidx*3+vn].v = fl.readNum!float;
328 // coords
329 verts[fidx*3+vn].x = fl.readNum!float;
330 verts[fidx*3+vn].y = fl.readNum!float;
331 verts[fidx*3+vn].z = fl.readNum!float;
332 // normal
333 norms[fidx*3+vn].x = fl.readNum!float;
334 norms[fidx*3+vn].y = fl.readNum!float;
335 norms[fidx*3+vn].z = fl.readNum!float;
338 texCount = tcount;
339 texts = xalloc!Texture(tcount);
340 // textures
341 foreach (immutable idx; 0..tcount) {
342 // dimensions
343 auto w = fl.readNum!ushort;
344 auto h = fl.readNum!ushort;
345 if (w < 1 || h < 1) throw new Exception("invalid model file");
346 // compressed size
347 auto csz = fl.readNum!uint;
348 if (csz == 0 || csz > int.max) throw new Exception("invalid model file");
349 auto ep = fl.tell;
351 auto zs = wrapZLibStreamRO(fl, VFSZLibMode.ZLib, w*h*4, ep, csz);
352 //auto data = new ubyte[](w*h*4);
353 ubyte* data = xalloc!ubyte(w*h*4);
354 scope(failure) xfree(data);
355 zs.rawReadExact(data[0..w*h*4]);
356 //texts ~= Texture(w, h, data, 0);
357 texts[idx].width = w;
358 texts[idx].height = h;
359 texts[idx].data = data;
360 texts[idx].tid = 0;
361 data = null;
363 fl.seek(ep+csz);
365 } else if (sign == "EMD2") {
366 // new model format
367 // number of faces
368 auto fcount = fl.readNum!ushort;
369 if (fcount == 0) throw new Exception("invalid model file");
370 // number of textures
371 auto tcount = fl.readNum!ushort;
372 if (tcount == 0 || tcount > fcount) throw new Exception("invalid model file");
373 // number of submodels
374 auto scount = fl.readNum!ushort;
375 if (scount == 0 || scount > fcount) throw new Exception("invalid model file");
376 // number of exhausts
377 auto ecount = fl.readNum!ushort;
378 if (/*ecount == 0 ||*/ ecount > 255) throw new Exception("invalid model file");
379 faceCount = fcount;
380 mids = xalloc!uint(fcount);
381 verts = xalloc!vec3(fcount*3);
382 norms = xalloc!vec3(fcount*3);
383 uvs = xalloc!UV(fcount*3);
384 inds = xalloc!uint(fcount*3);
385 subCount = scount;
386 subfcs = xalloc!uint(scount);
387 subsms = xalloc!ubyte(scount);
388 foreach (immutable idx, ref n; inds[0..fcount*3]) n = cast(uint)idx; // yep
389 exCount = ecount;
390 if (ecount) {
391 exPos = xalloc!vec3(ecount);
392 exSize = xalloc!vec3(ecount);
395 string readStr () {
396 auto len = fl.readNum!ubyte;
397 if (len) {
398 auto s = new char[](len);
399 fl.rawReadExact(s[]);
400 return cast(string)s; // it is safe to cast here
401 } else {
402 return null;
405 name = readStr;
406 idName = readStr;
407 dispName = readStr;
409 // face counts
410 foreach (ref uint c; subfcs[0..scount]) c = fl.readNum!ushort;
411 // face smoothness
412 //foreach (ref ubyte v; subsms[0..scount]) v = fl.readNum!ubyte;
413 fl.rawReadExact(subsms[0..scount]);
415 // exhausts
416 foreach (immutable ei; 0..ecount) {
417 exPos[ei].x = fl.readNum!float;
418 exPos[ei].y = fl.readNum!float;
419 exPos[ei].z = fl.readNum!float;
420 exSize[ei].x = fl.readNum!float;
421 exSize[ei].y = fl.readNum!float;
422 exSize[ei].z = fl.readNum!float;
425 // faces
426 foreach (immutable fidx; 0..fcount) {
427 // texture id
428 mids[fidx] = fl.readNum!ushort;
429 if (mids[fidx] >= tcount) throw new Exception("invalid model file");
430 // three vertices
431 foreach (immutable vn; 0..3) {
432 // uv
433 uvs[fidx*3+vn].u = fl.readNum!float;
434 uvs[fidx*3+vn].v = fl.readNum!float;
435 // coords
436 verts[fidx*3+vn].x = fl.readNum!float;
437 verts[fidx*3+vn].y = fl.readNum!float;
438 verts[fidx*3+vn].z = fl.readNum!float;
439 // normal
440 norms[fidx*3+vn].x = fl.readNum!float;
441 norms[fidx*3+vn].y = fl.readNum!float;
442 norms[fidx*3+vn].z = fl.readNum!float;
446 // material (texture) colors
448 foreach (immutable _; 0..tcount) {
449 fl.writeNum!float(mat.colorAmb[0]);
450 fl.writeNum!float(mat.colorAmb[1]);
451 fl.writeNum!float(mat.colorAmb[2]);
452 fl.writeNum!float(mat.colorAmb[3]);
453 fl.writeNum!float(mat.colorDiff[0]);
454 fl.writeNum!float(mat.colorDiff[1]);
455 fl.writeNum!float(mat.colorDiff[2]);
456 fl.writeNum!float(mat.colorDiff[3]);
457 fl.writeNum!float(mat.colorSpec[0]);
458 fl.writeNum!float(mat.colorSpec[1]);
459 fl.writeNum!float(mat.colorSpec[2]);
460 fl.writeNum!float(mat.colorSpec[3]);
461 fl.writeNum!float(mat.shininess);
464 fl.seek(tcount*(13*float.sizeof), Seek.Cur);
466 // textures
467 texCount = tcount;
468 texts = xalloc!Texture(tcount);
469 foreach (immutable idx; 0..tcount) {
470 // dimensions
471 auto w = fl.readNum!ushort;
472 auto h = fl.readNum!ushort;
473 if (w < 1 || h < 1) throw new Exception("invalid model file");
474 auto compType = fl.readNum!ubyte;
475 if (compType == 0) {
476 ubyte* data = xalloc!ubyte(w*h*4);
477 scope(failure) xfree(data);
478 fl.rawReadExact(data[0..w*h*4]);
479 texts[idx].width = w;
480 texts[idx].height = h;
481 texts[idx].data = data;
482 texts[idx].tid = 0;
483 data = null;
484 } else if (compType == 1) {
485 // compressed size
486 auto csz = fl.readNum!uint;
487 if (csz == 0 || csz > int.max) throw new Exception("invalid model file");
488 auto ep = fl.tell;
490 auto zs = wrapZLibStreamRO(fl, VFSZLibMode.ZLib, w*h*4, ep, csz);
491 //auto data = new ubyte[](w*h*4);
492 ubyte* data = xalloc!ubyte(w*h*4);
493 scope(failure) xfree(data);
494 zs.rawReadExact(data[0..w*h*4]);
495 texts[idx].width = w;
496 texts[idx].height = h;
497 texts[idx].data = data;
498 texts[idx].tid = 0;
499 data = null;
501 fl.seek(ep+csz);
502 } else {
503 throw new Exception("invalid compression type");
506 } else {
507 throw new Exception("invalid model signature");
509 // calc bbox
510 bbox[0] = vec3(float.max, float.max, float.max);
511 bbox[1] = vec3(-float.max, -float.max, -float.max);
512 foreach (const ref vec3 v; verts[0..faceCount*3]) {
513 import std.algorithm : min, max;
514 bbox[0].x = min(bbox[0].x, v.x);
515 bbox[0].y = min(bbox[0].y, v.y);
516 bbox[0].z = min(bbox[0].z, v.z);
517 bbox[1].x = max(bbox[1].x, v.x);
518 bbox[1].y = max(bbox[1].y, v.y);
519 bbox[1].z = max(bbox[1].z, v.z);
525 // ////////////////////////////////////////////////////////////////////////// //
526 __gshared bool doLights = true;
527 __gshared bool drawLights = false;
528 private {
529 __gshared int lightCount = 0;
530 __gshared float[4][8] lightColor;
531 __gshared float[3][8] lightPos;
535 // ////////////////////////////////////////////////////////////////////////// //
536 void lightsClear () {
537 lightCount = 0;
541 void lightAdd (float x, float y, float z, float r, float g, float b) {
542 if (lightCount < 8) {
543 lightColor[lightCount][0] = r;
544 lightColor[lightCount][1] = g;
545 lightColor[lightCount][2] = b;
546 lightColor[lightCount][3] = 1.0f;
547 lightPos[lightCount][0] = x;
548 lightPos[lightCount][1] = y;
549 lightPos[lightCount][2] = z;
550 ++lightCount;
555 // ////////////////////////////////////////////////////////////////////////// //
556 void drawModel (float angle, EliteModel shipModel) {
557 import iv.glbinds;
559 if (shipModel is null) return;
561 //glClearColor(0.2, 0.2, 0.2, 0);
562 //glClear(shipModel.glClearFlags);
564 //glEnable(GL_DEPTH_TEST);
565 //glDepthFunc(GL_LEQUAL);
566 //glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
567 glClearDepth(1.0f);
569 // setup projection
570 glMatrixMode(GL_PROJECTION);
571 glLoadIdentity();
572 oglPerspective(
573 90.0, // field of view in degree
574 1.0, // aspect ratio
575 1.0, // Z near
576 10000.0, // Z far
578 float zz = shipModel.bbox[1].z-shipModel.bbox[0].z;
579 zz += 10;
580 //if (zz < 20) zz = 20;
581 oglLookAt(
582 0.0, 0.0, -zz, // eye is at (0,0,5)
583 0.0, 0.0, 0, // center is at (0,0,0)
584 0.0, 1.0, 0.0, // up is in positive Y direction
587 // setup model matrix
588 glMatrixMode(GL_MODELVIEW);
589 glLoadIdentity();
591 // setup lighting
594 static immutable float[4] ldiff0 = [1.0, 1.0, 0.0, 1.0];
595 static immutable float[3] lpos0 = [-20.0, 0.0, -20.0-20];
596 glLightfv(GL_LIGHT0, GL_DIFFUSE, ldiff0.ptr);
597 glLightfv(GL_LIGHT0, GL_POSITION, lpos0.ptr);
598 glEnable(GL_LIGHT0);
601 static immutable float[4] ldiff1 = [1.0, 0.0, 0.0, 1.0];
602 static immutable float[3] lpos1 = [20.0, -20.0, 20.0-20];
603 glLightfv(GL_LIGHT1, GL_DIFFUSE, ldiff1.ptr);
604 glLightfv(GL_LIGHT1, GL_POSITION, lpos1.ptr);
605 glEnable(GL_LIGHT1);
610 lightsClear();
611 lightAdd(
612 0, zz, -50,
613 1.0, 0.0, 0.0
615 lightAdd(
616 zz/2, zz/2, zz,
617 1.0, 1.0, 1.0
621 glDisable(GL_LIGHTING);
622 if (doLights) {
623 glShadeModel(GL_SMOOTH);
624 __gshared float[4][8] ldiff = void;
625 __gshared float[3][8] lpos = void;
626 if (drawLights) {
627 foreach (uint idx; 0..lightCount) {
628 ldiff[idx] = lightColor.ptr[idx][];
629 lpos[idx] = lightPos.ptr[idx][];
630 glColor4f(ldiff[idx][0], ldiff[idx][1], ldiff[idx][2], 1.0);
632 glBegin(/*GL_QUADS*/GL_TRIANGLE_FAN);
633 glVertex3f(lpos[idx][0]-1, lpos[idx][1]-1, lpos[idx][2]);
634 glVertex3f(lpos[idx][0]+1, lpos[idx][1]-1, lpos[idx][2]);
635 glVertex3f(lpos[idx][0]+1, lpos[idx][1]+1, lpos[idx][2]);
636 glVertex3f(lpos[idx][0]-1, lpos[idx][1]+1, lpos[idx][2]);
637 glEnd();
640 glPointSize(5);
641 glBegin(GL_POINTS);
642 glVertex3fv(lpos[idx].ptr);
643 glEnd();
644 glPointSize(1);
647 glColor3f(1, 1, 1);
650 __gshared float[4] ambcol;
651 ambcol[0] = 0.6f;
652 ambcol[1] = 0.6f;
653 ambcol[2] = 0.6f;
654 ambcol[3] = 1.0f;
655 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambcol.ptr);
656 foreach (uint idx; 0..lightCount) {
657 ldiff[idx] = lightColor[idx][];
658 lpos[idx] = lightPos[idx][];
659 //{ import std.stdio; writeln("LIGHT #", idx, " at ", lightPos[idx][], " color ", lightColor[idx][]); }
660 glEnable(GL_LIGHT0+idx);
661 //glLightfv(GL_LIGHT0+idx, GL_DIFFUSE, &lightColor[idx][0]);
662 //glLightfv(GL_LIGHT0+idx, GL_POSITION, &lightPos[idx][0]);
663 assert((&ldiff[0])+1 == &ldiff[1]);
664 glLightfv(GL_LIGHT0+idx, GL_DIFFUSE, ldiff[idx].ptr);
665 //glLightfv(GL_LIGHT0+idx, GL_SPECULAR, ldiff[idx].ptr);
666 glLightfv(GL_LIGHT0+idx, GL_POSITION, lpos[idx].ptr);
668 glEnable(GL_LIGHTING);
670 version(none) {
672 static immutable float[4] ldiff0 = [1.0, 0.0, 0.0, 1.0];
673 static immutable float[3] lpos0 = [-90.0, 0.0, 90.0];
675 __gshared float[4] ldiff0 = [1.0, 0.0, 0.0, 1.0];
676 __gshared float[3] lpos0 = [-90.0, 0.0, 90.0];
677 //lightColor[0] = ldiff0[];
678 //lightPos[0] = lpos0[];
679 //glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor[0].ptr);
680 //glLightfv(GL_LIGHT0, GL_POSITION, lightPos[0].ptr);
681 glLightfv(GL_LIGHT0, GL_DIFFUSE, ldiff0.ptr);
682 glLightfv(GL_LIGHT0, GL_POSITION, lpos0.ptr);
683 //glEnable(GL_LIGHT0);
684 //glEnable(GL_LIGHTING);
688 doLight(
689 90, 40, -40,
690 1.0, 0.0, 0.0
692 doLight(
693 -90, 0, 90,
694 1.0, 1.0, 1.0
699 doLight(
700 zz, zz/2, -zz/2,
701 1.0, 0.0, 0.0
705 doLight(
706 0, zz, -50,
707 1.0, 0.0, 0.0
709 doLight(
710 zz/2, zz/2, zz,
711 1.0, 1.0, 1.0
715 //angle = 142;
717 // rotate model
718 glRotatef(angle, 0.8, 0.5, 0.3);
720 glRotatef(angle, 0.8, 0.0, 0.0);
721 glRotatef(angle, 0.0, 0.3, 0.0);
722 glRotatef(angle, 0.0, 0.0, 0.1);
725 version(none) {
726 // enable color tracking
727 glEnable(GL_COLOR_MATERIAL);
728 // set material properties which will be assigned by glColor
729 glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
730 //glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
731 // blue reflective properties
732 glColor3f(0.0f, 0.5f, 1.0f);
735 //glEnable(GL_LIGHTING);
736 shipModel.glDraw();
737 shipModel.glDrawExhaust();
739 if (doLights) {
740 foreach (uint idx; 0..lightCount) glDisable(GL_LIGHT0+idx);
741 glDisable(GL_LIGHTING);
742 glShadeModel(GL_FLAT);
744 //glDisable(GL_DEPTH_TEST);