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)
720 displaySystem.driver.SetLight(this, id, light);
723 void SetLights(Object object)
726 display3D._SetLights(this, object, 0);
729 // --- Transformations ---
731 void SetTransform(Matrix matrix, bool viewSpace)
733 if(display3D.selection)
737 transpose.Transpose(matrix);
741 for(c = 0; c<ClippingPlane::enumSize; c++)
742 display3D.localPickingPlanes[c].MultMatrix(display3D.viewPickingPlanes[c], transpose);
746 for(c = 0; c<ClippingPlane::enumSize; c++)
747 display3D.localPickingPlanes[c].MultMatrix(display3D.worldPickingPlanes[c], transpose);
751 if(display3D.intersecting)
755 p2.Add(display3D.rayView.p0, display3D.rayView.delta);
757 p2.Add(display3D.rayWorld.p0, display3D.rayWorld.delta);
759 display3D.rayLocal.p0.DivideMatrix(display3D.rayWorld.p0, matrix);
760 tp2.DivideMatrix(p2, matrix);
761 display3D.rayLocal.delta.Subtract(tp2, display3D.rayLocal.p0);
765 displaySystem.driver.SetTransform(this, matrix, viewSpace, viewSpace ? false : true);
768 void PushMatrix(void)
770 displaySystem.driver.PushMatrix(this);
775 displaySystem.driver.PopMatrix(this, true);
779 void ApplyMaterial(Material material, Mesh mesh)
781 if(material != display3D.material)
783 display3D.material = material;
784 displaySystem.driver.ApplyMaterial(this, material, mesh);
788 void DrawPrimitives(PrimitiveSingle primitive, Mesh mesh)
790 displaySystem.driver.DrawPrimitives(this, primitive, mesh);
793 void SelectMesh(Mesh mesh)
795 displaySystem.driver.SelectMesh(this, mesh);
796 display3D.mesh = mesh;
799 bool DrawMesh(Object object)
802 if(display3D.selection)
803 result = display3D.PickMesh(object, null);
806 Mesh mesh = object.mesh;
807 Material objectMaterial = object.material;
809 if(mesh.groups.first)
811 PrimitiveGroup group;
812 displaySystem.driver.SelectMesh(this, mesh);
813 display3D.mesh = mesh;
815 for(group = mesh.groups.first; group; group = group.next)
817 Material material = group.material ? group.material : objectMaterial;
818 if(!material) material = defaultMaterial;
820 if(material != display3D.material)
822 display3D.material = material;
823 displaySystem.driver.ApplyMaterial(this, material, mesh);
826 // *** Render Vertex Arrays ***
827 displaySystem.driver.DrawPrimitives(this, (PrimitiveSingle *)&group.type, mesh);
831 if(object.flags.translucent)
834 Matrix inverse, inverseTranspose;
837 if(object.flags.viewSpace)
838 matrix = object.matrix;
841 Camera camera = display3D.camera;
842 Matrix temp = object.matrix;
843 temp.m[3][0] -= camera.cPosition.x;
844 temp.m[3][1] -= camera.cPosition.y;
845 temp.m[3][2] -= camera.cPosition.z;
846 matrix.Multiply(temp, camera.viewMatrix);
849 inverse.Inverse(matrix);
850 inverseTranspose.Transpose(inverse);
852 for(c = 0; c < mesh.nPrimitives; c++)
854 PrimitiveSingle * triangle = &mesh.primitives[c];
855 SortPrimitive * sort;
856 Plane * plane = &triangle->plane;
857 if(display3D.nTriangles >= display3D.maxTriangles)
859 display3D.maxTriangles = display3D.maxTriangles ? (display3D.maxTriangles * 3 / 2) : 32768;
860 display3D.triangles = renew display3D.triangles SortPrimitive[display3D.maxTriangles];
862 sort = &display3D.triangles[display3D.nTriangles++];
863 sort->object = object;
864 sort->triangle = triangle;
865 sort->middle.MultMatrix(triangle->middle, matrix);
866 sort->middle.z *= -1;
867 // sort->plane.MultMatrix(triangle->plane, inverseTranspose);
868 sort->plane.d = plane->a * inverseTranspose.m[0][3] +
869 plane->b * inverseTranspose.m[1][3] +
870 plane->c * inverseTranspose.m[2][3] +
871 plane->d * inverseTranspose.m[3][3];
877 displaySystem.driver.SelectMesh(this, mesh);
878 display3D.mesh = mesh;
880 for(c = 0; c<mesh.nPrimitives; c++)
882 PrimitiveSingle * primitive = &mesh.primitives[c];
884 Material material = primitive->material ? primitive->material : objectMaterial;
885 if(!material) material = defaultMaterial;
887 if(material != display3D.material)
889 display3D.material = material;
890 displaySystem.driver.ApplyMaterial(this, material, mesh);
893 displaySystem.driver.DrawPrimitives(this, primitive, display3D.mesh);
901 bool IsObjectVisible(Object object)
904 if(display3D.selection || !display3D.camera)
905 planes = object.flags.viewSpace ? display3D.viewPickingPlanes : display3D.worldPickingPlanes;
907 planes = object.flags.viewSpace ? display3D.camera.viewClippingPlanes : display3D.camera.worldClippingPlanes;
908 return object.InsideFrustum(planes) != outside;
911 bool DrawObject(Object object)
914 if(object && object.volume)
917 FrustumPlacement visible;
919 Camera camera = display3D.camera;
921 if(display3D.selection || !camera)
922 planes = object.flags.viewSpace ? display3D.viewPickingPlanes : display3D.worldPickingPlanes;
924 planes = object.flags.viewSpace ? camera.viewClippingPlanes : camera.worldClippingPlanes;
926 visible = object.InsideFrustum(planes);
928 if(visible || display3D.pickingPlanes)
930 if(display3D.collectingHits && object.tag)
932 /*if(object.flags.root)
933 this.tags[display3D.tagIndex] = object.tag;
935 this.tags[++display3D.tagIndex] = object.tag;
937 display3D.tags[display3D.tagIndex++] = object.tag;
940 if(object.flags.mesh && object.mesh)
942 if(!display3D.selection && displaySystem.driver.PushMatrix)
943 displaySystem.driver.PushMatrix(this);
946 if(object.mesh.tangents && object.mesh.normals)
948 Mesh mesh = object.mesh;
951 int count = mesh.nVertices;
952 Vector3Df * normals = mesh.normals;
953 Vector3Df * vertices = mesh.vertices;
954 ColorRGB * lightVectors;
955 Vector3Df * tangents = mesh.tangents;
957 float * l = display3D.light0Pos;
958 Vector3Df light { l[0], l[1], l[2] };
959 Matrix o = object.matrix;
960 Matrix t, inv = camera.viewMatrix;
962 Vector3D cPos = camera.cPosition;
963 Vector3D pos = camera.position;
964 bool positional = l[3] ? true : false;
966 inv.Scale(1.0/nearPlane, -1.0/nearPlane,-1.0/nearPlane);
968 pos.MultMatrix(cPos, camera.viewMatrix);
970 ot.x = o.m[3][0] + pos.x;
971 ot.y = o.m[3][1] + pos.y;
972 ot.z = o.m[3][2] + pos.z;
981 mesh.Allocate({ lightVectors = true }, mesh.nVertices, displaySystem);
982 mesh.Lock({ lightVectors = true });
983 lightVectors = mesh.lightVectors;
984 for(i = 0; i < count; i++)
986 Vector3Df tangent1 = tangents[i*2 + 0];
987 Vector3Df tangent2 = tangents[i*2 + 1];
988 Vector3Df normal = normals[i];
989 Vector3Df tTangent1, tTangent2, tNormal;
991 tTangent1.MultMatrix(tangent1, inv);
992 tTangent2.MultMatrix(tangent2, inv);
993 tNormal .MultMatrix(normal, inv);
995 tTangent1.Normalize(tTangent1);
996 tTangent2.Normalize(tTangent2);
997 tNormal .Normalize(tNormal);
1002 tTangent1.x, tTangent2.x, tNormal.x, 0,
1003 tTangent1.y, tTangent2.y, tNormal.y, 0,
1004 tTangent1.z, tTangent2.z, tNormal.z, 1
1009 Vector3Df tPos = vertices[i];
1010 tPos.x += ot.x, tPos.y += ot.y, tPos.z += ot.z;
1012 // Subtract vertex from light for positional lights
1013 light.x = l[0] - tPos.x;
1014 light.y = l[1] + tPos.y;
1015 light.z = l[2] - tPos.z;
1017 n.MultMatrix(light, tbn);
1020 lightVectors[i] = { n.x / 2 + 0.5f, n.y / 2 + 0.5f, n.z / 2 + 0.5f };
1023 mesh.Unlock({ lightVectors = true });
1025 // Create normalization cube map
1030 int w = 256, h = 256, d = 256;
1031 Vector3Df min = mesh.min, max = mesh.max;
1034 (max.x - min.x) / w,
1035 (max.y - min.y) / h,
1039 for(i = 0; i < 6; i++)
1041 Bitmap face = i > 0 ? { } : mesh.normMap;
1045 face.Allocate(null, w, h, 0, pixelFormat888, false);
1046 face.driverData = mesh.normMap.driverData;
1047 p = (ColorAlpha *)face.picture;
1048 for(y = 0; y < h; y++)
1050 for(x = 0; x < w; x++, p++)
1052 Vector3Df v { min.x + x * delta.x, min.y + y * delta.y, min.z };
1054 *p = ColorAlpha { 255, {
1055 (byte)((v.x / 2.0 + 0.5) * 255),
1056 (byte)((v.y / 2.0 + 0.5) * 255),
1057 (byte)((v.z / 2.0 + 0.5) * 255) } };
1060 displaySystem.driver.MakeDDBitmap(displaySystem, face, true, (i + 1));
1063 face.driverData = 0;
1071 mesh.Free({ lightVectors = true });
1075 SetTransform(object.matrix, object.flags.viewSpace);
1076 if(display3D.selection)
1078 if(visible == intersecting || display3D.intersecting)
1080 Vector3D rayIntersect;
1081 if(display3D.PickMesh(object, rayIntersect))
1083 if(display3D.intersecting)
1085 Vector3D wresult, vresult;
1086 wresult.MultMatrix(rayIntersect, object.matrix);
1087 if(!object.flags.viewSpace)
1088 camera.TransformPoint(vresult, wresult);
1092 if(vresult.z < display3D.rayIntersect.z)
1093 display3D.rayIntersect = vresult;
1094 display3D.intersected = true;
1104 result |= DrawMesh(object);
1105 if(displaySystem.driver.PopMatrix)
1106 displaySystem.driver.PopMatrix(this, true);
1108 if(display3D.collectingHits && result /*&& object.tag*/)
1111 HitRecord hit = (HitRecord)new0 byte[sizeof(class HitRecord) + sizeof(void *) * (display3D.tagIndex/*+1*/)];
1112 display3D.hitList.Add(hit);
1113 hit.pos = display3D.hitList.count-1;
1114 hit.numTags = display3D.tagIndex /*+ 1*/;
1115 for(c = 0; c</*=*/display3D.tagIndex; c++)
1117 hit.tags[c] = display3D.tags[c];
1120 if(!object.flags.viewSpace)
1121 camera.TransformPoint(hit.center, object.wcenter);
1123 hit.center = object.wcenter;
1127 for(child = object.children.first; child; child = child.next)
1128 result |= DrawObject(child);
1130 if(display3D.collectingHits && /*!object.flags.root && */object.tag)
1131 display3D.tagIndex--;
1137 void DrawTranslucency(void)
1139 if(display3D.camera)
1141 // *** Render translucent primitives ***
1142 if(display3D.nTriangles)
1144 Matrix * matrix = null;
1149 display3D.SortTriangles();
1153 displaySystem.driver.PushMatrix(this);
1154 for(c=0; c<display3D.nTriangles; c++)
1156 SortPrimitive * sort = &display3D.triangles[c];
1157 Mesh mesh = sort->object.mesh;
1158 PrimitiveSingle * primitive = sort->triangle;
1161 if(&sort->object.matrix != matrix)
1163 matrix = &sort->object.matrix;
1165 displaySystem.driver.PopMatrix(this, false);
1166 displaySystem.driver.PushMatrix(this);
1167 SetTransform(matrix, sort->object.flags.viewSpace);
1169 if(mesh != display3D.mesh)
1171 displaySystem.driver.SelectMesh(this, mesh);
1172 display3D.mesh = mesh;
1175 material = primitive->material ? primitive->material : sort->object.material;
1176 if(!material) material = defaultMaterial;
1178 if(material != display3D.material)
1180 displaySystem.driver.ApplyMaterial(this, material, display3D.mesh);
1181 display3D.material = material;
1186 Material testMaterial { };
1189 amount = (display3D.triangles[0].middle.z - display3D.triangles[c].middle.z) /
1190 (display3D.triangles[0].middle.z - display3D.triangles[display3D.nTriangles-1].middle.z);
1192 testMaterial.flags.doubleSided = { doubleSided = true, translucent = true };
1193 testMaterial.diffuse.a = 1;
1194 testMaterial.emissive.r = testMaterial.emissive.g = testMaterial.emissive.b = amount;
1195 testMaterial.baseMap = material->baseMap;
1197 displaySystem.driver.ApplyMaterial(this, testMaterial, display3D.mesh);
1201 // *** Render primitive ***
1202 // if(sort->plane.d > 0)
1203 displaySystem.driver.DrawPrimitives(this, primitive, display3D.mesh);
1205 displaySystem.driver.PopMatrix(this, true);
1207 display3D.nTriangles = 0;
1214 void StartSelection(int pickX, int pickY, int pickW, int pickH)
1218 display3D = Display3D { };
1220 display3D.pickX = (float)pickX;
1221 display3D.pickY = (float)pickY;
1222 display3D.pickWidth = (float)pickW;
1223 display3D.pickHeight = (float)pickH;
1224 display3D.selection = true;
1227 void CollectHits(void)
1229 display3D.collectingHits = true;
1232 int GetHits(OldList list)
1234 display3D.collectingHits = false;
1235 display3D.hitList.Sort(HitRecord::Compare, null);
1236 list = display3D.hitList;
1237 display3D.hitList.Clear();
1241 void IntersectPolygons(void)
1243 display3D.rayIntersect = { MAXFLOAT, MAXFLOAT, MAXFLOAT };
1244 display3D.intersected = false;
1245 display3D.intersecting = true;
1248 bool GetIntersect(Vector3D intersect)
1250 intersect = display3D.rayIntersect;
1251 display3D.intersecting = false;
1252 return display3D.intersected;
1255 void StopSelection(void)
1257 display3D.selection = false;
1260 // --- Rendering States ---
1261 property FillModeValue fillMode { set { displaySystem.driver.SetRenderState(this, fillMode, value); } };
1262 property bool depthTest { set { displaySystem.driver.SetRenderState(this, depthTest, value); } };
1263 property bool depthWrite { set { displaySystem.driver.SetRenderState(this, depthWrite, value); } };
1264 property float fogDensity { set { displaySystem.driver.SetRenderState(this, fogDensity, RenderStateFloat { value }.ui); } };
1265 property Color fogColor { set { displaySystem.driver.SetRenderState(this, fogColor, value); } };
1266 property bool blend { set { displaySystem.driver.SetRenderState(this, blend, value); } };
1267 property Color ambient { set { displaySystem.driver.SetRenderState(this, ambient, value); } };
1268 property bool alphaWrite { set { displaySystem.driver.SetRenderState(this, alphaWrite, value); } };
1269 property bool antiAlias { set { displaySystem.driver.SetRenderState(this, antiAlias, value); } };
1270 property bool vSync { set { displaySystem.driver.SetRenderState(this, vSync, value); } };
1272 property bool pickingPlanes { set { display3D.pickingPlanes = value; } };
1274 property DisplayFlags flags { get { return displaySystem.flags; } }
1275 property PixelFormat pixelFormat { get { return /*alphaBlend ? pixelFormat888 : */displaySystem.pixelFormat; } }
1276 property bool alphaBlend { set { alphaBlend = value; } get { return alphaBlend; } };
1277 property bool useSharedMemory { set { useSharedMemory = value; } get { return useSharedMemory; } };
1278 property void * systemWindow { get { return window; } };
1279 property DisplaySystem displaySystem { get { return displaySystem; } };
1280 #ifndef ECERE_VANILLA
1281 property GLCapabilities glCapabilities
1283 get { return ((OGLDisplay)driverData).capabilities; }
1286 glCapabilities = value;
1287 if(driverData && displaySystem.driver == class(OpenGLDisplayDriver))
1289 OGLDisplay oglDisplay = driverData;
1290 if(!oglDisplay.originalCapabilities.fixedFunction)
1291 value.shaders = true;
1292 if(!oglDisplay.originalCapabilities.shaders)
1293 value.fixedFunction = true;
1294 // Disable things that don't work with shaders
1297 value.fixedFunction = false;
1298 value.legacy = false;
1299 value.immediate = false;
1301 oglDisplay.capabilities = oglDisplay.originalCapabilities & value;
1304 OpenGLDisplayDriver::initialDisplaySetup(this, true, false);
1316 DisplaySystem displaySystem;
1319 #if !defined(__EMSCRIPTEN__)
1324 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
1325 Display3D display3D;
1328 void * windowDriverData;
1329 bool useSharedMemory;
1330 GLCapabilities glCapabilities;
1331 glCapabilities = { true, true, true, true, true, true, true, true };
1334 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
1335 private class Display3D : struct
1339 SortPrimitive * triangles;
1341 Vector3D points[MAX_CLIP_POINTS];
1342 Vector3D newPoints[MAX_CLIP_POINTS];
1343 byte goodPoints[MAX_CLIP_POINTS];
1348 Plane viewPickingPlanes[ClippingPlane], worldPickingPlanes[ClippingPlane];
1349 Plane localPickingPlanes[ClippingPlane];
1351 bool collectingHits, selection, intersecting, intersected, pickingPlanes;
1352 float pickX, pickY, pickWidth, pickHeight;
1357 Line rayView, rayWorld, rayLocal;
1358 Vector3D rayIntersect;
1366 int _SetLights(Display display, Object object, int id)
1368 if(id < NumberOfLights)
1372 if(object.flags.light && !object.light.flags.off)
1373 display.SetLight(id++, object.light);
1375 for(child = object.children.first; child; child = child.next)
1377 id = _SetLights(display, child, id);
1383 //#define TRESHOLD -1
1384 //#define TRESHOLD -0.25
1385 #define TRESHOLD -0.0025
1387 bool PickPrimitives(Mesh mesh, PrimitiveSingle primitive, Vector3D rayDiff, Vector3D rayIntersect)
1389 Plane * planes = localPickingPlanes;
1391 int nIndex = 1, nPoints = 1;
1393 bool result = false;
1394 Vector3D * points = this.points;
1395 Vector3D * newPoints = this.newPoints;
1396 byte * goodPoints = this.goodPoints;
1397 int nVertices = primitive.type.vertexRange ? primitive.nVertices : primitive.nIndices;
1400 bool i32bit = primitive.type.indices32bit;
1401 uint32 * indices32 = primitive.indices32;
1402 uint16 * indices16 = primitive.indices;
1404 switch(primitive.type.primitiveType)
1406 case triangles: nIndex = 3; nPoints = 3; break;
1407 case quads: nIndex = 4; nPoints = 4; break;
1410 nIndex = 1; nPoints = 3;
1412 tmp = primitive.type.vertexRange ? mesh.vertices[primitive.first] : mesh.vertices[(i32bit ? indices32[0] : indices16[0])];
1413 points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1414 tmp = primitive.type.vertexRange ? mesh.vertices[primitive.first+1] : mesh.vertices[(i32bit ? indices32[1] : indices16[1])];
1415 points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1419 for(c = offset; c<nVertices; c += nIndex)
1421 bool outside = false;
1428 if(primitive.type.vertexRange)
1430 if(primitive.type.primitiveType == triStrip)
1432 tmp = mesh.vertices[primitive.first + (c & 1) ? (c - 1) : (c - 2)];
1433 points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1434 tmp = mesh.vertices[primitive.first + (c & 1) ? (c - 2) : (c - 1)];
1435 points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1437 else if(primitive.type.primitiveType == triFan)
1439 tmp = mesh.vertices[primitive.first + 0];
1440 points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1441 tmp = mesh.vertices[primitive.first + c - 1];
1442 points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1444 for(i = 0; i<nIndex; i++)
1446 tmp = mesh.vertices[primitive.first + c+i];
1447 points[i + offset] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1452 if(primitive.type.primitiveType == triStrip)
1454 i = (c & 1) ? (c - 1) : (c - 2);
1455 tmp = mesh.vertices[(i32bit ? indices32[i] : indices16[i])];
1456 points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1458 i = (c & 1) ? (c - 2) : (c - 1);
1459 tmp = mesh.vertices[(i32bit ? indices32[i] : indices16[i])];
1460 points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1462 else if(primitive.type.primitiveType == triFan)
1464 tmp = mesh.vertices[(i32bit ? indices32[0] : indices16[0])];
1465 points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1466 tmp = mesh.vertices[(i32bit ? indices32[c-1] : indices16[c-1])];
1467 points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1469 for(i = 0; i<nIndex; i++)
1471 tmp = mesh.vertices[(i32bit ? indices32[c+i] : indices16[c+i])];
1472 points[i + offset] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1476 for(p = 0; p < 6; p++)
1478 Plane * plane = &planes[p];
1480 int numGoodPoints = 0;
1482 memset(goodPoints, 0, n);
1483 for(i = 0; i < n; i++)
1485 double dot = plane->normal.DotProduct(points[i]);
1486 double distance = dot + plane->d;
1487 if(distance > TRESHOLD)
1498 if(numGoodPoints < n)
1509 newPoints[newN++] = points[j];
1518 for(lastGood = n-1; !goodPoints[lastGood]; lastGood--);
1520 edge.p0 = points[lastGood];
1521 edge.delta.Subtract(points[j], edge.p0);
1522 plane->IntersectLine(edge, newPoints[newN++]);
1524 for(next = j+1; next != j; next++)
1526 if(next == n) next = 0;
1527 if(goodPoints[next])
1529 int prev = next - 1;
1530 if(prev < 0) prev = n-1;
1532 edge.p0 = points[prev];
1533 edge.delta.Subtract(points[next], edge.p0);
1534 plane->IntersectLine(edge, newPoints[newN++]);
1544 // Use the new points
1545 memcpy(points, newPoints, newN * sizeof(Vector3D));
1554 // TODO: Implement intersection with TriStrip, TriFan...
1557 // Intersect primitives
1559 Vector3D intersect, diff;
1560 int i0 = c, i1 = c+1, i2 = c+2;
1562 if(primitive.type.primitiveType == triStrip)
1564 i0 = (c & 1) ? (c - 1) : (c - 2);
1565 i1 = (c & 1) ? (c - 2) : (c - 1);
1568 else if(primitive.type.primitiveType == triFan)
1575 if(primitive.type.vertexRange)
1577 mesh.vertices[primitive.first + i0],
1578 mesh.vertices[primitive.first + i1],
1579 mesh.vertices[primitive.first + i2]);
1582 mesh.vertices[(i32bit ? indices32[i0] : indices16[i0])],
1583 mesh.vertices[(i32bit ? indices32[i1] : indices16[i1])],
1584 mesh.vertices[(i32bit ? indices32[i2] : indices16[i2])]);
1586 plane.IntersectLine(rayLocal, intersect);
1587 diff.Subtract(intersect, rayLocal.p0);
1588 diff.x /= rayLocal.delta.x;
1589 diff.y /= rayLocal.delta.y;
1590 diff.z /= rayLocal.delta.z;
1591 if(diff.x < rayDiff.x || diff.y < rayDiff.y || diff.z < rayDiff.z)
1594 rayIntersect = intersect;
1601 switch(primitive.type)
1604 points[strip] = points[2];
1608 points[1] = points[2];
1615 bool PickMesh(Object object, Vector3D rayIntersect)
1617 Mesh mesh = object.mesh;
1618 bool result = false;
1619 Vector3D rayDiff { MAXFLOAT, MAXFLOAT, MAXFLOAT };
1620 if(rayIntersect != null)
1621 rayIntersect = { MAXFLOAT, MAXFLOAT, MAXFLOAT };
1623 if(mesh.groups.first)
1625 PrimitiveGroup group;
1627 for(group = mesh.groups.first; group; group = group.next)
1629 if(PickPrimitives(mesh, (PrimitiveSingle *)&group.type, rayDiff, rayIntersect))
1640 for(c = 0; c < mesh.nPrimitives; c++)
1642 if(PickPrimitives(mesh, mesh.primitives[c], rayDiff, rayIntersect))
1653 void SortTriangles(void)
1656 Object object = null;
1658 for(c=0; c<nTriangles; c++)
1660 SortPrimitive * sort = &triangles[c];
1661 Mesh mesh = sort->object.mesh;
1662 PrimitiveSingle * primitive = sort->triangle;
1663 Vector3Df min { MAXFLOAT, MAXFLOAT, MAXFLOAT };
1664 Vector3Df max { -MAXFLOAT, -MAXFLOAT, -MAXFLOAT };
1666 bool ix32 = primitive->type.indices32bit;
1667 if(object != sort->object)
1669 object = sort->object;
1670 if(object.flags.viewSpace)
1671 matrix = object.matrix;
1674 Camera camera = this.camera;
1675 Matrix temp = object.matrix;
1676 temp.m[3][0] -= camera.cPosition.x;
1677 temp.m[3][1] -= camera.cPosition.y;
1678 temp.m[3][2] -= camera.cPosition.z;
1679 matrix.Multiply(temp, camera.viewMatrix);
1683 for(v = 0; v<primitive->nIndices; v++)
1685 Vector3Df * local = &mesh.vertices[ix32 ? primitive->indices32[v] : primitive->indices[v]];
1688 vertex.MultMatrix(local, &matrix);
1690 if(vertex.x > max.x) max.x = vertex.x;
1691 if(vertex.y > max.y) max.y = vertex.y;
1692 if(vertex.z > max.z) max.z = vertex.z;
1693 if(vertex.x < min.x) min.x = vertex.x;
1694 if(vertex.y < min.y) min.y = vertex.y;
1695 if(vertex.z < min.z) min.z = vertex.z;
1701 sort->marked = false;
1705 Logf("========= Before Sort ==========\n");
1706 for(c=0; c<nTriangles; c++)
1708 SortPrimitive * sort = &triangles[c];
1710 Mesh mesh = sort->mesh;
1711 PrimitiveSingle * primitive = sort->triangle;
1713 Logf("Triangle %d (%s):\n", c, primitive->material->name);
1715 for(v = 0; v<primitive->nIndices; v++)
1717 Vector3Df * local = &mesh.vertices[primitive->indices[v]];
1721 vertex.<MultMatrix(local, sort->matrix);
1723 Logf("Vertex %d:", v);
1725 // Logf(" Local %f, %f, %f:\n", local->x, local->y, local->z);
1726 Logf(" View %f, %f, %f:\n", vertex.x, vertex.y, vertex.z);
1730 Logf("Min %f, %f, %f:\n", sort->min.x, sort->min.y, sort->min.z);
1731 Logf("Max %f, %f, %f:\n", sort->max.x, sort->max.y, sort->max.z);
1735 // *** Sort translucent primitives ***
1736 qsort((void*) triangles, nTriangles, sizeof(SortPrimitive), SortPrimitive::Compare);
1738 Logf("\n\n========= After Sort ==========\n");
1739 for(c=0; c<nTriangles; c++)
1741 SortPrimitive * sort = &triangles[c];
1743 Mesh mesh = sort->mesh;
1744 PrimitiveSingle * primitive = sort->triangle;
1746 Logf("Triangle %d (%s):\n", c, primitive->material->name);
1748 for(v = 0; v<primitive->nIndices; v++)
1750 Vector3Df * local = &mesh.vertices[primitive->indices[v]];
1754 vertex.MultMatrix(local, sort->matrix);
1756 Logf("Vertex %d:", v);
1758 // Logf(" Local %f, %f, %f:\n", local->x, local->y, local->z);
1759 Logf(" View %f, %f, %f:\n", vertex.x, vertex.y, vertex.z);
1763 Logf("Min %f, %f, %f:\n", sort->min.x, sort->min.y, sort->min.z);
1764 Logf("Max %f, %f, %f:\n", sort->max.x, sort->max.y, sort->max.z);
1771 If all five tests fail for a particular Q,
1772 then P might obscure Q. Now Q must be tested.
1773 First, the algorithm checks if Q has been "marked."
1774 If Q is marked, then Q was "moved around" in the list
1775 during a previous iteration of the loop. The algorithm
1776 only allows a polygon to be moved once, to avoid the possibility
1777 of infinite loops. If Q is not marked, it is tested to see
1778 if it might obscure P. If Q cannot obscure P, then Q is possibly
1779 behind P and so it is good candidate to be drawn next.
1780 Therefore, the algorithm "abandons" the current P (that is, it
1781 stops testing Q's against the current P) and moves the current
1782 Q to the end of the list to become the next P.
1787 for(p = 0; p<nTriangles; p++)
1789 SortPrimitive * poly1 = &triangles[p];
1792 for(q = p+1; q<nTriangles; q++)
1796 SortPrimitive * poly2 = &triangles[q];
1797 if(poly1->ZOverlap(poly2) && !poly2->marked)
1799 if(poly1->ShouldBeSwapped(poly2))
1801 if(!poly2->ShouldBeSwapped(poly1))
1803 SortPrimitive temp = *poly2;
1804 memmove(triangles+1, triangles, sizeof(SortPrimitive)*q);
1805 triangles[0] = temp;
1806 triangles[0].marked = true;
1819 for(p = 0; p<nTriangles; p++)
1821 SortPrimitive * poly1 = &triangles[p];
1824 // for(q = p+1; q<nTriangles; q++)
1825 for(q = 0; q<nTriangles; q++)
1829 SortPrimitive * poly2 = &triangles[q];
1830 if(poly1->ZOverlap(poly2) && !poly2->marked)
1832 if(poly1->ShouldBeSwapped(poly2))
1834 if(!poly2->ShouldBeSwapped(poly1))
1836 SortPrimitive temp = *poly2;
1837 memmove(triangles+1, triangles, sizeof(SortPrimitive)*q);
1838 triangles[0] = temp;
1839 triangles[0].marked = true;
1852 for(p = nTriangles-1; p>=0; p--)
1854 SortPrimitive * poly1 = &triangles[p];
1857 for(q = nTriangles-1; q>=0; q--)
1861 SortPrimitive * poly2 = &triangles[q];
1862 if(poly1->ZOverlap(poly2) && !poly2->marked)
1864 if(poly1->ShouldBeSwapped(poly2))
1866 if(!poly2->ShouldBeSwapped(poly1))
1868 SortPrimitive temp = *poly2;
1869 memmove(triangles + q, triangles + q + 1, sizeof(SortPrimitive)*q);
1871 triangles[nTriangles-1] = temp;
1884 for(c=0; c<nTriangles; c++)
1887 SortPrimitive * poly1 = &triangles[c];
1889 // for(b=0; b<nTriangles; b++)
1890 //for(b=c+1; b<nTriangles; b++)
1892 if(b<this.nTriangles)
1894 SortPrimitive * poly2 = &this.triangles[b];
1896 if(poly1->ZOverlap(poly2) && poly1->ShouldBeSwapped(poly2))
1898 SortPrimitive temp = *poly1;
1911 bool IsDriverTextMode(const char * driverName)
1913 subclass(DisplayDriver) driver = GetDisplayDriver(driverName);
1914 return driver ? driver.textMode : false;
1917 bool IsDriverPrinter(const char * driverName)
1919 subclass(DisplayDriver) driver = GetDisplayDriver(driverName);
1920 return driver ? driver.printer : false;
1923 static ColorAlpha defaultPalette[256] =
1927 0xFF000000,0xFF000080,0xFF008000,0xFF008080,0xFF800000,0xFF800080,0xFF808000,0xFFC0C0C0,
1928 0xFF808080,0xFF0000FF,0xFF00FF00,0xFF00FFFF,0xFFFF0000,0xFFFF00FF,0xFFFFFF00,0xFFFFFFFF,
1930 0xFF000000,0xFF0000AA,0xFF00AA00,0xFF00AAAA,0xFFAA0000,0xFFAA00AA,0xFFAAAA00,0xFFABABAB,
1931 0xFF555555,0xFF5555FF,0xFF55FF55,0xFF55FFFF,0xFFFF5555,0xFFFF55FF,0xFFFFFF55,0xFFFFFFFF,
1933 // 6 x 6 x 6 Color Cube
1934 0xFF000000, 0xFF000033, 0xFF000066, 0xFF000099, 0xFF0000CC, 0xFF0000FF,
1935 0xFF003300, 0xFF003333, 0xFF003366, 0xFF003399, 0xFF0033CC, 0xFF0033FF,
1936 0xFF006600, 0xFF006633, 0xFF006666, 0xFF006699, 0xFF0066CC, 0xFF0066FF,
1937 0xFF009900, 0xFF009933, 0xFF009966, 0xFF009999, 0xFF0099CC, 0xFF0099FF,
1938 0xFF00CC00, 0xFF00CC33, 0xFF00CC66, 0xFF00CC99, 0xFF00CCCC, 0xFF00CCFF,
1939 0xFF00FF00, 0xFF00FF33, 0xFF00FF66, 0xFF00FF99, 0xFF00FFCC, 0xFF00FFFF,
1941 0xFF330000, 0xFF330033, 0xFF330066, 0xFF330099, 0xFF3300CC, 0xFF3300FF,
1942 0xFF333300, 0xFF333333, 0xFF333366, 0xFF333399, 0xFF3333CC, 0xFF3333FF,
1943 0xFF336600, 0xFF336633, 0xFF336666, 0xFF336699, 0xFF3366CC, 0xFF3366FF,
1944 0xFF339900, 0xFF339933, 0xFF339966, 0xFF339999, 0xFF3399CC, 0xFF3399FF,
1945 0xFF33CC00, 0xFF33CC33, 0xFF33CC66, 0xFF33CC99, 0xFF33CCCC, 0xFF33CCFF,
1946 0xFF33FF00, 0xFF33FF33, 0xFF33FF66, 0xFF33FF99, 0xFF33FFCC, 0xFF33FFFF,
1948 0xFF660000, 0xFF660033, 0xFF660066, 0xFF660099, 0xFF6600CC, 0xFF6600FF,
1949 0xFF663300, 0xFF663333, 0xFF663366, 0xFF663399, 0xFF6633CC, 0xFF6633FF,
1950 0xFF666600, 0xFF666633, 0xFF666666, 0xFF666699, 0xFF6666CC, 0xFF6666FF,
1951 0xFF669900, 0xFF669933, 0xFF669966, 0xFF669999, 0xFF6699CC, 0xFF6699FF,
1952 0xFF66CC00, 0xFF66CC33, 0xFF66CC66, 0xFF66CC99, 0xFF66CCCC, 0xFF66CCFF,
1953 0xFF66FF00, 0xFF66FF33, 0xFF66FF66, 0xFF66FF99, 0xFF66FFCC, 0xFF66FFFF,
1955 0xFF990000, 0xFF990033, 0xFF990066, 0xFF990099, 0xFF9900CC, 0xFF9900FF,
1956 0xFF993300, 0xFF993333, 0xFF993366, 0xFF993399, 0xFF9933CC, 0xFF9933FF,
1957 0xFF996600, 0xFF996633, 0xFF996666, 0xFF996699, 0xFF9966CC, 0xFF9966FF,
1958 0xFF999900, 0xFF999933, 0xFF999966, 0xFF999999, 0xFF9999CC, 0xFF9999FF,
1959 0xFF99CC00, 0xFF99CC33, 0xFF99CC66, 0xFF99CC99, 0xFF99CCCC, 0xFF99CCFF,
1960 0xFF99FF00, 0xFF99FF33, 0xFF99FF66, 0xFF99FF99, 0xFF99FFCC, 0xFF99FFFF,
1962 0xFFCC0000, 0xFFCC0033, 0xFFCC0066, 0xFFCC0099, 0xFFCC00CC, 0xFFCC00FF,
1963 0xFFCC3300, 0xFFCC3333, 0xFFCC3366, 0xFFCC3399, 0xFFCC33CC, 0xFFCC33FF,
1964 0xFFCC6600, 0xFFCC6633, 0xFFCC6666, 0xFFCC6699, 0xFFCC66CC, 0xFFCC66FF,
1965 0xFFCC9900, 0xFFCC9933, 0xFFCC9966, 0xFFCC9999, 0xFFCC99CC, 0xFFCC99FF,
1966 0xFFCCCC00, 0xFFCCCC33, 0xFFCCCC66, 0xFFCCCC99, 0xFFCCCCCC, 0xFFCCCCFF,
1967 0xFFCCFF00, 0xFFCCFF33, 0xFFCCFF66, 0xFFCCFF99, 0xFFCCFFCC, 0xFFCCFFFF,
1969 0xFFFF0000, 0xFFFF0033, 0xFFFF0066, 0xFFFF0099, 0xFFFF00CC, 0xFFFF00FF,
1970 0xFFFF3300, 0xFFFF3333, 0xFFFF3366, 0xFFFF3399, 0xFFFF33CC, 0xFFFF33FF,
1971 0xFFFF6600, 0xFFFF6633, 0xFFFF6666, 0xFFFF6699, 0xFFFF66CC, 0xFFFF66FF,
1972 0xFFFF9900, 0xFFFF9933, 0xFFFF9966, 0xFFFF9999, 0xFFFF99CC, 0xFFFF99FF,
1973 0xFFFFCC00, 0xFFFFCC33, 0xFFFFCC66, 0xFFFFCC99, 0xFFFFCCCC, 0xFFFFCCFF,
1974 0xFFFFFF00, 0xFFFFFF33, 0xFFFFFF66, 0xFFFFFF99, 0xFFFFFFCC, 0xFFFFFFFF,
1976 // 16 Shades of gray
1977 0xFF000000,0xFF101010,0xFF202020,0xFF303030,0xFF404040,0xFF505050,0xFF606060,0xFF707070,
1978 0xFF808080,0xFF909090,0xFFA0A0A0,0xFFB0B0B0,0xFFC0C0C0,0xFFD0D0D0,0xFFE0E0E0,0xFFF0F0F0,
1981 0xFF080808,0xFF101010,0xFF585858,0xFF606060,0xFFA8A8A8,0xFFB0B0B0,0xFFF8F8F8,0xFFFFFFFF
1985 0xFF080000,0xFF100000,0xFF180000,0xFF200000,0xFF280000,0xFF300000,0xFF380000,0xFF400000,
1986 0xFF480000,0xFF500000,0xFF580000,0xFF600000,0xFF680000,0xFF700000,0xFF780000,0xFF800000,
1987 0xFF880000,0xFF900000,0xFF980000,0xFFA00000,0xFFA80000,0xFFB00000,0xFFB80000,0xFFC00000,
1988 0xFFC80000,0xFFD00000,0xFFD80000,0xFFE00000,0xFFE80000,0xFFF00000,0xFFF80000,0xFFFF0000,
1990 0xFF000800,0xFF001000,0xFF001800,0xFF002000,0xFF002800,0xFF003000,0xFF003800,0xFF004000,
1991 0xFF004800,0xFF005000,0xFF005800,0xFF006000,0xFF006800,0xFF007000,0xFF007800,0xFF008000,
1992 0xFF008800,0xFF009000,0xFF009800,0xFF00A000,0xFF00A800,0xFF00B000,0xFF00B800,0xFF00C000,
1993 0xFF00C800,0xFF00D000,0xFF00D800,0xFF00E000,0xFF00E800,0xFF00F000,0xFF00F800,0xFF00FF00,
1995 0xFF000808,0xFF001010,0xFF001818,0xFF002020,0xFF002828,0xFF003030,0xFF003838,0xFF004040,
1996 0xFF004848,0xFF005050,0xFF005858,0xFF006060,0xFF006868,0xFF007070,0xFF007878,0xFF008080,
1997 0xFF008888,0xFF009090,0xFF009898,0xFF00A0A0,0xFF00A8A8,0xFF00B0B0,0xFF00B8B8,0xFF00C0C0,
1998 0xFF00C8C8,0xFF00D0D0,0xFF00D8D8,0xFF00E0E0,0xFF00E8E8,0xFF00F0F0,0xFF00F8F8,0xFF00FFFF,
2000 0xFF000008,0xFF000010,0xFF000018,0xFF000020,0xFF000028,0xFF000030,0xFF000038,0xFF000040,
2001 0xFF000048,0xFF000050,0xFF000058,0xFF000060,0xFF000068,0xFF000070,0xFF000078,0xFF000080,
2002 0xFF000088,0xFF000090,0xFF000098,0xFF0000A0,0xFF0000A8,0xFF0000B0,0xFF0000B8,0xFF0000C0,
2003 0xFF0000C8,0xFF0000D0,0xFF0000D8,0xFF0000E0,0xFF0000E8,0xFF0000F0,0xFF0000F8,0xFF0000FF,
2005 0xFF080008,0xFF100010,0xFF180018,0xFF200020,0xFF280028,0xFF300030,0xFF380038,0xFF400040,
2006 0xFF480048,0xFF500050,0xFF580058,0xFF600060,0xFF680068,0xFF700070,0xFF780078,0xFF800080,
2007 0xFF880088,0xFF900090,0xFF980098,0xFFA000A0,0xFFA800A8,0xFFB000B0,0xFFB800B8,0xFFC000C0,
2008 0xFFC800C8,0xFFD000D0,0xFFD800D8,0xFFE000E0,0xFFE800E8,0xFFF000F0,0xFFF800F8,0xFFFF00FF,
2010 0xFF080800,0xFF101000,0xFF181800,0xFF202000,0xFF282800,0xFF303000,0xFF383800,0xFF404000,
2011 0xFF484800,0xFF505000,0xFF585800,0xFF606000,0xFF686800,0xFF707000,0xFF787800,0xFF808000,
2012 0xFF888800,0xFF909000,0xFF989800,0xFFA0A000,0xFFA8A800,0xFFB0B000,0xFFB8B800,0xFFC0C000,
2013 0xFFC8C800,0xFFD0D000,0xFFD8D800,0xFFE0E000,0xFFE8E800,0xFFF0F000,0xFFF8F800,0xFFFFFF00,
2015 0xFF080808,0xFF101010,0xFF181818,0xFF202020,0xFF282828,0xFF303030,0xFF383838,0xFF404040,
2016 0xFF484848,0xFF505050,0xFF585858,0xFF606060,0xFF686868,0xFF707070,0xFF787878,0xFF808080,
2017 0xFF888888,0xFF909090,0xFF989898,0xFFA0A0A0,0xFFA8A8A8,0xFFB0B0B0,0xFFB8B8B8,0xFFC0C0C0,
2018 0xFFC8C8C8,0xFFD0D0D0,0xFFD8D8D8,0xFFE0E0E0,0xFFE8E8E8,0xFFF0F0F0,0xFFF8F8F8,0xFFFFFFFF
2022 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
2023 static Material defaultMaterial
2026 diffuse = { 1.0f, 1.0f, 1.0f },
2027 ambient = { 1.0f, 1.0f, 1.0f },
2028 flags = { doubleSided = true, noFog = true };
2032 static byte colorDepthShifts[PixelFormat] = { 0,0,1,1,1,2,0,1,2 };
2033 static Size resolutions[Resolution] =
2036 {320,200},{320,240},{320,400},{360,480},
2037 {400,256},{400,300},{512,256},{512,384},
2038 {640,200},{640,350},{640,400},{640,480},
2039 {720,348},{800,600},{856,480},{960,720},
2040 {1024,768},{1152,864},{1280,1024},{1600,1200},
2043 static int colorDepths[PixelFormat] = {4,8,12,15,16,32,8,16,32};
2045 // --- Query utilities ---
2047 public int GetResolutionWidth(Resolution resolution)
2049 return resolutions[resolution].w;
2052 public int GetResolutionHeight(Resolution resolution)
2054 return resolutions[resolution].h;
2057 public int GetDepthBits(PixelFormat colorDepth)
2059 return colorDepths[colorDepth];
2062 public byte GetColorDepthShifts(PixelFormat format)
2064 return colorDepthShifts[format];
2067 public ColorAlpha * GetDefaultPalette()
2069 return (ColorAlpha *)defaultPalette;
2071 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
2072 public Material GetDefaultMaterial()
2074 return defaultMaterial;
2077 public int BestColorMatch(ColorAlpha * palette, int start, int end, Color rgb)
2083 int bestscore = MAXINT,score;
2084 byte r = rgb.r, g = rgb.g, b = rgb.b;
2087 for(c = start; c <= end; c++)
2090 current = palette[c];
2091 if(rgb && !c) continue;
2095 score = Abs(dr) + Abs(dg) + Abs(db);
2096 if(score <= bestscore)
2106 // had to move this here due to compiler ordering issue for "get property" symbol
2107 subclass(DisplayDriver) GetDisplayDriver(const char * driverName)
2112 for(link = class(DisplayDriver).derivatives.first; link; link = link.next)
2114 subclass(DisplayDriver) displayDriver = link.data;
2115 if(displayDriver && displayDriver.name && !strcmp(displayDriver.name, driverName))
2116 return displayDriver;
2122 DisplaySystem GetDisplaySystem(const char * driverName)
2124 subclass(DisplayDriver) displayDriver = GetDisplayDriver(driverName);
2125 return displayDriver ? displayDriver.displaySystem : null;