(experimental) it is now possible to select navigation link with keyboard
[xreader.git] / xmodel.d
blobca0cb5991e6d04d59487477b8f9bc4fa621f4505
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.cmdcon;
20 import iv.glbinds;
21 import iv.vfs;
22 import iv.vmath;
25 // ////////////////////////////////////////////////////////////////////////// //
26 final class EliteModel {
27 public:
28 static align(1) struct UV {
29 align(1):
30 float u, v;
33 static struct Texture {
34 uint width, height;
35 ubyte* data;
36 uint tid;
39 static:
40 T* xalloc(T) (uint count) {
41 import core.stdc.stdlib : malloc;
42 import core.stdc.string : memset;
43 assert(count > 0);
44 auto res = malloc(T.sizeof*count);
45 if (res is null) assert(0, "out of memory");
46 memset(res, 0, T.sizeof*count);
47 return cast(T*)res;
50 void xfree(T) (ref T* ptr) {
51 if (ptr !is null) {
52 import core.stdc.stdlib : free;
53 free(ptr);
54 ptr = null;
58 public:
59 vec3[2] bbox;
61 uint texCount;
62 Texture* texts;
64 uint faceCount;
65 uint* mids; // face material array
66 vec3* verts;
67 vec3* norms;
68 UV* uvs;
69 uint* inds; // just a big array of indexes
70 uint subCount; // submodels
71 uint* subfcs; // faces in each submodel
72 ubyte* subsms; // smoothness
74 // exhaust
75 uint exCount;
76 vec3* exPos;
77 vec3* exSize;
79 string name;
80 string idName;
81 string dispName;
83 public:
84 this (const(char)[] fname) { load(fname); }
85 this (VFile fl) { load(fl); }
87 // don't unload textures here, as OpenGL context may be already destroyed
88 ~this () { freeData(); }
90 void freeData () {
91 if (texCount > 0) {
92 foreach (immutable idx; 0..texCount) xfree(texts[idx].data);
93 xfree(texts);
94 texCount = 0;
96 xfree(mids);
97 xfree(verts);
98 xfree(norms);
99 xfree(uvs);
100 xfree(inds);
101 xfree(subfcs);
102 xfree(subsms);
103 xfree(exPos);
104 xfree(exSize);
105 subCount = 0;
106 exCount = 0;
107 name = null;
108 idName = null;
109 dispName = null;
112 void freeImages () {
113 import core.stdc.stdlib : free;
114 foreach (immutable idx; 0..texCount) xfree(texts[idx].data);
117 void glUnload () {
118 glBindTexture(GL_TEXTURE_2D, 0);
119 foreach (immutable idx; 0..texCount) {
120 if (texts[idx].tid) {
121 glDeleteTextures(1, &texts[idx].tid);
122 texts[idx].tid = 0;
127 void glUpload () {
128 foreach (immutable idx; 0..texCount) {
129 if (texts[idx].tid) continue;
130 if (texts[idx].data is null) continue;
132 uint wrapOpt = GL_REPEAT;
133 uint filterOpt = GL_LINEAR;
135 glGenTextures(1, &texts[idx].tid);
136 glBindTexture(GL_TEXTURE_2D, texts[idx].tid);
137 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapOpt);
138 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapOpt);
139 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filterOpt);
140 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filterOpt);
141 //float[4] bclr = 0.0;
142 //glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, bclr.ptr);
143 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texts[idx].width, texts[idx].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texts[idx].data);
147 static uint glClearFlags () { pragma(inline, true); return (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); }
149 // setup model and view matrices before calling this
150 // also, setup lighting
151 void glDraw () {
152 if (texCount == 0) return;
154 glEnable(GL_TEXTURE_2D);
155 glEnable(GL_DEPTH_TEST);
156 //glDisable(GL_LIGHTING);
157 glDisable(GL_DITHER);
158 glDisable(GL_BLEND);
160 glEnable(GL_RESCALE_NORMAL);
161 glDisable(GL_SCISSOR_TEST);
162 glDisable(GL_STENCIL_TEST);
163 glDisable(GL_COLOR_MATERIAL);
165 glDepthFunc(GL_LEQUAL);
166 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
168 glEnable(GL_CULL_FACE);
169 //glCullFace(GL_FRONT);
170 glCullFace(GL_BACK);
171 glFrontFace(GL_CCW);
173 glDisable(GL_CULL_FACE); // this way we can draw any model
175 glEnableClientState(GL_VERTEX_ARRAY);
176 glEnableClientState(GL_NORMAL_ARRAY);
177 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
179 glVertexPointer(3, GL_FLOAT, 0, verts);
180 glNormalPointer(GL_FLOAT, 0, norms);
181 glTexCoordPointer(2, GL_FLOAT, 0, uvs);
183 uint s = 0;
184 foreach (immutable smidx, uint len; subfcs[0..subCount]) {
185 auto end = s+len;
186 glShadeModel(subsms[smidx] ? GL_SMOOTH : GL_FLAT);
187 while (s < faceCount && s < end) {
188 uint tid = mids[s];
189 uint e = s;
190 while (e < faceCount && e < end && mids[e] == tid) ++e;
191 glBindTexture(GL_TEXTURE_2D, texts[tid].tid);
192 glDrawElements(GL_TRIANGLES, (e-s)*3, GL_UNSIGNED_INT, inds+s*3);
193 s = e;
197 glBindTexture(GL_TEXTURE_2D, 0);
198 glDisableClientState(GL_VERTEX_ARRAY);
199 glDisableClientState(GL_NORMAL_ARRAY);
200 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
203 void glDrawExhaust () {
204 // "12.87 -6.34 -54.9 7.45 7.46 6"
205 // "-12.87 -6.34 -54.9 7.45 7.46 6"
207 glEnable(GL_TEXTURE_2D);
208 glEnable(GL_DEPTH_TEST);
209 //glDisable(GL_LIGHTING);
210 glDisable(GL_DITHER);
211 glEnable(GL_COLOR_MATERIAL);
213 glEnable(GL_BLEND);
214 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
216 glDepthFunc(GL_LEQUAL);
217 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
219 glEnable(GL_CULL_FACE);
220 //glCullFace(GL_FRONT);
221 glCullFace(GL_BACK);
222 glFrontFace(GL_CCW);
224 glDisable(GL_CULL_FACE); // this way we can draw any model
225 glShadeModel(GL_FLAT);
227 void drawTri() (in auto ref vec3 p0, in auto ref vec3 p1, in auto ref vec3 p2) {
228 // calculate normal
229 vec3 n = (p1-p0).cross(p2-p0).normalized;
230 glBegin(GL_TRIANGLES);
231 glNormal3f(n.x, n.y, n.z);
232 glVertex3f(p0.x, p0.y, p0.z);
233 glVertex3f(p1.x, p1.y, p1.z);
234 glVertex3f(p2.x, p2.y, p2.z);
235 glEnd();
238 void drawCone() (/*in auto ref*/ vec3 pos, /*in auto ref*/ vec3 size) {
239 //float zlen = size.z;
240 //if (zlen < 0) zlen = -zlen;
241 auto zlen = bbox[1].z-bbox[0].z;
242 if (zlen < 0) zlen = -zlen;
243 zlen /= 3.0;
244 //zlen *= 2.0;
245 glColor4f(0, 0.5, 0.8, 0.2);
246 //pos *= 0.5;
247 size *= 0.5;
248 drawTri(
249 pos-vec3(size.x, size.y, 0),
250 pos-vec3(0, 0, -zlen),
251 pos-vec3(size.x, -size.y, 0),
253 drawTri(
254 pos-vec3(-size.x, -size.y, 0),
255 pos-vec3(0, 0, -zlen),
256 pos-vec3(-size.x, size.y, 0),
258 drawTri(
259 pos-vec3(-size.x, size.y, 0),
260 pos-vec3(0, 0, -zlen),
261 pos-vec3(size.x, size.y, 0),
263 drawTri(
264 pos-vec3(size.x, -size.y, 0),
265 pos-vec3(0, 0, -zlen),
266 pos-vec3(-size.x, -size.y, 0),
270 //drawCone(vec3(12.87, -6.34, 54.9), vec3(7.45, 7.46, 6));
271 foreach (immutable ei; 0..exCount) {
272 drawCone(exPos[ei], exSize[ei]);
275 glColor4f(1, 1, 1, 1);
276 glDisable(GL_CULL_FACE); // this way we can draw any model
277 glDisable(GL_BLEND);
280 private:
281 void load (const(char)[] fname) {
282 import std.path;
283 load(VFile(fname));
284 if (name.length == 0) {
285 name = fname.baseName.stripExtension.idup;
286 if (name.length > 3 && name[0..4] == "oxm:") name = name[4..$];
288 if (idName.length == 0) idName = name;
289 if (dispName.length == 0) dispName = name;
292 void load (VFile fl) {
293 scope(failure) freeData();
294 // signature
295 char[4] sign;
296 fl.rawReadExact(sign[]);
298 if (sign == "EMD1") {
299 // old model format
300 // number of faces
301 auto fcount = fl.readNum!ushort;
302 if (fcount == 0) throw new Exception("invalid model file");
303 // number of textures
304 auto tcount = fl.readNum!ushort;
305 if (tcount == 0 || tcount > fcount) throw new Exception("invalid model file");
306 faceCount = fcount;
307 mids = xalloc!uint(fcount);
308 verts = xalloc!vec3(fcount*3);
309 norms = xalloc!vec3(fcount*3);
310 uvs = xalloc!UV(fcount*3);
311 inds = xalloc!uint(fcount*3);
312 subCount = 1;
313 subfcs = xalloc!uint(fcount);
314 subfcs[0] = fcount;
315 subsms = xalloc!ubyte(fcount);
316 subsms[0] = 1;
317 foreach (immutable idx, ref n; inds[0..fcount*3]) n = cast(uint)idx; // yep
318 exCount = 0;
319 // faces
320 foreach (immutable fidx; 0..fcount) {
321 // texture id
322 mids[fidx] = fl.readNum!ushort;
323 if (mids[fidx] >= tcount) throw new Exception("invalid model file");
324 // three vertices
325 foreach (immutable vn; 0..3) {
326 // uv
327 uvs[fidx*3+vn].u = fl.readNum!float;
328 uvs[fidx*3+vn].v = fl.readNum!float;
329 // coords
330 verts[fidx*3+vn].x = fl.readNum!float;
331 verts[fidx*3+vn].y = fl.readNum!float;
332 verts[fidx*3+vn].z = fl.readNum!float;
333 // normal
334 norms[fidx*3+vn].x = fl.readNum!float;
335 norms[fidx*3+vn].y = fl.readNum!float;
336 norms[fidx*3+vn].z = fl.readNum!float;
339 texCount = tcount;
340 texts = xalloc!Texture(tcount);
341 // textures
342 foreach (immutable idx; 0..tcount) {
343 // dimensions
344 auto w = fl.readNum!ushort;
345 auto h = fl.readNum!ushort;
346 if (w < 1 || h < 1) throw new Exception("invalid model file");
347 // compressed size
348 auto csz = fl.readNum!uint;
349 if (csz == 0 || csz > int.max) throw new Exception("invalid model file");
350 auto ep = fl.tell;
352 auto zs = wrapZLibStreamRO(fl, VFSZLibMode.ZLib, w*h*4, ep, csz);
353 //auto data = new ubyte[](w*h*4);
354 ubyte* data = xalloc!ubyte(w*h*4);
355 scope(failure) xfree(data);
356 zs.rawReadExact(data[0..w*h*4]);
357 //texts ~= Texture(w, h, data, 0);
358 texts[idx].width = w;
359 texts[idx].height = h;
360 texts[idx].data = data;
361 texts[idx].tid = 0;
362 data = null;
364 fl.seek(ep+csz);
366 } else if (sign == "EMD2") {
367 // new model format
368 // number of faces
369 auto fcount = fl.readNum!ushort;
370 if (fcount == 0) throw new Exception("invalid model file");
371 // number of textures
372 auto tcount = fl.readNum!ushort;
373 if (tcount == 0 || tcount > fcount) throw new Exception("invalid model file");
374 // number of submodels
375 auto scount = fl.readNum!ushort;
376 if (scount == 0 || scount > fcount) throw new Exception("invalid model file");
377 // number of exhausts
378 auto ecount = fl.readNum!ushort;
379 if (/*ecount == 0 ||*/ ecount > 255) throw new Exception("invalid model file");
380 faceCount = fcount;
381 mids = xalloc!uint(fcount);
382 verts = xalloc!vec3(fcount*3);
383 norms = xalloc!vec3(fcount*3);
384 uvs = xalloc!UV(fcount*3);
385 inds = xalloc!uint(fcount*3);
386 subCount = scount;
387 subfcs = xalloc!uint(scount);
388 subsms = xalloc!ubyte(scount);
389 foreach (immutable idx, ref n; inds[0..fcount*3]) n = cast(uint)idx; // yep
390 exCount = ecount;
391 if (ecount) {
392 exPos = xalloc!vec3(ecount);
393 exSize = xalloc!vec3(ecount);
396 string readStr () {
397 auto len = fl.readNum!ubyte;
398 if (len) {
399 auto s = new char[](len);
400 fl.rawReadExact(s[]);
401 return cast(string)s; // it is safe to cast here
402 } else {
403 return null;
406 name = readStr;
407 idName = readStr;
408 dispName = readStr;
410 // face counts
411 foreach (ref uint c; subfcs[0..scount]) c = fl.readNum!ushort;
412 // face smoothness
413 //foreach (ref ubyte v; subsms[0..scount]) v = fl.readNum!ubyte;
414 fl.rawReadExact(subsms[0..scount]);
416 // exhausts
417 foreach (immutable ei; 0..ecount) {
418 exPos[ei].x = fl.readNum!float;
419 exPos[ei].y = fl.readNum!float;
420 exPos[ei].z = fl.readNum!float;
421 exSize[ei].x = fl.readNum!float;
422 exSize[ei].y = fl.readNum!float;
423 exSize[ei].z = fl.readNum!float;
426 // faces
427 foreach (immutable fidx; 0..fcount) {
428 // texture id
429 mids[fidx] = fl.readNum!ushort;
430 if (mids[fidx] >= tcount) throw new Exception("invalid model file");
431 // three vertices
432 foreach (immutable vn; 0..3) {
433 // uv
434 uvs[fidx*3+vn].u = fl.readNum!float;
435 uvs[fidx*3+vn].v = fl.readNum!float;
436 // coords
437 verts[fidx*3+vn].x = fl.readNum!float;
438 verts[fidx*3+vn].y = fl.readNum!float;
439 verts[fidx*3+vn].z = fl.readNum!float;
440 // normal
441 norms[fidx*3+vn].x = fl.readNum!float;
442 norms[fidx*3+vn].y = fl.readNum!float;
443 norms[fidx*3+vn].z = fl.readNum!float;
447 // material (texture) colors
449 foreach (immutable _; 0..tcount) {
450 fl.writeNum!float(mat.colorAmb[0]);
451 fl.writeNum!float(mat.colorAmb[1]);
452 fl.writeNum!float(mat.colorAmb[2]);
453 fl.writeNum!float(mat.colorAmb[3]);
454 fl.writeNum!float(mat.colorDiff[0]);
455 fl.writeNum!float(mat.colorDiff[1]);
456 fl.writeNum!float(mat.colorDiff[2]);
457 fl.writeNum!float(mat.colorDiff[3]);
458 fl.writeNum!float(mat.colorSpec[0]);
459 fl.writeNum!float(mat.colorSpec[1]);
460 fl.writeNum!float(mat.colorSpec[2]);
461 fl.writeNum!float(mat.colorSpec[3]);
462 fl.writeNum!float(mat.shininess);
465 fl.seek(tcount*(13*float.sizeof), Seek.Cur);
467 // textures
468 texCount = tcount;
469 texts = xalloc!Texture(tcount);
470 foreach (immutable idx; 0..tcount) {
471 // dimensions
472 auto w = fl.readNum!ushort;
473 auto h = fl.readNum!ushort;
474 if (w < 1 || h < 1) throw new Exception("invalid model file");
475 auto compType = fl.readNum!ubyte;
476 if (compType == 0) {
477 ubyte* data = xalloc!ubyte(w*h*4);
478 scope(failure) xfree(data);
479 fl.rawReadExact(data[0..w*h*4]);
480 texts[idx].width = w;
481 texts[idx].height = h;
482 texts[idx].data = data;
483 texts[idx].tid = 0;
484 data = null;
485 } else if (compType == 1) {
486 // compressed size
487 auto csz = fl.readNum!uint;
488 if (csz == 0 || csz > int.max) throw new Exception("invalid model file");
489 auto ep = fl.tell;
491 auto zs = wrapZLibStreamRO(fl, VFSZLibMode.ZLib, w*h*4, ep, csz);
492 //auto data = new ubyte[](w*h*4);
493 ubyte* data = xalloc!ubyte(w*h*4);
494 scope(failure) xfree(data);
495 zs.rawReadExact(data[0..w*h*4]);
496 texts[idx].width = w;
497 texts[idx].height = h;
498 texts[idx].data = data;
499 texts[idx].tid = 0;
500 data = null;
502 fl.seek(ep+csz);
503 } else {
504 throw new Exception("invalid compression type");
507 } else {
508 throw new Exception("invalid model signature");
510 // calc bbox
511 bbox[0] = vec3(float.max, float.max, float.max);
512 bbox[1] = vec3(-float.max, -float.max, -float.max);
513 foreach (const ref vec3 v; verts[0..faceCount*3]) {
514 import std.algorithm : min, max;
515 bbox[0].x = min(bbox[0].x, v.x);
516 bbox[0].y = min(bbox[0].y, v.y);
517 bbox[0].z = min(bbox[0].z, v.z);
518 bbox[1].x = max(bbox[1].x, v.x);
519 bbox[1].y = max(bbox[1].y, v.y);
520 bbox[1].z = max(bbox[1].z, v.z);
526 // ////////////////////////////////////////////////////////////////////////// //
527 __gshared bool doLights = true;
528 __gshared bool drawLights = false;
529 private {
530 __gshared int lightCount = 0;
531 __gshared float[4][8] lightColor;
532 __gshared float[3][8] lightPos;
536 // ////////////////////////////////////////////////////////////////////////// //
537 void lightsClear () {
538 lightCount = 0;
542 void lightAdd (float x, float y, float z, float r, float g, float b) {
543 if (lightCount < 8) {
544 lightColor[lightCount][0] = r;
545 lightColor[lightCount][1] = g;
546 lightColor[lightCount][2] = b;
547 lightColor[lightCount][3] = 1.0f;
548 lightPos[lightCount][0] = x;
549 lightPos[lightCount][1] = y;
550 lightPos[lightCount][2] = z;
551 ++lightCount;
556 // ////////////////////////////////////////////////////////////////////////// //
557 void drawModel (float angle, EliteModel shipModel) {
558 import iv.glbinds;
560 if (shipModel is null) return;
562 //glClearColor(0.2, 0.2, 0.2, 0);
563 //glClear(shipModel.glClearFlags);
565 //glEnable(GL_DEPTH_TEST);
566 //glDepthFunc(GL_LEQUAL);
567 //glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
568 glClearDepth(1.0f);
570 // setup projection
571 glMatrixMode(GL_PROJECTION);
572 glLoadIdentity();
573 oglPerspective(
574 90.0, // field of view in degree
575 1.0, // aspect ratio
576 1.0, // Z near
577 10000.0, // Z far
579 float zz = shipModel.bbox[1].z-shipModel.bbox[0].z;
580 zz += 10;
581 //if (zz < 20) zz = 20;
582 oglLookAt(
583 0.0, 0.0, -zz, // eye is at (0,0,5)
584 0.0, 0.0, 0, // center is at (0,0,0)
585 0.0, 1.0, 0.0, // up is in positive Y direction
588 // setup model matrix
589 glMatrixMode(GL_MODELVIEW);
590 glLoadIdentity();
592 // setup lighting
595 static immutable float[4] ldiff0 = [1.0, 1.0, 0.0, 1.0];
596 static immutable float[3] lpos0 = [-20.0, 0.0, -20.0-20];
597 glLightfv(GL_LIGHT0, GL_DIFFUSE, ldiff0.ptr);
598 glLightfv(GL_LIGHT0, GL_POSITION, lpos0.ptr);
599 glEnable(GL_LIGHT0);
602 static immutable float[4] ldiff1 = [1.0, 0.0, 0.0, 1.0];
603 static immutable float[3] lpos1 = [20.0, -20.0, 20.0-20];
604 glLightfv(GL_LIGHT1, GL_DIFFUSE, ldiff1.ptr);
605 glLightfv(GL_LIGHT1, GL_POSITION, lpos1.ptr);
606 glEnable(GL_LIGHT1);
611 lightsClear();
612 lightAdd(
613 0, zz, -50,
614 1.0, 0.0, 0.0
616 lightAdd(
617 zz/2, zz/2, zz,
618 1.0, 1.0, 1.0
622 glDisable(GL_LIGHTING);
623 if (doLights) {
624 glShadeModel(GL_SMOOTH);
625 __gshared float[4][8] ldiff = void;
626 __gshared float[3][8] lpos = void;
627 if (drawLights) {
628 foreach (uint idx; 0..lightCount) {
629 ldiff[idx] = lightColor.ptr[idx][];
630 lpos[idx] = lightPos.ptr[idx][];
631 glColor4f(ldiff[idx][0], ldiff[idx][1], ldiff[idx][2], 1.0);
633 glBegin(/*GL_QUADS*/GL_TRIANGLE_FAN);
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 glVertex3f(lpos[idx][0]-1, lpos[idx][1]+1, lpos[idx][2]);
638 glEnd();
641 glPointSize(5);
642 glBegin(GL_POINTS);
643 glVertex3fv(lpos[idx].ptr);
644 glEnd();
645 glPointSize(1);
648 glColor3f(1, 1, 1);
651 __gshared float[4] ambcol;
652 ambcol[0] = 0.6f;
653 ambcol[1] = 0.6f;
654 ambcol[2] = 0.6f;
655 ambcol[3] = 1.0f;
656 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambcol.ptr);
657 foreach (uint idx; 0..lightCount) {
658 ldiff[idx] = lightColor[idx][];
659 lpos[idx] = lightPos[idx][];
660 //{ import std.stdio; writeln("LIGHT #", idx, " at ", lightPos[idx][], " color ", lightColor[idx][]); }
661 glEnable(GL_LIGHT0+idx);
662 //glLightfv(GL_LIGHT0+idx, GL_DIFFUSE, &lightColor[idx][0]);
663 //glLightfv(GL_LIGHT0+idx, GL_POSITION, &lightPos[idx][0]);
664 assert((&ldiff[0])+1 == &ldiff[1]);
665 glLightfv(GL_LIGHT0+idx, GL_DIFFUSE, ldiff[idx].ptr);
666 //glLightfv(GL_LIGHT0+idx, GL_SPECULAR, ldiff[idx].ptr);
667 glLightfv(GL_LIGHT0+idx, GL_POSITION, lpos[idx].ptr);
669 glEnable(GL_LIGHTING);
671 version(none) {
673 static immutable float[4] ldiff0 = [1.0, 0.0, 0.0, 1.0];
674 static immutable float[3] lpos0 = [-90.0, 0.0, 90.0];
676 __gshared float[4] ldiff0 = [1.0, 0.0, 0.0, 1.0];
677 __gshared float[3] lpos0 = [-90.0, 0.0, 90.0];
678 //lightColor[0] = ldiff0[];
679 //lightPos[0] = lpos0[];
680 //glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor[0].ptr);
681 //glLightfv(GL_LIGHT0, GL_POSITION, lightPos[0].ptr);
682 glLightfv(GL_LIGHT0, GL_DIFFUSE, ldiff0.ptr);
683 glLightfv(GL_LIGHT0, GL_POSITION, lpos0.ptr);
684 //glEnable(GL_LIGHT0);
685 //glEnable(GL_LIGHTING);
689 doLight(
690 90, 40, -40,
691 1.0, 0.0, 0.0
693 doLight(
694 -90, 0, 90,
695 1.0, 1.0, 1.0
700 doLight(
701 zz, zz/2, -zz/2,
702 1.0, 0.0, 0.0
706 doLight(
707 0, zz, -50,
708 1.0, 0.0, 0.0
710 doLight(
711 zz/2, zz/2, zz,
712 1.0, 1.0, 1.0
716 //angle = 142;
718 // rotate model
719 glRotatef(angle, 0.8, 0.5, 0.3);
721 glRotatef(angle, 0.8, 0.0, 0.0);
722 glRotatef(angle, 0.0, 0.3, 0.0);
723 glRotatef(angle, 0.0, 0.0, 0.1);
726 version(none) {
727 // enable color tracking
728 glEnable(GL_COLOR_MATERIAL);
729 // set material properties which will be assigned by glColor
730 glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
731 //glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
732 // blue reflective properties
733 glColor3f(0.0f, 0.5f, 1.0f);
736 //glEnable(GL_LIGHTING);
737 shipModel.glDraw();
738 shipModel.glDrawExhaust();
740 if (doLights) {
741 foreach (uint idx; 0..lightCount) glDisable(GL_LIGHT0+idx);
742 glDisable(GL_LIGHTING);
743 glShadeModel(GL_FLAT);
745 //glDisable(GL_DEPTH_TEST);