3 #if (defined(ECERE_VANILLA) || defined(ECERE_ONEDRIVER)) && defined(__WIN32__)
4 #define ECERE_NOTRUETYPE
12 import "DisplaySystem"
15 import "BitmapResource"
17 import "LFBDisplayDriver"
19 // TOFIX: Temporary until we pass Display instead of DisplaySystem to FontExtent
20 #if defined(__WIN32__) && !defined(ECERE_NOTRUETYPE)
21 import "GDIDisplayDriver"
24 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
34 #if (!defined(ECERE_VANILLA) && !defined(ECERE_ONEDRIVER))
35 import "OpenGLDisplayDriver"
44 public class GLCapabilities : uint
47 // Expect reloading graphics
52 bool legacyFormats :1;
53 bool nonPow2Textures :1;
54 bool vertexPointer :1;
56 // Should be able to toggle without reloading
59 bool fixedFunction :1;
70 public enum RenderState { fillMode = 1, depthTest, depthWrite, fogDensity, fogColor, blend, ambient, alphaWrite, antiAlias, vSync };
72 public union RenderStateFloat { float f; uint ui; };
74 public enum FillModeValue { solid, wireframe };
76 public class DisplayFlags
78 public bool fullScreen:1, flipping:1, alpha:1, memBackBuffer:1, text:1, scrolling:1, printer:1;
80 public class FontFlags
82 public bool bold:1, italic:1, underline:1;
85 __attribute__((unused)) static void DummyFunction()
87 #if !defined(__EMSCRIPTEN__)
92 public class DisplayDriver
95 class_data const char * name;
96 class_data bool textMode;
97 class_data bool printer;
98 class_data DisplaySystem displaySystem;
100 class_property DisplaySystem displaySystem
102 set { class_data(displaySystem) = value; }
103 get { return class_data(displaySystem); }
106 class_property const char * name
108 set { class_data(name) = value; }
109 get { return class_data(name); }
112 class_property bool printer
114 set { class_data(printer) = value; }
115 get { return class_data(printer); }
118 // Constructor / Destructor
119 virtual bool ::CreateDisplaySystem(DisplaySystem);
120 virtual void ::DestroyDisplaySystem(DisplaySystem);
122 virtual bool ::CreateDisplay(Display);
123 virtual void ::DestroyDisplay(Display);
125 // Display Position and Size
126 virtual bool ::DisplaySize(Display, int, int);
127 virtual void ::DisplayPosition(Display, int, int);
130 virtual void ::SetPalette(Display, ColorAlpha *, bool);
131 virtual void ::RestorePalette(Display);
133 // Display the back buffer content
134 virtual void ::StartUpdate(Display);
135 virtual void ::Scroll(Display, Box, int, int, Extent);
136 virtual void ::Update(Display, Box);
137 virtual void ::EndUpdate(Display);
139 // Allocate/free a bitmap
140 virtual bool ::AllocateBitmap(DisplaySystem, Bitmap, int, int, int, PixelFormat, bool);
141 virtual void ::FreeBitmap(DisplaySystem, Bitmap);
144 virtual bool ::LockSystem(DisplaySystem displaySystem);
145 virtual void ::UnlockSystem(DisplaySystem displaySystem);
147 virtual bool ::Lock(Display);
148 virtual void ::Unlock(Display);
150 // Get/release a surface
151 virtual bool ::GetSurface(Display, Surface surface, int,int,Box);
152 virtual bool ::GetBitmapSurface(DisplaySystem displaySystem, Surface surface, Bitmap bitmap, int,int,Box);
153 virtual void ::ReleaseSurface(Display this, Surface);
156 virtual void ::Clip(Display, Surface, Box);
158 // Grab from the screen
159 virtual bool ::GrabScreen(Display, Bitmap, int, int, unsigned int, unsigned int);
161 // Converts a bitmap format
162 virtual bool ::ConvertBitmap(DisplaySystem, Bitmap, PixelFormat, ColorAlpha *);
164 // Converts an LFB bitmap into an offscreen bitmap for this device
165 virtual bool ::MakeDDBitmap(DisplaySystem, Bitmap, bool mipMaps, int cubeMapFace);
168 virtual Font ::LoadFont(DisplaySystem displaySystem, const char * faceName, float size, FontFlags flags, float outlineSize, float outlineFade);
169 virtual void ::UnloadFont(DisplaySystem, Font);
172 virtual void ::SetForeground(Display, Surface, ColorAlpha);
173 virtual void ::SetBackground(Display, Surface, ColorAlpha);
174 virtual void ::LineStipple(Display, Surface, uint pattern);
175 virtual ColorAlpha ::GetPixel(Display, Surface, int x, int y);
176 virtual void ::PutPixel(Display, Surface, int x, int y);
177 virtual void ::DrawLine(Display, Surface, int x1, int y1, int x2, int y2);
178 virtual void ::Rectangle(Display, Surface, int x1, int y1, int x2, int y2);
179 virtual void ::Area(Display, Surface, int x1, int y1, int x2, int y2);
180 virtual void ::Clear(Display, Surface, ClearType);
181 virtual void ::Blit(Display, Surface, Bitmap, int dx, int dy, int sx, int sy, int w, int h);
182 virtual void ::Stretch(Display, Surface, Bitmap, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh);
183 virtual void ::Filter(Display, Surface, Bitmap, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh);
184 virtual void ::BlitDI(Display, Surface, Bitmap, int dx, int dy, int sx, int sy, int w, int h);
185 virtual void ::StretchDI(Display, Surface, Bitmap, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh);
186 virtual void ::FilterDI(Display, Surface, Bitmap, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh);
187 virtual void ::TextFont(Display, Surface, Font);
188 virtual void ::TextOpacity(Display, Surface, bool);
189 virtual void ::WriteText(Display, Surface, int x, int y, const String text, int len, int prevGlyph, int * rPrevGlyph);
190 virtual void ::TextExtent(Display, Surface, const String text, int len, int * tw, int * th, int prevGlyph, int * rPrevGlyph, int * overHang);
191 virtual void ::FontExtent(DisplaySystem, Font, const String text, int len, int * tw, int * th, int prevGlyph, int * rPrevGlyph, int * overHang);
192 virtual void ::DrawingChar(Display, Surface, char ch);
193 virtual void ::NextPage(Display);
194 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
196 virtual void ::SetRenderState(Display, RenderState, uint);
197 virtual void ::SetLight(Display, int, Light);
198 virtual void ::SetCamera(Display, Surface, Camera);
199 virtual bool ::AllocateMesh(DisplaySystem, Mesh, MeshFeatures, int nVertices);
200 virtual void ::FreeMesh(DisplaySystem, Mesh);
201 virtual bool ::LockMesh(DisplaySystem, Mesh, MeshFeatures flags);
202 virtual void ::UnlockMesh(DisplaySystem, Mesh, MeshFeatures flags);
203 virtual void * ::AllocateIndices(DisplaySystem, int nIndices, bool indices32bit);
204 virtual void ::FreeIndices(DisplaySystem, void * indices);
205 virtual uint16 * ::LockIndices(DisplaySystem, void * indices);
206 virtual void ::UnlockIndices(DisplaySystem, void * indices, bool indices32bit, int nIndices);
207 virtual void ::SelectMesh(Display, Mesh);
208 virtual void ::ApplyMaterial(Display, Material, Mesh);
209 virtual void ::DrawPrimitives(Display, PrimitiveSingle *, Mesh mesh);
210 virtual void ::PushMatrix(Display);
211 virtual void ::PopMatrix(Display, bool);
212 virtual void ::SetTransform(Display, Matrix, bool, bool);
214 virtual void ::SetBlitTint(Display, Surface, ColorAlpha);
217 public enum Alignment { left, right, center };
218 public enum ClearType { colorBuffer, depthBuffer, colorAndDepth };
220 define textCellW = 8;
221 define textCellH = 16;
223 public enum PixelFormat // : byte MESSES UP GuiApplication
225 pixelFormat4, pixelFormat8, pixelFormat444, pixelFormat555, pixelFormat565, pixelFormat888, pixelFormatAlpha, pixelFormatText, pixelFormatRGBA
227 public enum Resolution : int
229 resText80x25, res320x200, res320x240, res320x400, res360x480, res400x256, res400x300, res512x256, res512x384,
230 res640x200, res640x350, res640x400, res640x480, res720x348, res800x600, res856x480, res960x720, res1024x768,
231 res1152x864, res1280x1024, res1600x1200, res768x480
234 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
235 public class LightFlags
237 public bool off:1, spot:1, omni:1, attenuation:1;
247 Quaternion orientation;
260 public define NumberOfLights = 8;
262 // Painter's algorithm
264 public class HitRecord : struct
267 HitRecord prev, next;
271 void * tags[1]; // More tags may follow
273 int Compare(HitRecord recordB, void * unused)
275 if(center.z > recordB.center.z)
277 else if(center.z < recordB.center.z)
279 else if(pos > recordB.pos)
281 else if(pos < recordB.pos)
288 #define EPSILON 0.00001
292 PrimitiveSingle * triangle;
299 int Compare(SortPrimitive primitive2)
302 if(ZOverlap(primitive2) && Sgn(plane.d) != Sgn(primitive2.plane.d))
303 value = plane.d - primitive2.plane.d;
305 value = middle.z - primitive2.middle.z;
309 else if(value<-EPSILON)
315 bool ZOverlap(SortPrimitive poly2)
317 if(min.z > poly2.max.z - EPSILON || poly2.min.z > max.z - EPSILON)
323 bool XYOverlap(SortPrimitive poly2)
325 if(min.x > poly2.max.x - EPSILON || poly2.min.x > max.x - EPSILON )
327 if(min.y > poly2.max.y - EPSILON || poly2.min.y > max.y - EPSILON )
332 bool SurfaceOutside(SortPrimitive poly2)
336 PrimitiveSingle * primitive = triangle;
337 Mesh mesh = object.mesh;
338 Matrix * matrix = &object.matrix;
340 double a = poly2.plane.a, b = poly2.plane.b, c = poly2.plane.c, d = poly2.plane.d;
346 d = - (a * poly2.middle.x + b * poly2.middle.y + c * poly2.middle.z);
349 for(v = 0; v < primitive->nIndices; v++)
352 Vector3Df * local = &mesh.vertices[primitive->indices[v]];
355 vertex.MultMatrix(local, matrix);
357 surface = a * vertex.x + b * vertex.y + c * vertex.z + d;
359 if(surface < EPSILON)
372 bool SurfaceInside(SortPrimitive poly2)
376 PrimitiveSingle * primitive = poly2.triangle;
377 Mesh mesh = poly2.object.mesh;
378 Matrix * matrix = &poly2.object.matrix;
380 double a = plane.a, b = plane.b, c = plane.c, d = plane.d;
386 d = - (a * middle.x + b * middle.y + c * middle.z);
389 for(v = 0; v < primitive->nIndices; v++)
392 Vector3Df * local = &mesh.vertices[primitive->indices[v]];
395 vertex.MultMatrix(local, matrix);
397 surface = a * vertex.x + b * vertex.y + c * vertex.z + d;
398 if(surface > -EPSILON)
411 bool ShouldBeSwapped(SortPrimitive poly2)
413 if (!XYOverlap(poly2)) return false;
414 if (SurfaceOutside(poly2)) return false;
415 if (SurfaceInside(poly2)) return false;
423 #define MAX_CLIP_POINTS 50
432 displaySystem.numDisplays--;
433 displaySystem.driver.DestroyDisplay(this);
435 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
440 bool Create(DisplaySystem displaySystem, void * window)
445 this.displaySystem = displaySystem;
446 this.window = window;
447 displaySystem.numDisplays++;
448 if(displaySystem.driver.CreateDisplay(this))
450 // if(!result) LogErrorCode(DisplayInitFailed, displaySystem.driver.name);
455 Surface GetSurface(int x, int y, Box clip)
457 Surface result = null;
458 Surface surface { _refCount = 1 };
461 Box box { -x, -y, -x + width - 1, -y + height - 1 };
464 surface.width = width - x;
465 surface.height = height - y;
466 surface.driver = displaySystem.driver;
467 surface.displaySystem = displaySystem;
468 surface.display = this;
470 if(displaySystem.driver.GetSurface(this, surface, x, y, box))
478 bool Resize(int width, int height)
480 return displaySystem.driver.DisplaySize(this, width, height);
483 void Position(int x, int y)
485 displaySystem.driver.DisplayPosition(this, x,y);
488 void StartUpdate(void)
490 displaySystem.driver.StartUpdate(this);
493 void Scroll(Box scroll, int x, int y, Extent dirty)
495 displaySystem.driver.Scroll(this, scroll, x, y, dirty);
498 void Update(Box updateBox)
500 displaySystem.driver.Update(this, updateBox);
505 displaySystem.driver.EndUpdate(this);
510 displaySystem.driver.NextPage(this);
513 bool Grab(Bitmap bitmap, int x, int y, int w, int h)
516 if(bitmap && w > 0 && h > 0 &&
517 displaySystem.driver.GrabScreen(this, bitmap, x, y, w, h))
524 void FontExtent(Font font, const char * text, int len, int * width, int * height)
527 FontExtent2(font, text, len, width, height, 0, null, &overHang);
528 if(width) *width += overHang;
531 void FontExtent2(Font font, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * overHang)
533 // Fix for OnLoadGraphics time alpha blended window text extent on GDI
534 #if defined(__WIN32__) && !defined(ECERE_NOTRUETYPE)
535 if(this && alphaBlend && pixelFormat == pixelFormat888 &&
536 displaySystem.driver == class(GDIDisplayDriver))
538 Surface s = GetSurface(0,0,null);
542 s.TextExtent2(text, len, width, height, prevGlyph, rPrevGlyph, overHang);
548 // TODO: Should really pass display here...
549 DisplaySystem::FontExtent2(this ? displaySystem : null, font, text, len, width, height, prevGlyph, rPrevGlyph, overHang);
552 void SetPalette(ColorAlpha * palette, bool colorMatch)
554 displaySystem.driver.SetPalette(this, palette, colorMatch);
557 void RestorePalette(void)
559 displaySystem.driver.RestorePalette(this);
562 bool Lock(bool render)
567 for(c = 0; c<current; c++)
569 Logf("Locking (%d)\n", current+1);
572 // TOCHECK: Why is displaySystem null with GISDesigner?
573 result = displaySystem && displaySystem.Lock();
576 #if !defined(__EMSCRIPTEN__)
581 result = displaySystem.driver.Lock(this);
597 for(c = 0; c<current; c++)
599 Logf("Unlocking (%d)\n", current);
602 if(!current && displaySystem)
603 displaySystem.driver.Unlock(this);
604 #if !defined(__EMSCRIPTEN__)
609 displaySystem.Unlock();
612 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
613 // *** 3D GRAPHICS ***
614 void SetCamera(Surface surface, Camera camera)
618 display3D = Display3D { };
620 if(!display3D.selection)
625 if(!display3D.selection)
626 displaySystem.driver.SelectMesh(this, null);
628 display3D.material = null;
629 display3D.mesh = null;
631 if(!display3D.selection)
633 displaySystem.driver.SetCamera(this, surface, camera);
636 this.display3D.camera = camera;
641 camera.Setup(width, height, null);
643 // Always calling Update() here had broken interpolation in OrbitWithMouse!
644 if(!camera.cAngle.w && surface)
647 if(display3D.selection)
649 // Compute Picking Planes
651 Vector3D point { 0,0,0 };
653 Angle fovLeft, fovRight, fovTop, fovBottom;
656 double l = camera.origin.x - (display3D.pickX - display3D.pickWidth/2.0f);
657 double r = camera.origin.x - (display3D.pickX + display3D.pickWidth/2.0f);
658 double t = (display3D.pickY - display3D.pickHeight/2.0f) - camera.origin.y;
659 double b = (display3D.pickY + display3D.pickHeight/2.0f) - camera.origin.y;
661 fovLeft = atan(l / camera.focalX);
662 fovRight = atan(r / camera.focalX);
663 fovTop = atan(t / camera.focalY);
664 fovBottom = atan(b / camera.focalY);
667 quat.Yaw(fovLeft - Pi/2);
668 quat.ToDirection(normal);
669 display3D.viewPickingPlanes[left].FromPointNormal(normal, point);
672 quat.Yaw(fovRight + Pi/2);
673 quat.ToDirection(normal);
674 display3D.viewPickingPlanes[right].FromPointNormal(normal, point);
677 quat.Pitch(fovTop + Pi/2);
678 quat.ToDirection(normal);
679 display3D.viewPickingPlanes[top].FromPointNormal(normal, point);
682 quat.Pitch(fovBottom - Pi/2);
683 quat.ToDirection(normal);
684 display3D.viewPickingPlanes[bottom].FromPointNormal(normal, point);
687 normal.x = 0; normal.y = 0; normal.z = 1;
688 point.z = camera.zMin;
689 display3D.viewPickingPlanes[near].FromPointNormal(normal, point);
692 normal.x = 0; normal.y = 0; normal.z = -1;
693 point.z = camera.zMax;
694 display3D.viewPickingPlanes[far].FromPointNormal(normal, point);
696 for(c = 0; c<ClippingPlane::enumSize; c++)
697 display3D.worldPickingPlanes[c].MultMatrix(display3D.viewPickingPlanes[c], camera.inverseTranspose);
699 // Compute picking ray
702 display3D.rayView.p0 = { 0, 0, 0 };
703 p.x = display3D.pickX;
704 p.y = display3D.pickY;
706 camera.Unproject(p, display3D.rayView.delta);
708 // Convert ray to world space
709 camera.Untransform(display3D.rayView.p0, display3D.rayWorld.p0);
710 camera.Untransform(display3D.rayView.delta, p);
711 display3D.rayWorld.delta.Subtract(p, display3D.rayWorld.p0);
718 void SetLight(int id, Light light)
722 display3D = Display3D { };
724 displaySystem.driver.SetLight(this, id, light);
727 void SetLights(Object object)
730 display3D._SetLights(this, object, 0);
733 // --- Transformations ---
735 void SetTransform(Matrix matrix, bool viewSpace)
737 if(display3D.selection)
741 transpose.Transpose(matrix);
745 for(c = 0; c<ClippingPlane::enumSize; c++)
746 display3D.localPickingPlanes[c].MultMatrix(display3D.viewPickingPlanes[c], transpose);
750 for(c = 0; c<ClippingPlane::enumSize; c++)
751 display3D.localPickingPlanes[c].MultMatrix(display3D.worldPickingPlanes[c], transpose);
755 if(display3D.intersecting)
759 p2.Add(display3D.rayView.p0, display3D.rayView.delta);
761 p2.Add(display3D.rayWorld.p0, display3D.rayWorld.delta);
763 display3D.rayLocal.p0.DivideMatrix(display3D.rayWorld.p0, matrix);
764 tp2.DivideMatrix(p2, matrix);
765 display3D.rayLocal.delta.Subtract(tp2, display3D.rayLocal.p0);
769 displaySystem.driver.SetTransform(this, matrix, viewSpace, viewSpace ? false : true);
772 void PushMatrix(void)
774 displaySystem.driver.PushMatrix(this);
779 displaySystem.driver.PopMatrix(this, true);
783 void ApplyMaterial(Material material, Mesh mesh)
785 if(material != display3D.material)
787 display3D.material = material;
788 displaySystem.driver.ApplyMaterial(this, material, mesh);
792 void DrawPrimitives(PrimitiveSingle primitive, Mesh mesh)
794 displaySystem.driver.DrawPrimitives(this, primitive, mesh);
797 void SelectMesh(Mesh mesh)
799 displaySystem.driver.SelectMesh(this, mesh);
801 display3D.mesh = mesh;
804 bool DrawMesh(Object object)
807 if(display3D.selection)
808 result = display3D.PickMesh(object, null);
811 Mesh mesh = object.mesh;
812 Material objectMaterial = object.material;
814 if(mesh.groups.first)
816 PrimitiveGroup group;
817 displaySystem.driver.SelectMesh(this, mesh);
818 display3D.mesh = mesh;
820 for(group = mesh.groups.first; group; group = group.next)
822 Material material = group.material ? group.material : objectMaterial;
823 if(!material) material = defaultMaterial;
825 if(material != display3D.material)
827 display3D.material = material;
828 displaySystem.driver.ApplyMaterial(this, material, mesh);
831 // *** Render Vertex Arrays ***
832 displaySystem.driver.DrawPrimitives(this, (PrimitiveSingle *)&group.type, mesh);
836 if(object.flags.translucent)
839 Matrix inverse, inverseTranspose;
842 if(object.flags.viewSpace)
843 matrix = object.matrix;
846 Camera camera = display3D.camera;
847 Matrix temp = object.matrix;
848 temp.m[3][0] -= camera.cPosition.x;
849 temp.m[3][1] -= camera.cPosition.y;
850 temp.m[3][2] -= camera.cPosition.z;
851 matrix.Multiply(temp, camera.viewMatrix);
854 inverse.Inverse(matrix);
855 inverseTranspose.Transpose(inverse);
857 for(c = 0; c < mesh.nPrimitives; c++)
859 PrimitiveSingle * triangle = &mesh.primitives[c];
860 SortPrimitive * sort;
861 Plane * plane = &triangle->plane;
862 if(display3D.nTriangles >= display3D.maxTriangles)
864 display3D.maxTriangles = display3D.maxTriangles ? (display3D.maxTriangles * 3 / 2) : 32768;
865 display3D.triangles = renew display3D.triangles SortPrimitive[display3D.maxTriangles];
867 sort = &display3D.triangles[display3D.nTriangles++];
868 sort->object = object;
869 sort->triangle = triangle;
870 sort->middle.MultMatrix(triangle->middle, matrix);
871 sort->middle.z *= -1;
872 // sort->plane.MultMatrix(triangle->plane, inverseTranspose);
873 sort->plane.d = plane->a * inverseTranspose.m[0][3] +
874 plane->b * inverseTranspose.m[1][3] +
875 plane->c * inverseTranspose.m[2][3] +
876 plane->d * inverseTranspose.m[3][3];
882 displaySystem.driver.SelectMesh(this, mesh);
883 display3D.mesh = mesh;
885 for(c = 0; c<mesh.nPrimitives; c++)
887 PrimitiveSingle * primitive = &mesh.primitives[c];
889 Material material = primitive->material ? primitive->material : objectMaterial;
890 if(!material) material = defaultMaterial;
892 if(material != display3D.material)
894 display3D.material = material;
895 displaySystem.driver.ApplyMaterial(this, material, mesh);
898 displaySystem.driver.DrawPrimitives(this, primitive, display3D.mesh);
906 bool IsObjectVisible(Object object)
909 if(display3D.selection || !display3D.camera)
910 planes = object.flags.viewSpace ? display3D.viewPickingPlanes : display3D.worldPickingPlanes;
912 planes = object.flags.viewSpace ? display3D.camera.viewClippingPlanes : display3D.camera.worldClippingPlanes;
913 return object.InsideFrustum(planes) != outside;
916 bool DrawObject(Object object)
919 if(object && object.volume)
922 FrustumPlacement visible;
924 Camera camera = display3D.camera;
926 if(display3D.selection || !camera)
927 planes = object.flags.viewSpace ? display3D.viewPickingPlanes : display3D.worldPickingPlanes;
929 planes = object.flags.viewSpace ? camera.viewClippingPlanes : camera.worldClippingPlanes;
931 visible = object.InsideFrustum(planes);
933 if(visible || display3D.pickingPlanes)
935 if(display3D.collectingHits && object.tag)
937 /*if(object.flags.root)
938 this.tags[display3D.tagIndex] = object.tag;
940 this.tags[++display3D.tagIndex] = object.tag;
942 display3D.tags[display3D.tagIndex++] = object.tag;
945 if(object.flags.mesh && object.mesh)
947 if(!display3D.selection && displaySystem.driver.PushMatrix)
948 displaySystem.driver.PushMatrix(this);
951 if(object.mesh.tangents && object.mesh.normals && object.flags.computeLightVectors)
953 Mesh mesh = object.mesh;
956 int count = mesh.nVertices;
957 Vector3Df * normals = mesh.normals;
958 Vector3Df * vertices = mesh.vertices;
959 ColorRGB * lightVectors;
960 Vector3Df * tangents = mesh.tangents;
962 float * l = display3D.light0Pos;
963 Vector3Df light { l[0], l[1], l[2] };
964 Matrix o = object.matrix;
965 Matrix t, inv = camera.viewMatrix;
967 Vector3D cPos = camera.cPosition;
969 bool positional = l[3] ? true : false;
971 inv.Scale(1.0/nearPlane, -1.0/nearPlane,-1.0/nearPlane);
973 pos.MultMatrix(cPos, camera.viewMatrix);
975 ot.x = o.m[3][0] + pos.x;
976 ot.y = o.m[3][1] + pos.y;
977 ot.z = o.m[3][2] + pos.z;
986 mesh.Allocate({ lightVectors = true }, mesh.nVertices, displaySystem);
987 mesh.Lock({ lightVectors = true });
988 lightVectors = mesh.lightVectors;
989 for(i = 0; i < count; i++)
991 Vector3Df tangent1 = tangents[i*2 + 0];
992 Vector3Df tangent2 = tangents[i*2 + 1];
993 Vector3Df normal = normals[i];
994 Vector3Df tTangent1, tTangent2, tNormal;
996 tTangent1.MultMatrix(tangent1, inv);
997 tTangent2.MultMatrix(tangent2, inv);
998 tNormal .MultMatrix(normal, inv);
1000 tTangent1.Normalize(tTangent1);
1001 tTangent2.Normalize(tTangent2);
1002 tNormal .Normalize(tNormal);
1007 tTangent1.x, tTangent2.x, tNormal.x, 0,
1008 tTangent1.y, tTangent2.y, tNormal.y, 0,
1009 tTangent1.z, tTangent2.z, tNormal.z, 1
1014 Vector3Df tPos = vertices[i];
1015 tPos.x += ot.x, tPos.y += ot.y, tPos.z += ot.z;
1017 // Subtract vertex from light for positional lights
1018 light.x = l[0] - tPos.x;
1019 light.y = l[1] + tPos.y;
1020 light.z = l[2] - tPos.z;
1022 n.MultMatrix(light, tbn);
1025 lightVectors[i] = { n.x / 2 + 0.5f, n.y / 2 + 0.5f, n.z / 2 + 0.5f };
1028 mesh.Unlock({ lightVectors = true });
1030 // Create normalization cube map
1035 int w = 256, h = 256, d = 256;
1036 Vector3Df min = mesh.min, max = mesh.max;
1039 (max.x - min.x) / w,
1040 (max.y - min.y) / h,
1044 for(i = 0; i < 6; i++)
1046 Bitmap face = i > 0 ? { } : mesh.normMap;
1050 face.Allocate(null, w, h, 0, pixelFormat888, false);
1051 face.driverData = mesh.normMap.driverData;
1052 p = (ColorAlpha *)face.picture;
1053 for(y = 0; y < h; y++)
1055 for(x = 0; x < w; x++, p++)
1057 Vector3Df v { min.x + x * delta.x, min.y + y * delta.y, min.z };
1059 *p = ColorAlpha { 255, {
1060 (byte)((v.x / 2.0 + 0.5) * 255),
1061 (byte)((v.y / 2.0 + 0.5) * 255),
1062 (byte)((v.z / 2.0 + 0.5) * 255) } };
1065 displaySystem.driver.MakeDDBitmap(displaySystem, face, true, (i + 1));
1068 face.driverData = 0;
1076 mesh.Free({ lightVectors = true });
1080 SetTransform(object.matrix, object.flags.viewSpace);
1081 if(display3D.selection)
1083 if(visible == intersecting || display3D.intersecting)
1085 Vector3D rayIntersect;
1086 if(display3D.PickMesh(object, rayIntersect))
1088 if(display3D.intersecting)
1090 Vector3D wresult, vresult;
1091 wresult.MultMatrix(rayIntersect, object.matrix);
1092 if(!object.flags.viewSpace)
1093 camera.TransformPoint(vresult, wresult);
1097 if(vresult.z < display3D.rayIntersect.z)
1098 display3D.rayIntersect = vresult;
1099 display3D.intersected = true;
1109 result |= DrawMesh(object);
1110 if(displaySystem.driver.PopMatrix)
1111 displaySystem.driver.PopMatrix(this, true);
1113 if(display3D.collectingHits && result /*&& object.tag*/)
1116 HitRecord hit = (HitRecord)new0 byte[sizeof(class HitRecord) + sizeof(void *) * (display3D.tagIndex/*+1*/)];
1117 display3D.hitList.Add(hit);
1118 hit.pos = display3D.hitList.count-1;
1119 hit.numTags = display3D.tagIndex /*+ 1*/;
1120 for(c = 0; c</*=*/display3D.tagIndex; c++)
1122 hit.tags[c] = display3D.tags[c];
1125 if(!object.flags.viewSpace)
1126 camera.TransformPoint(hit.center, object.wcenter);
1128 hit.center = object.wcenter;
1132 for(child = object.children.first; child; child = child.next)
1133 result |= DrawObject(child);
1135 if(display3D.collectingHits && /*!object.flags.root && */object.tag)
1136 display3D.tagIndex--;
1142 void DrawTranslucency(void)
1144 if(display3D && display3D.camera)
1146 // *** Render translucent primitives ***
1147 if(display3D.nTriangles)
1149 Matrix * matrix = null;
1154 display3D.SortTriangles();
1158 displaySystem.driver.PushMatrix(this);
1159 for(c=0; c<display3D.nTriangles; c++)
1161 SortPrimitive * sort = &display3D.triangles[c];
1162 Mesh mesh = sort->object.mesh;
1163 PrimitiveSingle * primitive = sort->triangle;
1166 if(&sort->object.matrix != matrix)
1168 matrix = &sort->object.matrix;
1170 displaySystem.driver.PopMatrix(this, false);
1171 displaySystem.driver.PushMatrix(this);
1172 SetTransform(matrix, sort->object.flags.viewSpace);
1174 if(mesh != display3D.mesh)
1176 displaySystem.driver.SelectMesh(this, mesh);
1177 display3D.mesh = mesh;
1180 material = primitive->material ? primitive->material : sort->object.material;
1181 if(!material) material = defaultMaterial;
1183 if(material != display3D.material)
1185 displaySystem.driver.ApplyMaterial(this, material, display3D.mesh);
1186 display3D.material = material;
1191 Material testMaterial { };
1194 amount = (display3D.triangles[0].middle.z - display3D.triangles[c].middle.z) /
1195 (display3D.triangles[0].middle.z - display3D.triangles[display3D.nTriangles-1].middle.z);
1197 testMaterial.flags.doubleSided = { doubleSided = true, translucent = true };
1198 testMaterial.diffuse.a = 1;
1199 testMaterial.emissive.r = testMaterial.emissive.g = testMaterial.emissive.b = amount;
1200 testMaterial.baseMap = material->baseMap;
1202 displaySystem.driver.ApplyMaterial(this, testMaterial, display3D.mesh);
1206 // *** Render primitive ***
1207 // if(sort->plane.d > 0)
1208 displaySystem.driver.DrawPrimitives(this, primitive, display3D.mesh);
1210 displaySystem.driver.PopMatrix(this, true);
1212 display3D.nTriangles = 0;
1219 void StartSelection(int pickX, int pickY, int pickW, int pickH)
1223 display3D = Display3D { };
1225 display3D.pickX = (float)pickX;
1226 display3D.pickY = (float)pickY;
1227 display3D.pickWidth = (float)pickW;
1228 display3D.pickHeight = (float)pickH;
1229 display3D.selection = true;
1232 void CollectHits(void)
1234 display3D.collectingHits = true;
1237 int GetHits(OldList list)
1239 display3D.collectingHits = false;
1240 display3D.hitList.Sort(HitRecord::Compare, null);
1241 list = display3D.hitList;
1242 display3D.hitList.Clear();
1246 void IntersectPolygons(void)
1248 display3D.rayIntersect = { MAXFLOAT, MAXFLOAT, MAXFLOAT };
1249 display3D.intersected = false;
1250 display3D.intersecting = true;
1253 bool GetIntersect(Vector3D intersect)
1255 intersect = display3D.rayIntersect;
1256 display3D.intersecting = false;
1257 return display3D.intersected;
1260 void StopSelection(void)
1262 display3D.selection = false;
1265 // --- Rendering States ---
1266 property FillModeValue fillMode { set { displaySystem.driver.SetRenderState(this, fillMode, value); } };
1267 property bool depthTest { set { displaySystem.driver.SetRenderState(this, depthTest, value); } };
1268 property bool depthWrite { set { displaySystem.driver.SetRenderState(this, depthWrite, value); } };
1269 property float fogDensity { set { displaySystem.driver.SetRenderState(this, fogDensity, RenderStateFloat { value }.ui); } };
1270 property Color fogColor { set { displaySystem.driver.SetRenderState(this, fogColor, value); } };
1271 property bool blend { set { displaySystem.driver.SetRenderState(this, blend, value); } };
1272 property Color ambient { set { displaySystem.driver.SetRenderState(this, ambient, value); } };
1273 property bool alphaWrite { set { displaySystem.driver.SetRenderState(this, alphaWrite, value); } };
1274 property bool antiAlias { set { displaySystem.driver.SetRenderState(this, antiAlias, value); } };
1275 property bool vSync { set { displaySystem.driver.SetRenderState(this, vSync, value); } };
1277 property bool pickingPlanes { set { display3D.pickingPlanes = value; } };
1279 property DisplayFlags flags { get { return displaySystem.flags; } }
1280 property PixelFormat pixelFormat { get { return /*alphaBlend ? pixelFormat888 : */displaySystem.pixelFormat; } }
1281 property bool alphaBlend { set { alphaBlend = value; } get { return alphaBlend; } };
1282 property bool useSharedMemory { set { useSharedMemory = value; } get { return useSharedMemory; } };
1283 property void * systemWindow { get { return window; } };
1284 property DisplaySystem displaySystem { get { return displaySystem; } };
1285 #if !defined(ECERE_VANILLA) && !defined(ECERE_ONEDRIVER)
1286 property GLCapabilities glCapabilities
1288 get { return ((OGLDisplay)driverData).capabilities; }
1291 glCapabilities = value;
1292 if(driverData && displaySystem.driver == class(OpenGLDisplayDriver))
1294 OGLDisplay oglDisplay = driverData;
1295 if(!oglDisplay.originalCapabilities.fixedFunction)
1296 value.shaders = true;
1297 if(!oglDisplay.originalCapabilities.shaders)
1298 value.fixedFunction = true;
1299 // Disable things that don't work with shaders
1302 value.fixedFunction = false;
1303 value.legacy = false;
1304 value.immediate = false;
1306 oglDisplay.capabilities = oglDisplay.originalCapabilities & value;
1309 OpenGLDisplayDriver::initialDisplaySetup(this, true, false);
1321 DisplaySystem displaySystem;
1324 #if !defined(__EMSCRIPTEN__)
1329 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
1330 Display3D display3D;
1333 void * windowDriverData;
1334 bool useSharedMemory;
1335 GLCapabilities glCapabilities;
1336 glCapabilities = { true, true, true, true, true, true, true, true };
1339 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
1340 private class Display3D : struct
1344 SortPrimitive * triangles;
1346 Vector3D points[MAX_CLIP_POINTS];
1347 Vector3D newPoints[MAX_CLIP_POINTS];
1348 byte goodPoints[MAX_CLIP_POINTS];
1353 Plane viewPickingPlanes[ClippingPlane], worldPickingPlanes[ClippingPlane];
1354 Plane localPickingPlanes[ClippingPlane];
1356 bool collectingHits, selection, intersecting, intersected, pickingPlanes;
1357 float pickX, pickY, pickWidth, pickHeight;
1362 Line rayView, rayWorld, rayLocal;
1363 Vector3D rayIntersect;
1371 int _SetLights(Display display, Object object, int id)
1373 if(id < NumberOfLights)
1377 if(object.flags.light && !object.light.flags.off)
1378 display.SetLight(id++, object.light);
1380 for(child = object.children.first; child; child = child.next)
1382 id = _SetLights(display, child, id);
1388 //#define TRESHOLD -1
1389 //#define TRESHOLD -0.25
1390 #define TRESHOLD -0.0025
1392 bool PickPrimitives(Mesh mesh, PrimitiveSingle primitive, Vector3D rayDiff, Vector3D rayIntersect)
1394 Plane * planes = localPickingPlanes;
1396 int nIndex = 1, nPoints = 1;
1398 bool result = false;
1399 Vector3D * points = this.points;
1400 Vector3D * newPoints = this.newPoints;
1401 byte * goodPoints = this.goodPoints;
1402 int nVertices = primitive.type.vertexRange ? primitive.nVertices : primitive.nIndices;
1405 bool i32bit = primitive.type.indices32bit;
1406 uint32 * indices32 = primitive.indices32;
1407 uint16 * indices16 = primitive.indices;
1409 switch(primitive.type.primitiveType)
1411 case triangles: nIndex = 3; nPoints = 3; break;
1412 case quads: nIndex = 4; nPoints = 4; break;
1415 nIndex = 1; nPoints = 3;
1417 tmp = primitive.type.vertexRange ? mesh.vertices[primitive.first] : mesh.vertices[(i32bit ? indices32[0] : indices16[0])];
1418 points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1419 tmp = primitive.type.vertexRange ? mesh.vertices[primitive.first+1] : mesh.vertices[(i32bit ? indices32[1] : indices16[1])];
1420 points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1424 for(c = offset; c<nVertices; c += nIndex)
1426 bool outside = false;
1433 if(primitive.type.vertexRange)
1435 if(primitive.type.primitiveType == triStrip)
1437 tmp = mesh.vertices[primitive.first + (c & 1) ? (c - 1) : (c - 2)];
1438 points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1439 tmp = mesh.vertices[primitive.first + (c & 1) ? (c - 2) : (c - 1)];
1440 points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1442 else if(primitive.type.primitiveType == triFan)
1444 tmp = mesh.vertices[primitive.first + 0];
1445 points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1446 tmp = mesh.vertices[primitive.first + c - 1];
1447 points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1449 for(i = 0; i<nIndex; i++)
1451 tmp = mesh.vertices[primitive.first + c+i];
1452 points[i + offset] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1457 if(primitive.type.primitiveType == triStrip)
1459 i = (c & 1) ? (c - 1) : (c - 2);
1460 tmp = mesh.vertices[(i32bit ? indices32[i] : indices16[i])];
1461 points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1463 i = (c & 1) ? (c - 2) : (c - 1);
1464 tmp = mesh.vertices[(i32bit ? indices32[i] : indices16[i])];
1465 points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1467 else if(primitive.type.primitiveType == triFan)
1469 tmp = mesh.vertices[(i32bit ? indices32[0] : indices16[0])];
1470 points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1471 tmp = mesh.vertices[(i32bit ? indices32[c-1] : indices16[c-1])];
1472 points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1474 for(i = 0; i<nIndex; i++)
1476 tmp = mesh.vertices[(i32bit ? indices32[c+i] : indices16[c+i])];
1477 points[i + offset] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1481 for(p = 0; p < 6; p++)
1483 Plane * plane = &planes[p];
1485 int numGoodPoints = 0;
1487 memset(goodPoints, 0, n);
1488 for(i = 0; i < n; i++)
1490 double dot = plane->normal.DotProduct(points[i]);
1491 double distance = dot + plane->d;
1492 if(distance > TRESHOLD)
1503 if(numGoodPoints < n)
1514 newPoints[newN++] = points[j];
1523 for(lastGood = n-1; !goodPoints[lastGood]; lastGood--);
1525 edge.p0 = points[lastGood];
1526 edge.delta.Subtract(points[j], edge.p0);
1527 plane->IntersectLine(edge, newPoints[newN++]);
1529 for(next = j+1; next != j; next++)
1531 if(next == n) next = 0;
1532 if(goodPoints[next])
1534 int prev = next - 1;
1535 if(prev < 0) prev = n-1;
1537 edge.p0 = points[prev];
1538 edge.delta.Subtract(points[next], edge.p0);
1539 plane->IntersectLine(edge, newPoints[newN++]);
1549 // Use the new points
1550 memcpy(points, newPoints, newN * sizeof(Vector3D));
1559 // TODO: Implement intersection with TriStrip, TriFan...
1562 // Intersect primitives
1564 Vector3D intersect, diff;
1565 int i0 = c, i1 = c+1, i2 = c+2;
1567 if(primitive.type.primitiveType == triStrip)
1569 i0 = (c & 1) ? (c - 1) : (c - 2);
1570 i1 = (c & 1) ? (c - 2) : (c - 1);
1573 else if(primitive.type.primitiveType == triFan)
1580 if(primitive.type.vertexRange)
1582 mesh.vertices[primitive.first + i0],
1583 mesh.vertices[primitive.first + i1],
1584 mesh.vertices[primitive.first + i2]);
1587 mesh.vertices[(i32bit ? indices32[i0] : indices16[i0])],
1588 mesh.vertices[(i32bit ? indices32[i1] : indices16[i1])],
1589 mesh.vertices[(i32bit ? indices32[i2] : indices16[i2])]);
1591 plane.IntersectLine(rayLocal, intersect);
1592 diff.Subtract(intersect, rayLocal.p0);
1593 diff.x /= rayLocal.delta.x;
1594 diff.y /= rayLocal.delta.y;
1595 diff.z /= rayLocal.delta.z;
1596 if(diff.x < rayDiff.x || diff.y < rayDiff.y || diff.z < rayDiff.z)
1599 rayIntersect = intersect;
1606 switch(primitive.type)
1609 points[strip] = points[2];
1613 points[1] = points[2];
1620 bool PickMesh(Object object, Vector3D rayIntersect)
1622 Mesh mesh = object.mesh;
1623 bool result = false;
1624 Vector3D rayDiff { MAXFLOAT, MAXFLOAT, MAXFLOAT };
1625 if(rayIntersect != null)
1626 rayIntersect = { MAXFLOAT, MAXFLOAT, MAXFLOAT };
1628 if(mesh.groups.first)
1630 PrimitiveGroup group;
1632 for(group = mesh.groups.first; group; group = group.next)
1634 if(PickPrimitives(mesh, (PrimitiveSingle *)&group.type, rayDiff, rayIntersect))
1645 for(c = 0; c < mesh.nPrimitives; c++)
1647 if(PickPrimitives(mesh, mesh.primitives[c], rayDiff, rayIntersect))
1658 void SortTriangles(void)
1661 Object object = null;
1663 for(c=0; c<nTriangles; c++)
1665 SortPrimitive * sort = &triangles[c];
1666 Mesh mesh = sort->object.mesh;
1667 PrimitiveSingle * primitive = sort->triangle;
1668 Vector3Df min { MAXFLOAT, MAXFLOAT, MAXFLOAT };
1669 Vector3Df max { -MAXFLOAT, -MAXFLOAT, -MAXFLOAT };
1671 bool ix32 = primitive->type.indices32bit;
1672 if(object != sort->object)
1674 object = sort->object;
1675 if(object.flags.viewSpace)
1676 matrix = object.matrix;
1679 Camera camera = this.camera;
1680 Matrix temp = object.matrix;
1681 temp.m[3][0] -= camera.cPosition.x;
1682 temp.m[3][1] -= camera.cPosition.y;
1683 temp.m[3][2] -= camera.cPosition.z;
1684 matrix.Multiply(temp, camera.viewMatrix);
1688 for(v = 0; v<primitive->nIndices; v++)
1690 Vector3Df * local = &mesh.vertices[ix32 ? primitive->indices32[v] : primitive->indices[v]];
1693 vertex.MultMatrix(local, &matrix);
1695 if(vertex.x > max.x) max.x = vertex.x;
1696 if(vertex.y > max.y) max.y = vertex.y;
1697 if(vertex.z > max.z) max.z = vertex.z;
1698 if(vertex.x < min.x) min.x = vertex.x;
1699 if(vertex.y < min.y) min.y = vertex.y;
1700 if(vertex.z < min.z) min.z = vertex.z;
1706 sort->marked = false;
1710 Logf("========= Before Sort ==========\n");
1711 for(c=0; c<nTriangles; c++)
1713 SortPrimitive * sort = &triangles[c];
1715 Mesh mesh = sort->mesh;
1716 PrimitiveSingle * primitive = sort->triangle;
1718 Logf("Triangle %d (%s):\n", c, primitive->material->name);
1720 for(v = 0; v<primitive->nIndices; v++)
1722 Vector3Df * local = &mesh.vertices[primitive->indices[v]];
1726 vertex.<MultMatrix(local, sort->matrix);
1728 Logf("Vertex %d:", v);
1730 // Logf(" Local %f, %f, %f:\n", local->x, local->y, local->z);
1731 Logf(" View %f, %f, %f:\n", vertex.x, vertex.y, vertex.z);
1735 Logf("Min %f, %f, %f:\n", sort->min.x, sort->min.y, sort->min.z);
1736 Logf("Max %f, %f, %f:\n", sort->max.x, sort->max.y, sort->max.z);
1740 // *** Sort translucent primitives ***
1741 qsort((void*) triangles, nTriangles, sizeof(SortPrimitive), SortPrimitive::Compare);
1743 Logf("\n\n========= After Sort ==========\n");
1744 for(c=0; c<nTriangles; c++)
1746 SortPrimitive * sort = &triangles[c];
1748 Mesh mesh = sort->mesh;
1749 PrimitiveSingle * primitive = sort->triangle;
1751 Logf("Triangle %d (%s):\n", c, primitive->material->name);
1753 for(v = 0; v<primitive->nIndices; v++)
1755 Vector3Df * local = &mesh.vertices[primitive->indices[v]];
1759 vertex.MultMatrix(local, sort->matrix);
1761 Logf("Vertex %d:", v);
1763 // Logf(" Local %f, %f, %f:\n", local->x, local->y, local->z);
1764 Logf(" View %f, %f, %f:\n", vertex.x, vertex.y, vertex.z);
1768 Logf("Min %f, %f, %f:\n", sort->min.x, sort->min.y, sort->min.z);
1769 Logf("Max %f, %f, %f:\n", sort->max.x, sort->max.y, sort->max.z);
1776 If all five tests fail for a particular Q,
1777 then P might obscure Q. Now Q must be tested.
1778 First, the algorithm checks if Q has been "marked."
1779 If Q is marked, then Q was "moved around" in the list
1780 during a previous iteration of the loop. The algorithm
1781 only allows a polygon to be moved once, to avoid the possibility
1782 of infinite loops. If Q is not marked, it is tested to see
1783 if it might obscure P. If Q cannot obscure P, then Q is possibly
1784 behind P and so it is good candidate to be drawn next.
1785 Therefore, the algorithm "abandons" the current P (that is, it
1786 stops testing Q's against the current P) and moves the current
1787 Q to the end of the list to become the next P.
1792 for(p = 0; p<nTriangles; p++)
1794 SortPrimitive * poly1 = &triangles[p];
1797 for(q = p+1; q<nTriangles; q++)
1801 SortPrimitive * poly2 = &triangles[q];
1802 if(poly1->ZOverlap(poly2) && !poly2->marked)
1804 if(poly1->ShouldBeSwapped(poly2))
1806 if(!poly2->ShouldBeSwapped(poly1))
1808 SortPrimitive temp = *poly2;
1809 memmove(triangles+1, triangles, sizeof(SortPrimitive)*q);
1810 triangles[0] = temp;
1811 triangles[0].marked = true;
1824 for(p = 0; p<nTriangles; p++)
1826 SortPrimitive * poly1 = &triangles[p];
1829 // for(q = p+1; q<nTriangles; q++)
1830 for(q = 0; q<nTriangles; q++)
1834 SortPrimitive * poly2 = &triangles[q];
1835 if(poly1->ZOverlap(poly2) && !poly2->marked)
1837 if(poly1->ShouldBeSwapped(poly2))
1839 if(!poly2->ShouldBeSwapped(poly1))
1841 SortPrimitive temp = *poly2;
1842 memmove(triangles+1, triangles, sizeof(SortPrimitive)*q);
1843 triangles[0] = temp;
1844 triangles[0].marked = true;
1857 for(p = nTriangles-1; p>=0; p--)
1859 SortPrimitive * poly1 = &triangles[p];
1862 for(q = nTriangles-1; q>=0; q--)
1866 SortPrimitive * poly2 = &triangles[q];
1867 if(poly1->ZOverlap(poly2) && !poly2->marked)
1869 if(poly1->ShouldBeSwapped(poly2))
1871 if(!poly2->ShouldBeSwapped(poly1))
1873 SortPrimitive temp = *poly2;
1874 memmove(triangles + q, triangles + q + 1, sizeof(SortPrimitive)*q);
1876 triangles[nTriangles-1] = temp;
1889 for(c=0; c<nTriangles; c++)
1892 SortPrimitive * poly1 = &triangles[c];
1894 // for(b=0; b<nTriangles; b++)
1895 //for(b=c+1; b<nTriangles; b++)
1897 if(b<this.nTriangles)
1899 SortPrimitive * poly2 = &this.triangles[b];
1901 if(poly1->ZOverlap(poly2) && poly1->ShouldBeSwapped(poly2))
1903 SortPrimitive temp = *poly1;
1916 bool IsDriverTextMode(const char * driverName)
1918 subclass(DisplayDriver) driver = GetDisplayDriver(driverName);
1919 return driver ? driver.textMode : false;
1922 bool IsDriverPrinter(const char * driverName)
1924 subclass(DisplayDriver) driver = GetDisplayDriver(driverName);
1925 return driver ? driver.printer : false;
1928 static ColorAlpha defaultPalette[256] =
1932 0xFF000000,0xFF000080,0xFF008000,0xFF008080,0xFF800000,0xFF800080,0xFF808000,0xFFC0C0C0,
1933 0xFF808080,0xFF0000FF,0xFF00FF00,0xFF00FFFF,0xFFFF0000,0xFFFF00FF,0xFFFFFF00,0xFFFFFFFF,
1935 0xFF000000,0xFF0000AA,0xFF00AA00,0xFF00AAAA,0xFFAA0000,0xFFAA00AA,0xFFAAAA00,0xFFABABAB,
1936 0xFF555555,0xFF5555FF,0xFF55FF55,0xFF55FFFF,0xFFFF5555,0xFFFF55FF,0xFFFFFF55,0xFFFFFFFF,
1938 // 6 x 6 x 6 Color Cube
1939 0xFF000000, 0xFF000033, 0xFF000066, 0xFF000099, 0xFF0000CC, 0xFF0000FF,
1940 0xFF003300, 0xFF003333, 0xFF003366, 0xFF003399, 0xFF0033CC, 0xFF0033FF,
1941 0xFF006600, 0xFF006633, 0xFF006666, 0xFF006699, 0xFF0066CC, 0xFF0066FF,
1942 0xFF009900, 0xFF009933, 0xFF009966, 0xFF009999, 0xFF0099CC, 0xFF0099FF,
1943 0xFF00CC00, 0xFF00CC33, 0xFF00CC66, 0xFF00CC99, 0xFF00CCCC, 0xFF00CCFF,
1944 0xFF00FF00, 0xFF00FF33, 0xFF00FF66, 0xFF00FF99, 0xFF00FFCC, 0xFF00FFFF,
1946 0xFF330000, 0xFF330033, 0xFF330066, 0xFF330099, 0xFF3300CC, 0xFF3300FF,
1947 0xFF333300, 0xFF333333, 0xFF333366, 0xFF333399, 0xFF3333CC, 0xFF3333FF,
1948 0xFF336600, 0xFF336633, 0xFF336666, 0xFF336699, 0xFF3366CC, 0xFF3366FF,
1949 0xFF339900, 0xFF339933, 0xFF339966, 0xFF339999, 0xFF3399CC, 0xFF3399FF,
1950 0xFF33CC00, 0xFF33CC33, 0xFF33CC66, 0xFF33CC99, 0xFF33CCCC, 0xFF33CCFF,
1951 0xFF33FF00, 0xFF33FF33, 0xFF33FF66, 0xFF33FF99, 0xFF33FFCC, 0xFF33FFFF,
1953 0xFF660000, 0xFF660033, 0xFF660066, 0xFF660099, 0xFF6600CC, 0xFF6600FF,
1954 0xFF663300, 0xFF663333, 0xFF663366, 0xFF663399, 0xFF6633CC, 0xFF6633FF,
1955 0xFF666600, 0xFF666633, 0xFF666666, 0xFF666699, 0xFF6666CC, 0xFF6666FF,
1956 0xFF669900, 0xFF669933, 0xFF669966, 0xFF669999, 0xFF6699CC, 0xFF6699FF,
1957 0xFF66CC00, 0xFF66CC33, 0xFF66CC66, 0xFF66CC99, 0xFF66CCCC, 0xFF66CCFF,
1958 0xFF66FF00, 0xFF66FF33, 0xFF66FF66, 0xFF66FF99, 0xFF66FFCC, 0xFF66FFFF,
1960 0xFF990000, 0xFF990033, 0xFF990066, 0xFF990099, 0xFF9900CC, 0xFF9900FF,
1961 0xFF993300, 0xFF993333, 0xFF993366, 0xFF993399, 0xFF9933CC, 0xFF9933FF,
1962 0xFF996600, 0xFF996633, 0xFF996666, 0xFF996699, 0xFF9966CC, 0xFF9966FF,
1963 0xFF999900, 0xFF999933, 0xFF999966, 0xFF999999, 0xFF9999CC, 0xFF9999FF,
1964 0xFF99CC00, 0xFF99CC33, 0xFF99CC66, 0xFF99CC99, 0xFF99CCCC, 0xFF99CCFF,
1965 0xFF99FF00, 0xFF99FF33, 0xFF99FF66, 0xFF99FF99, 0xFF99FFCC, 0xFF99FFFF,
1967 0xFFCC0000, 0xFFCC0033, 0xFFCC0066, 0xFFCC0099, 0xFFCC00CC, 0xFFCC00FF,
1968 0xFFCC3300, 0xFFCC3333, 0xFFCC3366, 0xFFCC3399, 0xFFCC33CC, 0xFFCC33FF,
1969 0xFFCC6600, 0xFFCC6633, 0xFFCC6666, 0xFFCC6699, 0xFFCC66CC, 0xFFCC66FF,
1970 0xFFCC9900, 0xFFCC9933, 0xFFCC9966, 0xFFCC9999, 0xFFCC99CC, 0xFFCC99FF,
1971 0xFFCCCC00, 0xFFCCCC33, 0xFFCCCC66, 0xFFCCCC99, 0xFFCCCCCC, 0xFFCCCCFF,
1972 0xFFCCFF00, 0xFFCCFF33, 0xFFCCFF66, 0xFFCCFF99, 0xFFCCFFCC, 0xFFCCFFFF,
1974 0xFFFF0000, 0xFFFF0033, 0xFFFF0066, 0xFFFF0099, 0xFFFF00CC, 0xFFFF00FF,
1975 0xFFFF3300, 0xFFFF3333, 0xFFFF3366, 0xFFFF3399, 0xFFFF33CC, 0xFFFF33FF,
1976 0xFFFF6600, 0xFFFF6633, 0xFFFF6666, 0xFFFF6699, 0xFFFF66CC, 0xFFFF66FF,
1977 0xFFFF9900, 0xFFFF9933, 0xFFFF9966, 0xFFFF9999, 0xFFFF99CC, 0xFFFF99FF,
1978 0xFFFFCC00, 0xFFFFCC33, 0xFFFFCC66, 0xFFFFCC99, 0xFFFFCCCC, 0xFFFFCCFF,
1979 0xFFFFFF00, 0xFFFFFF33, 0xFFFFFF66, 0xFFFFFF99, 0xFFFFFFCC, 0xFFFFFFFF,
1981 // 16 Shades of gray
1982 0xFF000000,0xFF101010,0xFF202020,0xFF303030,0xFF404040,0xFF505050,0xFF606060,0xFF707070,
1983 0xFF808080,0xFF909090,0xFFA0A0A0,0xFFB0B0B0,0xFFC0C0C0,0xFFD0D0D0,0xFFE0E0E0,0xFFF0F0F0,
1986 0xFF080808,0xFF101010,0xFF585858,0xFF606060,0xFFA8A8A8,0xFFB0B0B0,0xFFF8F8F8,0xFFFFFFFF
1990 0xFF080000,0xFF100000,0xFF180000,0xFF200000,0xFF280000,0xFF300000,0xFF380000,0xFF400000,
1991 0xFF480000,0xFF500000,0xFF580000,0xFF600000,0xFF680000,0xFF700000,0xFF780000,0xFF800000,
1992 0xFF880000,0xFF900000,0xFF980000,0xFFA00000,0xFFA80000,0xFFB00000,0xFFB80000,0xFFC00000,
1993 0xFFC80000,0xFFD00000,0xFFD80000,0xFFE00000,0xFFE80000,0xFFF00000,0xFFF80000,0xFFFF0000,
1995 0xFF000800,0xFF001000,0xFF001800,0xFF002000,0xFF002800,0xFF003000,0xFF003800,0xFF004000,
1996 0xFF004800,0xFF005000,0xFF005800,0xFF006000,0xFF006800,0xFF007000,0xFF007800,0xFF008000,
1997 0xFF008800,0xFF009000,0xFF009800,0xFF00A000,0xFF00A800,0xFF00B000,0xFF00B800,0xFF00C000,
1998 0xFF00C800,0xFF00D000,0xFF00D800,0xFF00E000,0xFF00E800,0xFF00F000,0xFF00F800,0xFF00FF00,
2000 0xFF000808,0xFF001010,0xFF001818,0xFF002020,0xFF002828,0xFF003030,0xFF003838,0xFF004040,
2001 0xFF004848,0xFF005050,0xFF005858,0xFF006060,0xFF006868,0xFF007070,0xFF007878,0xFF008080,
2002 0xFF008888,0xFF009090,0xFF009898,0xFF00A0A0,0xFF00A8A8,0xFF00B0B0,0xFF00B8B8,0xFF00C0C0,
2003 0xFF00C8C8,0xFF00D0D0,0xFF00D8D8,0xFF00E0E0,0xFF00E8E8,0xFF00F0F0,0xFF00F8F8,0xFF00FFFF,
2005 0xFF000008,0xFF000010,0xFF000018,0xFF000020,0xFF000028,0xFF000030,0xFF000038,0xFF000040,
2006 0xFF000048,0xFF000050,0xFF000058,0xFF000060,0xFF000068,0xFF000070,0xFF000078,0xFF000080,
2007 0xFF000088,0xFF000090,0xFF000098,0xFF0000A0,0xFF0000A8,0xFF0000B0,0xFF0000B8,0xFF0000C0,
2008 0xFF0000C8,0xFF0000D0,0xFF0000D8,0xFF0000E0,0xFF0000E8,0xFF0000F0,0xFF0000F8,0xFF0000FF,
2010 0xFF080008,0xFF100010,0xFF180018,0xFF200020,0xFF280028,0xFF300030,0xFF380038,0xFF400040,
2011 0xFF480048,0xFF500050,0xFF580058,0xFF600060,0xFF680068,0xFF700070,0xFF780078,0xFF800080,
2012 0xFF880088,0xFF900090,0xFF980098,0xFFA000A0,0xFFA800A8,0xFFB000B0,0xFFB800B8,0xFFC000C0,
2013 0xFFC800C8,0xFFD000D0,0xFFD800D8,0xFFE000E0,0xFFE800E8,0xFFF000F0,0xFFF800F8,0xFFFF00FF,
2015 0xFF080800,0xFF101000,0xFF181800,0xFF202000,0xFF282800,0xFF303000,0xFF383800,0xFF404000,
2016 0xFF484800,0xFF505000,0xFF585800,0xFF606000,0xFF686800,0xFF707000,0xFF787800,0xFF808000,
2017 0xFF888800,0xFF909000,0xFF989800,0xFFA0A000,0xFFA8A800,0xFFB0B000,0xFFB8B800,0xFFC0C000,
2018 0xFFC8C800,0xFFD0D000,0xFFD8D800,0xFFE0E000,0xFFE8E800,0xFFF0F000,0xFFF8F800,0xFFFFFF00,
2020 0xFF080808,0xFF101010,0xFF181818,0xFF202020,0xFF282828,0xFF303030,0xFF383838,0xFF404040,
2021 0xFF484848,0xFF505050,0xFF585858,0xFF606060,0xFF686868,0xFF707070,0xFF787878,0xFF808080,
2022 0xFF888888,0xFF909090,0xFF989898,0xFFA0A0A0,0xFFA8A8A8,0xFFB0B0B0,0xFFB8B8B8,0xFFC0C0C0,
2023 0xFFC8C8C8,0xFFD0D0D0,0xFFD8D8D8,0xFFE0E0E0,0xFFE8E8E8,0xFFF0F0F0,0xFFF8F8F8,0xFFFFFFFF
2027 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
2028 static Material defaultMaterial
2031 diffuse = { 1.0f, 1.0f, 1.0f },
2032 ambient = { 1.0f, 1.0f, 1.0f },
2033 flags = { doubleSided = true, noFog = true };
2037 static byte colorDepthShifts[PixelFormat] = { 0,0,1,1,1,2,0,1,2 };
2038 static Size resolutions[Resolution] =
2041 {320,200},{320,240},{320,400},{360,480},
2042 {400,256},{400,300},{512,256},{512,384},
2043 {640,200},{640,350},{640,400},{640,480},
2044 {720,348},{800,600},{856,480},{960,720},
2045 {1024,768},{1152,864},{1280,1024},{1600,1200},
2048 static int colorDepths[PixelFormat] = {4,8,12,15,16,32,8,16,32};
2050 // --- Query utilities ---
2052 public int GetResolutionWidth(Resolution resolution)
2054 return resolutions[resolution].w;
2057 public int GetResolutionHeight(Resolution resolution)
2059 return resolutions[resolution].h;
2062 public int GetDepthBits(PixelFormat colorDepth)
2064 return colorDepths[colorDepth];
2067 public byte GetColorDepthShifts(PixelFormat format)
2069 return colorDepthShifts[format];
2072 public ColorAlpha * GetDefaultPalette()
2074 return (ColorAlpha *)defaultPalette;
2076 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
2077 public Material GetDefaultMaterial()
2079 return defaultMaterial;
2082 public int BestColorMatch(ColorAlpha * palette, int start, int end, Color rgb)
2088 int bestscore = MAXINT,score;
2089 byte r = rgb.r, g = rgb.g, b = rgb.b;
2092 for(c = start; c <= end; c++)
2095 current = palette[c];
2096 if(rgb && !c) continue;
2100 score = Abs(dr) + Abs(dg) + Abs(db);
2101 if(score <= bestscore)
2111 // had to move this here due to compiler ordering issue for "get property" symbol
2112 subclass(DisplayDriver) GetDisplayDriver(const char * driverName)
2117 for(link = class(DisplayDriver).derivatives.first; link; link = link.next)
2119 subclass(DisplayDriver) displayDriver = link.data;
2120 if(displayDriver && displayDriver.name && !strcmp(displayDriver.name, driverName))
2121 return displayDriver;
2127 DisplaySystem GetDisplaySystem(const char * driverName)
2129 subclass(DisplayDriver) displayDriver = GetDisplayDriver(driverName);
2130 return displayDriver ? displayDriver.displaySystem : null;