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);
800 display3D.mesh = mesh;
803 bool DrawMesh(Object object)
806 if(display3D.selection)
807 result = display3D.PickMesh(object, null);
810 Mesh mesh = object.mesh;
811 Material objectMaterial = object.material;
813 if(mesh.groups.first)
815 PrimitiveGroup group;
816 displaySystem.driver.SelectMesh(this, mesh);
817 display3D.mesh = mesh;
819 for(group = mesh.groups.first; group; group = group.next)
821 Material material = group.material ? group.material : objectMaterial;
822 if(!material) material = defaultMaterial;
824 if(material != display3D.material)
826 display3D.material = material;
827 displaySystem.driver.ApplyMaterial(this, material, mesh);
830 // *** Render Vertex Arrays ***
831 displaySystem.driver.DrawPrimitives(this, (PrimitiveSingle *)&group.type, mesh);
835 if(object.flags.translucent)
838 Matrix inverse, inverseTranspose;
841 if(object.flags.viewSpace)
842 matrix = object.matrix;
845 Camera camera = display3D.camera;
846 Matrix temp = object.matrix;
847 temp.m[3][0] -= camera.cPosition.x;
848 temp.m[3][1] -= camera.cPosition.y;
849 temp.m[3][2] -= camera.cPosition.z;
850 matrix.Multiply(temp, camera.viewMatrix);
853 inverse.Inverse(matrix);
854 inverseTranspose.Transpose(inverse);
856 for(c = 0; c < mesh.nPrimitives; c++)
858 PrimitiveSingle * triangle = &mesh.primitives[c];
859 SortPrimitive * sort;
860 Plane * plane = &triangle->plane;
861 if(display3D.nTriangles >= display3D.maxTriangles)
863 display3D.maxTriangles = display3D.maxTriangles ? (display3D.maxTriangles * 3 / 2) : 32768;
864 display3D.triangles = renew display3D.triangles SortPrimitive[display3D.maxTriangles];
866 sort = &display3D.triangles[display3D.nTriangles++];
867 sort->object = object;
868 sort->triangle = triangle;
869 sort->middle.MultMatrix(triangle->middle, matrix);
870 sort->middle.z *= -1;
871 // sort->plane.MultMatrix(triangle->plane, inverseTranspose);
872 sort->plane.d = plane->a * inverseTranspose.m[0][3] +
873 plane->b * inverseTranspose.m[1][3] +
874 plane->c * inverseTranspose.m[2][3] +
875 plane->d * inverseTranspose.m[3][3];
881 displaySystem.driver.SelectMesh(this, mesh);
882 display3D.mesh = mesh;
884 for(c = 0; c<mesh.nPrimitives; c++)
886 PrimitiveSingle * primitive = &mesh.primitives[c];
888 Material material = primitive->material ? primitive->material : objectMaterial;
889 if(!material) material = defaultMaterial;
891 if(material != display3D.material)
893 display3D.material = material;
894 displaySystem.driver.ApplyMaterial(this, material, mesh);
897 displaySystem.driver.DrawPrimitives(this, primitive, display3D.mesh);
905 bool IsObjectVisible(Object object)
908 if(display3D.selection || !display3D.camera)
909 planes = object.flags.viewSpace ? display3D.viewPickingPlanes : display3D.worldPickingPlanes;
911 planes = object.flags.viewSpace ? display3D.camera.viewClippingPlanes : display3D.camera.worldClippingPlanes;
912 return object.InsideFrustum(planes) != outside;
915 bool DrawObject(Object object)
918 if(object && object.volume)
921 FrustumPlacement visible;
923 Camera camera = display3D.camera;
925 if(display3D.selection || !camera)
926 planes = object.flags.viewSpace ? display3D.viewPickingPlanes : display3D.worldPickingPlanes;
928 planes = object.flags.viewSpace ? camera.viewClippingPlanes : camera.worldClippingPlanes;
930 visible = object.InsideFrustum(planes);
932 if(visible || display3D.pickingPlanes)
934 if(display3D.collectingHits && object.tag)
936 /*if(object.flags.root)
937 this.tags[display3D.tagIndex] = object.tag;
939 this.tags[++display3D.tagIndex] = object.tag;
941 display3D.tags[display3D.tagIndex++] = object.tag;
944 if(object.flags.mesh && object.mesh)
946 if(!display3D.selection && displaySystem.driver.PushMatrix)
947 displaySystem.driver.PushMatrix(this);
950 if(object.mesh.tangents && object.mesh.normals)
952 Mesh mesh = object.mesh;
955 int count = mesh.nVertices;
956 Vector3Df * normals = mesh.normals;
957 Vector3Df * vertices = mesh.vertices;
958 ColorRGB * lightVectors;
959 Vector3Df * tangents = mesh.tangents;
961 float * l = display3D.light0Pos;
962 Vector3Df light { l[0], l[1], l[2] };
963 Matrix o = object.matrix;
964 Matrix t, inv = camera.viewMatrix;
966 Vector3D cPos = camera.cPosition;
968 bool positional = l[3] ? true : false;
970 inv.Scale(1.0/nearPlane, -1.0/nearPlane,-1.0/nearPlane);
972 pos.MultMatrix(cPos, camera.viewMatrix);
974 ot.x = o.m[3][0] + pos.x;
975 ot.y = o.m[3][1] + pos.y;
976 ot.z = o.m[3][2] + pos.z;
985 mesh.Allocate({ lightVectors = true }, mesh.nVertices, displaySystem);
986 mesh.Lock({ lightVectors = true });
987 lightVectors = mesh.lightVectors;
988 for(i = 0; i < count; i++)
990 Vector3Df tangent1 = tangents[i*2 + 0];
991 Vector3Df tangent2 = tangents[i*2 + 1];
992 Vector3Df normal = normals[i];
993 Vector3Df tTangent1, tTangent2, tNormal;
995 tTangent1.MultMatrix(tangent1, inv);
996 tTangent2.MultMatrix(tangent2, inv);
997 tNormal .MultMatrix(normal, inv);
999 tTangent1.Normalize(tTangent1);
1000 tTangent2.Normalize(tTangent2);
1001 tNormal .Normalize(tNormal);
1006 tTangent1.x, tTangent2.x, tNormal.x, 0,
1007 tTangent1.y, tTangent2.y, tNormal.y, 0,
1008 tTangent1.z, tTangent2.z, tNormal.z, 1
1013 Vector3Df tPos = vertices[i];
1014 tPos.x += ot.x, tPos.y += ot.y, tPos.z += ot.z;
1016 // Subtract vertex from light for positional lights
1017 light.x = l[0] - tPos.x;
1018 light.y = l[1] + tPos.y;
1019 light.z = l[2] - tPos.z;
1021 n.MultMatrix(light, tbn);
1024 lightVectors[i] = { n.x / 2 + 0.5f, n.y / 2 + 0.5f, n.z / 2 + 0.5f };
1027 mesh.Unlock({ lightVectors = true });
1029 // Create normalization cube map
1034 int w = 256, h = 256, d = 256;
1035 Vector3Df min = mesh.min, max = mesh.max;
1038 (max.x - min.x) / w,
1039 (max.y - min.y) / h,
1043 for(i = 0; i < 6; i++)
1045 Bitmap face = i > 0 ? { } : mesh.normMap;
1049 face.Allocate(null, w, h, 0, pixelFormat888, false);
1050 face.driverData = mesh.normMap.driverData;
1051 p = (ColorAlpha *)face.picture;
1052 for(y = 0; y < h; y++)
1054 for(x = 0; x < w; x++, p++)
1056 Vector3Df v { min.x + x * delta.x, min.y + y * delta.y, min.z };
1058 *p = ColorAlpha { 255, {
1059 (byte)((v.x / 2.0 + 0.5) * 255),
1060 (byte)((v.y / 2.0 + 0.5) * 255),
1061 (byte)((v.z / 2.0 + 0.5) * 255) } };
1064 displaySystem.driver.MakeDDBitmap(displaySystem, face, true, (i + 1));
1067 face.driverData = 0;
1075 mesh.Free({ lightVectors = true });
1079 SetTransform(object.matrix, object.flags.viewSpace);
1080 if(display3D.selection)
1082 if(visible == intersecting || display3D.intersecting)
1084 Vector3D rayIntersect;
1085 if(display3D.PickMesh(object, rayIntersect))
1087 if(display3D.intersecting)
1089 Vector3D wresult, vresult;
1090 wresult.MultMatrix(rayIntersect, object.matrix);
1091 if(!object.flags.viewSpace)
1092 camera.TransformPoint(vresult, wresult);
1096 if(vresult.z < display3D.rayIntersect.z)
1097 display3D.rayIntersect = vresult;
1098 display3D.intersected = true;
1108 result |= DrawMesh(object);
1109 if(displaySystem.driver.PopMatrix)
1110 displaySystem.driver.PopMatrix(this, true);
1112 if(display3D.collectingHits && result /*&& object.tag*/)
1115 HitRecord hit = (HitRecord)new0 byte[sizeof(class HitRecord) + sizeof(void *) * (display3D.tagIndex/*+1*/)];
1116 display3D.hitList.Add(hit);
1117 hit.pos = display3D.hitList.count-1;
1118 hit.numTags = display3D.tagIndex /*+ 1*/;
1119 for(c = 0; c</*=*/display3D.tagIndex; c++)
1121 hit.tags[c] = display3D.tags[c];
1124 if(!object.flags.viewSpace)
1125 camera.TransformPoint(hit.center, object.wcenter);
1127 hit.center = object.wcenter;
1131 for(child = object.children.first; child; child = child.next)
1132 result |= DrawObject(child);
1134 if(display3D.collectingHits && /*!object.flags.root && */object.tag)
1135 display3D.tagIndex--;
1141 void DrawTranslucency(void)
1143 if(display3D.camera)
1145 // *** Render translucent primitives ***
1146 if(display3D.nTriangles)
1148 Matrix * matrix = null;
1153 display3D.SortTriangles();
1157 displaySystem.driver.PushMatrix(this);
1158 for(c=0; c<display3D.nTriangles; c++)
1160 SortPrimitive * sort = &display3D.triangles[c];
1161 Mesh mesh = sort->object.mesh;
1162 PrimitiveSingle * primitive = sort->triangle;
1165 if(&sort->object.matrix != matrix)
1167 matrix = &sort->object.matrix;
1169 displaySystem.driver.PopMatrix(this, false);
1170 displaySystem.driver.PushMatrix(this);
1171 SetTransform(matrix, sort->object.flags.viewSpace);
1173 if(mesh != display3D.mesh)
1175 displaySystem.driver.SelectMesh(this, mesh);
1176 display3D.mesh = mesh;
1179 material = primitive->material ? primitive->material : sort->object.material;
1180 if(!material) material = defaultMaterial;
1182 if(material != display3D.material)
1184 displaySystem.driver.ApplyMaterial(this, material, display3D.mesh);
1185 display3D.material = material;
1190 Material testMaterial { };
1193 amount = (display3D.triangles[0].middle.z - display3D.triangles[c].middle.z) /
1194 (display3D.triangles[0].middle.z - display3D.triangles[display3D.nTriangles-1].middle.z);
1196 testMaterial.flags.doubleSided = { doubleSided = true, translucent = true };
1197 testMaterial.diffuse.a = 1;
1198 testMaterial.emissive.r = testMaterial.emissive.g = testMaterial.emissive.b = amount;
1199 testMaterial.baseMap = material->baseMap;
1201 displaySystem.driver.ApplyMaterial(this, testMaterial, display3D.mesh);
1205 // *** Render primitive ***
1206 // if(sort->plane.d > 0)
1207 displaySystem.driver.DrawPrimitives(this, primitive, display3D.mesh);
1209 displaySystem.driver.PopMatrix(this, true);
1211 display3D.nTriangles = 0;
1218 void StartSelection(int pickX, int pickY, int pickW, int pickH)
1222 display3D = Display3D { };
1224 display3D.pickX = (float)pickX;
1225 display3D.pickY = (float)pickY;
1226 display3D.pickWidth = (float)pickW;
1227 display3D.pickHeight = (float)pickH;
1228 display3D.selection = true;
1231 void CollectHits(void)
1233 display3D.collectingHits = true;
1236 int GetHits(OldList list)
1238 display3D.collectingHits = false;
1239 display3D.hitList.Sort(HitRecord::Compare, null);
1240 list = display3D.hitList;
1241 display3D.hitList.Clear();
1245 void IntersectPolygons(void)
1247 display3D.rayIntersect = { MAXFLOAT, MAXFLOAT, MAXFLOAT };
1248 display3D.intersected = false;
1249 display3D.intersecting = true;
1252 bool GetIntersect(Vector3D intersect)
1254 intersect = display3D.rayIntersect;
1255 display3D.intersecting = false;
1256 return display3D.intersected;
1259 void StopSelection(void)
1261 display3D.selection = false;
1264 // --- Rendering States ---
1265 property FillModeValue fillMode { set { displaySystem.driver.SetRenderState(this, fillMode, value); } };
1266 property bool depthTest { set { displaySystem.driver.SetRenderState(this, depthTest, value); } };
1267 property bool depthWrite { set { displaySystem.driver.SetRenderState(this, depthWrite, value); } };
1268 property float fogDensity { set { displaySystem.driver.SetRenderState(this, fogDensity, RenderStateFloat { value }.ui); } };
1269 property Color fogColor { set { displaySystem.driver.SetRenderState(this, fogColor, value); } };
1270 property bool blend { set { displaySystem.driver.SetRenderState(this, blend, value); } };
1271 property Color ambient { set { displaySystem.driver.SetRenderState(this, ambient, value); } };
1272 property bool alphaWrite { set { displaySystem.driver.SetRenderState(this, alphaWrite, value); } };
1273 property bool antiAlias { set { displaySystem.driver.SetRenderState(this, antiAlias, value); } };
1274 property bool vSync { set { displaySystem.driver.SetRenderState(this, vSync, value); } };
1276 property bool pickingPlanes { set { display3D.pickingPlanes = value; } };
1278 property DisplayFlags flags { get { return displaySystem.flags; } }
1279 property PixelFormat pixelFormat { get { return /*alphaBlend ? pixelFormat888 : */displaySystem.pixelFormat; } }
1280 property bool alphaBlend { set { alphaBlend = value; } get { return alphaBlend; } };
1281 property bool useSharedMemory { set { useSharedMemory = value; } get { return useSharedMemory; } };
1282 property void * systemWindow { get { return window; } };
1283 property DisplaySystem displaySystem { get { return displaySystem; } };
1284 #ifndef ECERE_VANILLA
1285 property GLCapabilities glCapabilities
1287 get { return ((OGLDisplay)driverData).capabilities; }
1290 glCapabilities = value;
1291 if(driverData && displaySystem.driver == class(OpenGLDisplayDriver))
1293 OGLDisplay oglDisplay = driverData;
1294 if(!oglDisplay.originalCapabilities.fixedFunction)
1295 value.shaders = true;
1296 if(!oglDisplay.originalCapabilities.shaders)
1297 value.fixedFunction = true;
1298 // Disable things that don't work with shaders
1301 value.fixedFunction = false;
1302 value.legacy = false;
1303 value.immediate = false;
1305 oglDisplay.capabilities = oglDisplay.originalCapabilities & value;
1308 OpenGLDisplayDriver::initialDisplaySetup(this, true, false);
1320 DisplaySystem displaySystem;
1323 #if !defined(__EMSCRIPTEN__)
1328 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
1329 Display3D display3D;
1332 void * windowDriverData;
1333 bool useSharedMemory;
1334 GLCapabilities glCapabilities;
1335 glCapabilities = { true, true, true, true, true, true, true, true };
1338 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
1339 private class Display3D : struct
1343 SortPrimitive * triangles;
1345 Vector3D points[MAX_CLIP_POINTS];
1346 Vector3D newPoints[MAX_CLIP_POINTS];
1347 byte goodPoints[MAX_CLIP_POINTS];
1352 Plane viewPickingPlanes[ClippingPlane], worldPickingPlanes[ClippingPlane];
1353 Plane localPickingPlanes[ClippingPlane];
1355 bool collectingHits, selection, intersecting, intersected, pickingPlanes;
1356 float pickX, pickY, pickWidth, pickHeight;
1361 Line rayView, rayWorld, rayLocal;
1362 Vector3D rayIntersect;
1370 int _SetLights(Display display, Object object, int id)
1372 if(id < NumberOfLights)
1376 if(object.flags.light && !object.light.flags.off)
1377 display.SetLight(id++, object.light);
1379 for(child = object.children.first; child; child = child.next)
1381 id = _SetLights(display, child, id);
1387 //#define TRESHOLD -1
1388 //#define TRESHOLD -0.25
1389 #define TRESHOLD -0.0025
1391 bool PickPrimitives(Mesh mesh, PrimitiveSingle primitive, Vector3D rayDiff, Vector3D rayIntersect)
1393 Plane * planes = localPickingPlanes;
1395 int nIndex = 1, nPoints = 1;
1397 bool result = false;
1398 Vector3D * points = this.points;
1399 Vector3D * newPoints = this.newPoints;
1400 byte * goodPoints = this.goodPoints;
1401 int nVertices = primitive.type.vertexRange ? primitive.nVertices : primitive.nIndices;
1404 bool i32bit = primitive.type.indices32bit;
1405 uint32 * indices32 = primitive.indices32;
1406 uint16 * indices16 = primitive.indices;
1408 switch(primitive.type.primitiveType)
1410 case triangles: nIndex = 3; nPoints = 3; break;
1411 case quads: nIndex = 4; nPoints = 4; break;
1414 nIndex = 1; nPoints = 3;
1416 tmp = primitive.type.vertexRange ? mesh.vertices[primitive.first] : mesh.vertices[(i32bit ? indices32[0] : indices16[0])];
1417 points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1418 tmp = primitive.type.vertexRange ? mesh.vertices[primitive.first+1] : mesh.vertices[(i32bit ? indices32[1] : indices16[1])];
1419 points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1423 for(c = offset; c<nVertices; c += nIndex)
1425 bool outside = false;
1432 if(primitive.type.vertexRange)
1434 if(primitive.type.primitiveType == triStrip)
1436 tmp = mesh.vertices[primitive.first + (c & 1) ? (c - 1) : (c - 2)];
1437 points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1438 tmp = mesh.vertices[primitive.first + (c & 1) ? (c - 2) : (c - 1)];
1439 points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1441 else if(primitive.type.primitiveType == triFan)
1443 tmp = mesh.vertices[primitive.first + 0];
1444 points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1445 tmp = mesh.vertices[primitive.first + c - 1];
1446 points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1448 for(i = 0; i<nIndex; i++)
1450 tmp = mesh.vertices[primitive.first + c+i];
1451 points[i + offset] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1456 if(primitive.type.primitiveType == triStrip)
1458 i = (c & 1) ? (c - 1) : (c - 2);
1459 tmp = mesh.vertices[(i32bit ? indices32[i] : indices16[i])];
1460 points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1462 i = (c & 1) ? (c - 2) : (c - 1);
1463 tmp = mesh.vertices[(i32bit ? indices32[i] : indices16[i])];
1464 points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1466 else if(primitive.type.primitiveType == triFan)
1468 tmp = mesh.vertices[(i32bit ? indices32[0] : indices16[0])];
1469 points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1470 tmp = mesh.vertices[(i32bit ? indices32[c-1] : indices16[c-1])];
1471 points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1473 for(i = 0; i<nIndex; i++)
1475 tmp = mesh.vertices[(i32bit ? indices32[c+i] : indices16[c+i])];
1476 points[i + offset] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1480 for(p = 0; p < 6; p++)
1482 Plane * plane = &planes[p];
1484 int numGoodPoints = 0;
1486 memset(goodPoints, 0, n);
1487 for(i = 0; i < n; i++)
1489 double dot = plane->normal.DotProduct(points[i]);
1490 double distance = dot + plane->d;
1491 if(distance > TRESHOLD)
1502 if(numGoodPoints < n)
1513 newPoints[newN++] = points[j];
1522 for(lastGood = n-1; !goodPoints[lastGood]; lastGood--);
1524 edge.p0 = points[lastGood];
1525 edge.delta.Subtract(points[j], edge.p0);
1526 plane->IntersectLine(edge, newPoints[newN++]);
1528 for(next = j+1; next != j; next++)
1530 if(next == n) next = 0;
1531 if(goodPoints[next])
1533 int prev = next - 1;
1534 if(prev < 0) prev = n-1;
1536 edge.p0 = points[prev];
1537 edge.delta.Subtract(points[next], edge.p0);
1538 plane->IntersectLine(edge, newPoints[newN++]);
1548 // Use the new points
1549 memcpy(points, newPoints, newN * sizeof(Vector3D));
1558 // TODO: Implement intersection with TriStrip, TriFan...
1561 // Intersect primitives
1563 Vector3D intersect, diff;
1564 int i0 = c, i1 = c+1, i2 = c+2;
1566 if(primitive.type.primitiveType == triStrip)
1568 i0 = (c & 1) ? (c - 1) : (c - 2);
1569 i1 = (c & 1) ? (c - 2) : (c - 1);
1572 else if(primitive.type.primitiveType == triFan)
1579 if(primitive.type.vertexRange)
1581 mesh.vertices[primitive.first + i0],
1582 mesh.vertices[primitive.first + i1],
1583 mesh.vertices[primitive.first + i2]);
1586 mesh.vertices[(i32bit ? indices32[i0] : indices16[i0])],
1587 mesh.vertices[(i32bit ? indices32[i1] : indices16[i1])],
1588 mesh.vertices[(i32bit ? indices32[i2] : indices16[i2])]);
1590 plane.IntersectLine(rayLocal, intersect);
1591 diff.Subtract(intersect, rayLocal.p0);
1592 diff.x /= rayLocal.delta.x;
1593 diff.y /= rayLocal.delta.y;
1594 diff.z /= rayLocal.delta.z;
1595 if(diff.x < rayDiff.x || diff.y < rayDiff.y || diff.z < rayDiff.z)
1598 rayIntersect = intersect;
1605 switch(primitive.type)
1608 points[strip] = points[2];
1612 points[1] = points[2];
1619 bool PickMesh(Object object, Vector3D rayIntersect)
1621 Mesh mesh = object.mesh;
1622 bool result = false;
1623 Vector3D rayDiff { MAXFLOAT, MAXFLOAT, MAXFLOAT };
1624 if(rayIntersect != null)
1625 rayIntersect = { MAXFLOAT, MAXFLOAT, MAXFLOAT };
1627 if(mesh.groups.first)
1629 PrimitiveGroup group;
1631 for(group = mesh.groups.first; group; group = group.next)
1633 if(PickPrimitives(mesh, (PrimitiveSingle *)&group.type, rayDiff, rayIntersect))
1644 for(c = 0; c < mesh.nPrimitives; c++)
1646 if(PickPrimitives(mesh, mesh.primitives[c], rayDiff, rayIntersect))
1657 void SortTriangles(void)
1660 Object object = null;
1662 for(c=0; c<nTriangles; c++)
1664 SortPrimitive * sort = &triangles[c];
1665 Mesh mesh = sort->object.mesh;
1666 PrimitiveSingle * primitive = sort->triangle;
1667 Vector3Df min { MAXFLOAT, MAXFLOAT, MAXFLOAT };
1668 Vector3Df max { -MAXFLOAT, -MAXFLOAT, -MAXFLOAT };
1670 bool ix32 = primitive->type.indices32bit;
1671 if(object != sort->object)
1673 object = sort->object;
1674 if(object.flags.viewSpace)
1675 matrix = object.matrix;
1678 Camera camera = this.camera;
1679 Matrix temp = object.matrix;
1680 temp.m[3][0] -= camera.cPosition.x;
1681 temp.m[3][1] -= camera.cPosition.y;
1682 temp.m[3][2] -= camera.cPosition.z;
1683 matrix.Multiply(temp, camera.viewMatrix);
1687 for(v = 0; v<primitive->nIndices; v++)
1689 Vector3Df * local = &mesh.vertices[ix32 ? primitive->indices32[v] : primitive->indices[v]];
1692 vertex.MultMatrix(local, &matrix);
1694 if(vertex.x > max.x) max.x = vertex.x;
1695 if(vertex.y > max.y) max.y = vertex.y;
1696 if(vertex.z > max.z) max.z = vertex.z;
1697 if(vertex.x < min.x) min.x = vertex.x;
1698 if(vertex.y < min.y) min.y = vertex.y;
1699 if(vertex.z < min.z) min.z = vertex.z;
1705 sort->marked = false;
1709 Logf("========= Before Sort ==========\n");
1710 for(c=0; c<nTriangles; c++)
1712 SortPrimitive * sort = &triangles[c];
1714 Mesh mesh = sort->mesh;
1715 PrimitiveSingle * primitive = sort->triangle;
1717 Logf("Triangle %d (%s):\n", c, primitive->material->name);
1719 for(v = 0; v<primitive->nIndices; v++)
1721 Vector3Df * local = &mesh.vertices[primitive->indices[v]];
1725 vertex.<MultMatrix(local, sort->matrix);
1727 Logf("Vertex %d:", v);
1729 // Logf(" Local %f, %f, %f:\n", local->x, local->y, local->z);
1730 Logf(" View %f, %f, %f:\n", vertex.x, vertex.y, vertex.z);
1734 Logf("Min %f, %f, %f:\n", sort->min.x, sort->min.y, sort->min.z);
1735 Logf("Max %f, %f, %f:\n", sort->max.x, sort->max.y, sort->max.z);
1739 // *** Sort translucent primitives ***
1740 qsort((void*) triangles, nTriangles, sizeof(SortPrimitive), SortPrimitive::Compare);
1742 Logf("\n\n========= After Sort ==========\n");
1743 for(c=0; c<nTriangles; c++)
1745 SortPrimitive * sort = &triangles[c];
1747 Mesh mesh = sort->mesh;
1748 PrimitiveSingle * primitive = sort->triangle;
1750 Logf("Triangle %d (%s):\n", c, primitive->material->name);
1752 for(v = 0; v<primitive->nIndices; v++)
1754 Vector3Df * local = &mesh.vertices[primitive->indices[v]];
1758 vertex.MultMatrix(local, sort->matrix);
1760 Logf("Vertex %d:", v);
1762 // Logf(" Local %f, %f, %f:\n", local->x, local->y, local->z);
1763 Logf(" View %f, %f, %f:\n", vertex.x, vertex.y, vertex.z);
1767 Logf("Min %f, %f, %f:\n", sort->min.x, sort->min.y, sort->min.z);
1768 Logf("Max %f, %f, %f:\n", sort->max.x, sort->max.y, sort->max.z);
1775 If all five tests fail for a particular Q,
1776 then P might obscure Q. Now Q must be tested.
1777 First, the algorithm checks if Q has been "marked."
1778 If Q is marked, then Q was "moved around" in the list
1779 during a previous iteration of the loop. The algorithm
1780 only allows a polygon to be moved once, to avoid the possibility
1781 of infinite loops. If Q is not marked, it is tested to see
1782 if it might obscure P. If Q cannot obscure P, then Q is possibly
1783 behind P and so it is good candidate to be drawn next.
1784 Therefore, the algorithm "abandons" the current P (that is, it
1785 stops testing Q's against the current P) and moves the current
1786 Q to the end of the list to become the next P.
1791 for(p = 0; p<nTriangles; p++)
1793 SortPrimitive * poly1 = &triangles[p];
1796 for(q = p+1; q<nTriangles; q++)
1800 SortPrimitive * poly2 = &triangles[q];
1801 if(poly1->ZOverlap(poly2) && !poly2->marked)
1803 if(poly1->ShouldBeSwapped(poly2))
1805 if(!poly2->ShouldBeSwapped(poly1))
1807 SortPrimitive temp = *poly2;
1808 memmove(triangles+1, triangles, sizeof(SortPrimitive)*q);
1809 triangles[0] = temp;
1810 triangles[0].marked = true;
1823 for(p = 0; p<nTriangles; p++)
1825 SortPrimitive * poly1 = &triangles[p];
1828 // for(q = p+1; q<nTriangles; q++)
1829 for(q = 0; q<nTriangles; q++)
1833 SortPrimitive * poly2 = &triangles[q];
1834 if(poly1->ZOverlap(poly2) && !poly2->marked)
1836 if(poly1->ShouldBeSwapped(poly2))
1838 if(!poly2->ShouldBeSwapped(poly1))
1840 SortPrimitive temp = *poly2;
1841 memmove(triangles+1, triangles, sizeof(SortPrimitive)*q);
1842 triangles[0] = temp;
1843 triangles[0].marked = true;
1856 for(p = nTriangles-1; p>=0; p--)
1858 SortPrimitive * poly1 = &triangles[p];
1861 for(q = nTriangles-1; q>=0; q--)
1865 SortPrimitive * poly2 = &triangles[q];
1866 if(poly1->ZOverlap(poly2) && !poly2->marked)
1868 if(poly1->ShouldBeSwapped(poly2))
1870 if(!poly2->ShouldBeSwapped(poly1))
1872 SortPrimitive temp = *poly2;
1873 memmove(triangles + q, triangles + q + 1, sizeof(SortPrimitive)*q);
1875 triangles[nTriangles-1] = temp;
1888 for(c=0; c<nTriangles; c++)
1891 SortPrimitive * poly1 = &triangles[c];
1893 // for(b=0; b<nTriangles; b++)
1894 //for(b=c+1; b<nTriangles; b++)
1896 if(b<this.nTriangles)
1898 SortPrimitive * poly2 = &this.triangles[b];
1900 if(poly1->ZOverlap(poly2) && poly1->ShouldBeSwapped(poly2))
1902 SortPrimitive temp = *poly1;
1915 bool IsDriverTextMode(const char * driverName)
1917 subclass(DisplayDriver) driver = GetDisplayDriver(driverName);
1918 return driver ? driver.textMode : false;
1921 bool IsDriverPrinter(const char * driverName)
1923 subclass(DisplayDriver) driver = GetDisplayDriver(driverName);
1924 return driver ? driver.printer : false;
1927 static ColorAlpha defaultPalette[256] =
1931 0xFF000000,0xFF000080,0xFF008000,0xFF008080,0xFF800000,0xFF800080,0xFF808000,0xFFC0C0C0,
1932 0xFF808080,0xFF0000FF,0xFF00FF00,0xFF00FFFF,0xFFFF0000,0xFFFF00FF,0xFFFFFF00,0xFFFFFFFF,
1934 0xFF000000,0xFF0000AA,0xFF00AA00,0xFF00AAAA,0xFFAA0000,0xFFAA00AA,0xFFAAAA00,0xFFABABAB,
1935 0xFF555555,0xFF5555FF,0xFF55FF55,0xFF55FFFF,0xFFFF5555,0xFFFF55FF,0xFFFFFF55,0xFFFFFFFF,
1937 // 6 x 6 x 6 Color Cube
1938 0xFF000000, 0xFF000033, 0xFF000066, 0xFF000099, 0xFF0000CC, 0xFF0000FF,
1939 0xFF003300, 0xFF003333, 0xFF003366, 0xFF003399, 0xFF0033CC, 0xFF0033FF,
1940 0xFF006600, 0xFF006633, 0xFF006666, 0xFF006699, 0xFF0066CC, 0xFF0066FF,
1941 0xFF009900, 0xFF009933, 0xFF009966, 0xFF009999, 0xFF0099CC, 0xFF0099FF,
1942 0xFF00CC00, 0xFF00CC33, 0xFF00CC66, 0xFF00CC99, 0xFF00CCCC, 0xFF00CCFF,
1943 0xFF00FF00, 0xFF00FF33, 0xFF00FF66, 0xFF00FF99, 0xFF00FFCC, 0xFF00FFFF,
1945 0xFF330000, 0xFF330033, 0xFF330066, 0xFF330099, 0xFF3300CC, 0xFF3300FF,
1946 0xFF333300, 0xFF333333, 0xFF333366, 0xFF333399, 0xFF3333CC, 0xFF3333FF,
1947 0xFF336600, 0xFF336633, 0xFF336666, 0xFF336699, 0xFF3366CC, 0xFF3366FF,
1948 0xFF339900, 0xFF339933, 0xFF339966, 0xFF339999, 0xFF3399CC, 0xFF3399FF,
1949 0xFF33CC00, 0xFF33CC33, 0xFF33CC66, 0xFF33CC99, 0xFF33CCCC, 0xFF33CCFF,
1950 0xFF33FF00, 0xFF33FF33, 0xFF33FF66, 0xFF33FF99, 0xFF33FFCC, 0xFF33FFFF,
1952 0xFF660000, 0xFF660033, 0xFF660066, 0xFF660099, 0xFF6600CC, 0xFF6600FF,
1953 0xFF663300, 0xFF663333, 0xFF663366, 0xFF663399, 0xFF6633CC, 0xFF6633FF,
1954 0xFF666600, 0xFF666633, 0xFF666666, 0xFF666699, 0xFF6666CC, 0xFF6666FF,
1955 0xFF669900, 0xFF669933, 0xFF669966, 0xFF669999, 0xFF6699CC, 0xFF6699FF,
1956 0xFF66CC00, 0xFF66CC33, 0xFF66CC66, 0xFF66CC99, 0xFF66CCCC, 0xFF66CCFF,
1957 0xFF66FF00, 0xFF66FF33, 0xFF66FF66, 0xFF66FF99, 0xFF66FFCC, 0xFF66FFFF,
1959 0xFF990000, 0xFF990033, 0xFF990066, 0xFF990099, 0xFF9900CC, 0xFF9900FF,
1960 0xFF993300, 0xFF993333, 0xFF993366, 0xFF993399, 0xFF9933CC, 0xFF9933FF,
1961 0xFF996600, 0xFF996633, 0xFF996666, 0xFF996699, 0xFF9966CC, 0xFF9966FF,
1962 0xFF999900, 0xFF999933, 0xFF999966, 0xFF999999, 0xFF9999CC, 0xFF9999FF,
1963 0xFF99CC00, 0xFF99CC33, 0xFF99CC66, 0xFF99CC99, 0xFF99CCCC, 0xFF99CCFF,
1964 0xFF99FF00, 0xFF99FF33, 0xFF99FF66, 0xFF99FF99, 0xFF99FFCC, 0xFF99FFFF,
1966 0xFFCC0000, 0xFFCC0033, 0xFFCC0066, 0xFFCC0099, 0xFFCC00CC, 0xFFCC00FF,
1967 0xFFCC3300, 0xFFCC3333, 0xFFCC3366, 0xFFCC3399, 0xFFCC33CC, 0xFFCC33FF,
1968 0xFFCC6600, 0xFFCC6633, 0xFFCC6666, 0xFFCC6699, 0xFFCC66CC, 0xFFCC66FF,
1969 0xFFCC9900, 0xFFCC9933, 0xFFCC9966, 0xFFCC9999, 0xFFCC99CC, 0xFFCC99FF,
1970 0xFFCCCC00, 0xFFCCCC33, 0xFFCCCC66, 0xFFCCCC99, 0xFFCCCCCC, 0xFFCCCCFF,
1971 0xFFCCFF00, 0xFFCCFF33, 0xFFCCFF66, 0xFFCCFF99, 0xFFCCFFCC, 0xFFCCFFFF,
1973 0xFFFF0000, 0xFFFF0033, 0xFFFF0066, 0xFFFF0099, 0xFFFF00CC, 0xFFFF00FF,
1974 0xFFFF3300, 0xFFFF3333, 0xFFFF3366, 0xFFFF3399, 0xFFFF33CC, 0xFFFF33FF,
1975 0xFFFF6600, 0xFFFF6633, 0xFFFF6666, 0xFFFF6699, 0xFFFF66CC, 0xFFFF66FF,
1976 0xFFFF9900, 0xFFFF9933, 0xFFFF9966, 0xFFFF9999, 0xFFFF99CC, 0xFFFF99FF,
1977 0xFFFFCC00, 0xFFFFCC33, 0xFFFFCC66, 0xFFFFCC99, 0xFFFFCCCC, 0xFFFFCCFF,
1978 0xFFFFFF00, 0xFFFFFF33, 0xFFFFFF66, 0xFFFFFF99, 0xFFFFFFCC, 0xFFFFFFFF,
1980 // 16 Shades of gray
1981 0xFF000000,0xFF101010,0xFF202020,0xFF303030,0xFF404040,0xFF505050,0xFF606060,0xFF707070,
1982 0xFF808080,0xFF909090,0xFFA0A0A0,0xFFB0B0B0,0xFFC0C0C0,0xFFD0D0D0,0xFFE0E0E0,0xFFF0F0F0,
1985 0xFF080808,0xFF101010,0xFF585858,0xFF606060,0xFFA8A8A8,0xFFB0B0B0,0xFFF8F8F8,0xFFFFFFFF
1989 0xFF080000,0xFF100000,0xFF180000,0xFF200000,0xFF280000,0xFF300000,0xFF380000,0xFF400000,
1990 0xFF480000,0xFF500000,0xFF580000,0xFF600000,0xFF680000,0xFF700000,0xFF780000,0xFF800000,
1991 0xFF880000,0xFF900000,0xFF980000,0xFFA00000,0xFFA80000,0xFFB00000,0xFFB80000,0xFFC00000,
1992 0xFFC80000,0xFFD00000,0xFFD80000,0xFFE00000,0xFFE80000,0xFFF00000,0xFFF80000,0xFFFF0000,
1994 0xFF000800,0xFF001000,0xFF001800,0xFF002000,0xFF002800,0xFF003000,0xFF003800,0xFF004000,
1995 0xFF004800,0xFF005000,0xFF005800,0xFF006000,0xFF006800,0xFF007000,0xFF007800,0xFF008000,
1996 0xFF008800,0xFF009000,0xFF009800,0xFF00A000,0xFF00A800,0xFF00B000,0xFF00B800,0xFF00C000,
1997 0xFF00C800,0xFF00D000,0xFF00D800,0xFF00E000,0xFF00E800,0xFF00F000,0xFF00F800,0xFF00FF00,
1999 0xFF000808,0xFF001010,0xFF001818,0xFF002020,0xFF002828,0xFF003030,0xFF003838,0xFF004040,
2000 0xFF004848,0xFF005050,0xFF005858,0xFF006060,0xFF006868,0xFF007070,0xFF007878,0xFF008080,
2001 0xFF008888,0xFF009090,0xFF009898,0xFF00A0A0,0xFF00A8A8,0xFF00B0B0,0xFF00B8B8,0xFF00C0C0,
2002 0xFF00C8C8,0xFF00D0D0,0xFF00D8D8,0xFF00E0E0,0xFF00E8E8,0xFF00F0F0,0xFF00F8F8,0xFF00FFFF,
2004 0xFF000008,0xFF000010,0xFF000018,0xFF000020,0xFF000028,0xFF000030,0xFF000038,0xFF000040,
2005 0xFF000048,0xFF000050,0xFF000058,0xFF000060,0xFF000068,0xFF000070,0xFF000078,0xFF000080,
2006 0xFF000088,0xFF000090,0xFF000098,0xFF0000A0,0xFF0000A8,0xFF0000B0,0xFF0000B8,0xFF0000C0,
2007 0xFF0000C8,0xFF0000D0,0xFF0000D8,0xFF0000E0,0xFF0000E8,0xFF0000F0,0xFF0000F8,0xFF0000FF,
2009 0xFF080008,0xFF100010,0xFF180018,0xFF200020,0xFF280028,0xFF300030,0xFF380038,0xFF400040,
2010 0xFF480048,0xFF500050,0xFF580058,0xFF600060,0xFF680068,0xFF700070,0xFF780078,0xFF800080,
2011 0xFF880088,0xFF900090,0xFF980098,0xFFA000A0,0xFFA800A8,0xFFB000B0,0xFFB800B8,0xFFC000C0,
2012 0xFFC800C8,0xFFD000D0,0xFFD800D8,0xFFE000E0,0xFFE800E8,0xFFF000F0,0xFFF800F8,0xFFFF00FF,
2014 0xFF080800,0xFF101000,0xFF181800,0xFF202000,0xFF282800,0xFF303000,0xFF383800,0xFF404000,
2015 0xFF484800,0xFF505000,0xFF585800,0xFF606000,0xFF686800,0xFF707000,0xFF787800,0xFF808000,
2016 0xFF888800,0xFF909000,0xFF989800,0xFFA0A000,0xFFA8A800,0xFFB0B000,0xFFB8B800,0xFFC0C000,
2017 0xFFC8C800,0xFFD0D000,0xFFD8D800,0xFFE0E000,0xFFE8E800,0xFFF0F000,0xFFF8F800,0xFFFFFF00,
2019 0xFF080808,0xFF101010,0xFF181818,0xFF202020,0xFF282828,0xFF303030,0xFF383838,0xFF404040,
2020 0xFF484848,0xFF505050,0xFF585858,0xFF606060,0xFF686868,0xFF707070,0xFF787878,0xFF808080,
2021 0xFF888888,0xFF909090,0xFF989898,0xFFA0A0A0,0xFFA8A8A8,0xFFB0B0B0,0xFFB8B8B8,0xFFC0C0C0,
2022 0xFFC8C8C8,0xFFD0D0D0,0xFFD8D8D8,0xFFE0E0E0,0xFFE8E8E8,0xFFF0F0F0,0xFFF8F8F8,0xFFFFFFFF
2026 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
2027 static Material defaultMaterial
2030 diffuse = { 1.0f, 1.0f, 1.0f },
2031 ambient = { 1.0f, 1.0f, 1.0f },
2032 flags = { doubleSided = true, noFog = true };
2036 static byte colorDepthShifts[PixelFormat] = { 0,0,1,1,1,2,0,1,2 };
2037 static Size resolutions[Resolution] =
2040 {320,200},{320,240},{320,400},{360,480},
2041 {400,256},{400,300},{512,256},{512,384},
2042 {640,200},{640,350},{640,400},{640,480},
2043 {720,348},{800,600},{856,480},{960,720},
2044 {1024,768},{1152,864},{1280,1024},{1600,1200},
2047 static int colorDepths[PixelFormat] = {4,8,12,15,16,32,8,16,32};
2049 // --- Query utilities ---
2051 public int GetResolutionWidth(Resolution resolution)
2053 return resolutions[resolution].w;
2056 public int GetResolutionHeight(Resolution resolution)
2058 return resolutions[resolution].h;
2061 public int GetDepthBits(PixelFormat colorDepth)
2063 return colorDepths[colorDepth];
2066 public byte GetColorDepthShifts(PixelFormat format)
2068 return colorDepthShifts[format];
2071 public ColorAlpha * GetDefaultPalette()
2073 return (ColorAlpha *)defaultPalette;
2075 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
2076 public Material GetDefaultMaterial()
2078 return defaultMaterial;
2081 public int BestColorMatch(ColorAlpha * palette, int start, int end, Color rgb)
2087 int bestscore = MAXINT,score;
2088 byte r = rgb.r, g = rgb.g, b = rgb.b;
2091 for(c = start; c <= end; c++)
2094 current = palette[c];
2095 if(rgb && !c) continue;
2099 score = Abs(dr) + Abs(dg) + Abs(db);
2100 if(score <= bestscore)
2110 // had to move this here due to compiler ordering issue for "get property" symbol
2111 subclass(DisplayDriver) GetDisplayDriver(const char * driverName)
2116 for(link = class(DisplayDriver).derivatives.first; link; link = link.next)
2118 subclass(DisplayDriver) displayDriver = link.data;
2119 if(displayDriver && displayDriver.name && !strcmp(displayDriver.name, driverName))
2120 return displayDriver;
2126 DisplaySystem GetDisplaySystem(const char * driverName)
2128 subclass(DisplayDriver) displayDriver = GetDisplayDriver(driverName);
2129 return displayDriver ? displayDriver.displaySystem : null;