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 public enum RenderState { fillMode = 1, depthTest, depthWrite, fogDensity, fogColor, blend, ambient, alphaWrite, antiAlias, vSync };
36 public union RenderStateFloat { float f; uint ui; };
38 public enum FillModeValue { solid, wireframe };
40 public class DisplayFlags
42 public bool fullScreen:1, flipping:1, alpha:1, memBackBuffer:1, text:1, scrolling:1, printer:1;
44 public class FontFlags
46 public bool bold:1, italic:1, underline:1;
49 __attribute__((unused)) static void DummyFunction()
54 public class DisplayDriver
57 class_data const char * name;
58 class_data bool textMode;
59 class_data bool printer;
60 class_data DisplaySystem displaySystem;
62 class_property DisplaySystem displaySystem
64 set { class_data(displaySystem) = value; }
65 get { return class_data(displaySystem); }
68 class_property const char * name
70 set { class_data(name) = value; }
71 get { return class_data(name); }
74 class_property bool printer
76 set { class_data(printer) = value; }
77 get { return class_data(printer); }
80 // Constructor / Destructor
81 virtual bool ::CreateDisplaySystem(DisplaySystem);
82 virtual void ::DestroyDisplaySystem(DisplaySystem);
84 virtual bool ::CreateDisplay(Display);
85 virtual void ::DestroyDisplay(Display);
87 // Display Position and Size
88 virtual bool ::DisplaySize(Display, int, int);
89 virtual void ::DisplayPosition(Display, int, int);
92 virtual void ::SetPalette(Display, ColorAlpha *, bool);
93 virtual void ::RestorePalette(Display);
95 // Display the back buffer content
96 virtual void ::StartUpdate(Display);
97 virtual void ::Scroll(Display, Box, int, int, Extent);
98 virtual void ::Update(Display, Box);
99 virtual void ::EndUpdate(Display);
101 // Allocate/free a bitmap
102 virtual bool ::AllocateBitmap(DisplaySystem, Bitmap, int, int, int, PixelFormat, bool);
103 virtual void ::FreeBitmap(DisplaySystem, Bitmap);
106 virtual bool ::LockSystem(DisplaySystem displaySystem);
107 virtual void ::UnlockSystem(DisplaySystem displaySystem);
109 virtual bool ::Lock(Display);
110 virtual void ::Unlock(Display);
112 // Get/release a surface
113 virtual bool ::GetSurface(Display, Surface surface, int,int,Box);
114 virtual bool ::GetBitmapSurface(DisplaySystem displaySystem, Surface surface, Bitmap bitmap, int,int,Box);
115 virtual void ::ReleaseSurface(Display this, Surface);
118 virtual void ::Clip(Display, Surface, Box);
120 // Grab from the screen
121 virtual bool ::GrabScreen(Display, Bitmap, int, int, unsigned int, unsigned int);
123 // Converts a bitmap format
124 virtual bool ::ConvertBitmap(DisplaySystem, Bitmap, PixelFormat, ColorAlpha *);
126 // Converts an LFB bitmap into an offscreen bitmap for this device
127 virtual bool ::MakeDDBitmap(DisplaySystem, Bitmap, bool);
130 virtual Font ::LoadFont(DisplaySystem displaySystem, const char * faceName, float size, FontFlags flags);
131 virtual void ::UnloadFont(DisplaySystem, Font);
134 virtual void ::SetForeground(Display, Surface, ColorAlpha);
135 virtual void ::SetBackground(Display, Surface, ColorAlpha);
136 virtual void ::LineStipple(Display, Surface, uint);
137 virtual ColorAlpha ::GetPixel(Display, Surface, int, int);
138 virtual void ::PutPixel(Display, Surface, int, int);
139 virtual void ::DrawLine(Display, Surface, int, int, int, int);
140 virtual void ::Rectangle(Display, Surface,int,int,int,int);
141 virtual void ::Area(Display, Surface,int,int,int,int);
142 virtual void ::Clear(Display, Surface, ClearType);
143 virtual void ::Blit(Display, Surface, Bitmap, int, int, int, int, int, int);
144 virtual void ::Stretch(Display, Surface, Bitmap, int, int, int, int, int, int,int,int);
145 virtual void ::Filter(Display, Surface, Bitmap, int, int, int, int, int, int,int,int);
146 virtual void ::BlitDI(Display, Surface, Bitmap, int, int, int, int, int, int);
147 virtual void ::StretchDI(Display, Surface, Bitmap, int, int, int, int, int, int,int,int);
148 virtual void ::FilterDI(Display, Surface, Bitmap, int, int, int, int, int, int, int,int);
149 virtual void ::TextFont(Display, Surface, Font);
150 virtual void ::TextOpacity(Display, Surface, bool);
151 virtual void ::WriteText(Display, Surface, int, int, const char *, int);
152 virtual void ::TextExtent(Display, Surface, const char *, int, int *, int *);
153 virtual void ::FontExtent(DisplaySystem, Font, const char *, int, int *, int *);
154 virtual void ::DrawingChar(Display, Surface, char);
155 virtual void ::NextPage(Display);
156 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
158 virtual void ::SetRenderState(Display, RenderState, uint);
159 virtual void ::SetLight(Display, int, Light);
160 virtual void ::SetCamera(Display, Surface, Camera);
161 virtual bool ::AllocateMesh(DisplaySystem, Mesh, MeshFeatures, int nVertices);
162 virtual void ::FreeMesh(DisplaySystem, Mesh);
163 virtual bool ::LockMesh(DisplaySystem, Mesh, MeshFeatures flags);
164 virtual void ::UnlockMesh(DisplaySystem, Mesh, MeshFeatures flags);
165 virtual void * ::AllocateIndices(DisplaySystem, int nIndices, bool indices32bit);
166 virtual void ::FreeIndices(DisplaySystem, void * indices);
167 virtual uint16 * ::LockIndices(DisplaySystem, void * indices);
168 virtual void ::UnlockIndices(DisplaySystem, void * indices, bool indices32bit, int nIndices);
169 virtual void ::SelectMesh(Display, Mesh);
170 virtual void ::ApplyMaterial(Display, Material, Mesh);
171 virtual void ::DrawPrimitives(Display, PrimitiveSingle *, Mesh mesh);
172 virtual void ::PushMatrix(Display);
173 virtual void ::PopMatrix(Display, bool);
174 virtual void ::SetTransform(Display, Matrix, bool, bool);
176 virtual void ::SetBlitTint(Display, Surface, ColorAlpha);
179 public enum Alignment { left, right, center };
180 public enum ClearType { colorBuffer, depthBuffer, colorAndDepth };
182 subclass(DisplayDriver) GetDisplayDriver(const char * driverName)
187 for(link = class(DisplayDriver).derivatives.first; link; link = link.next)
189 subclass(DisplayDriver) displayDriver = link.data;
190 if(displayDriver && displayDriver.name && !strcmp(displayDriver.name, driverName))
191 return displayDriver;
197 DisplaySystem GetDisplaySystem(const char * driverName)
199 subclass(DisplayDriver) displayDriver = GetDisplayDriver(driverName);
200 return displayDriver ? displayDriver.displaySystem : null;
203 define textCellW = 8;
204 define textCellH = 16;
206 public enum PixelFormat // : byte MESSES UP GuiApplication
208 pixelFormat4, pixelFormat8, pixelFormat444, pixelFormat555, pixelFormat565, pixelFormat888, pixelFormatAlpha, pixelFormatText, pixelFormatRGBA
210 public enum Resolution : int
212 resText80x25, res320x200, res320x240, res320x400, res360x480, res400x256, res400x300, res512x256, res512x384,
213 res640x200, res640x350, res640x400, res640x480, res720x348, res800x600, res856x480, res960x720, res1024x768,
214 res1152x864, res1280x1024, res1600x1200, res768x480
217 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
218 public class LightFlags
220 public bool off:1, spot:1, omni:1, attenuation:1;
230 Quaternion orientation;
243 define NumberOfLights = 8;
245 // Painter's algorithm
247 public class HitRecord : struct
250 HitRecord prev, next;
254 void * tags[1]; // More tags may follow
256 int Compare(HitRecord recordB, void * unused)
258 if(center.z > recordB.center.z)
260 else if(center.z < recordB.center.z)
262 else if(pos > recordB.pos)
264 else if(pos < recordB.pos)
271 #define EPSILON 0.00001
275 PrimitiveSingle * triangle;
282 int Compare(SortPrimitive primitive2)
285 if(ZOverlap(primitive2) && Sgn(plane.d) != Sgn(primitive2.plane.d))
286 value = plane.d - primitive2.plane.d;
288 value = middle.z - primitive2.middle.z;
292 else if(value<-EPSILON)
298 bool ZOverlap(SortPrimitive poly2)
300 if(min.z > poly2.max.z - EPSILON || poly2.min.z > max.z - EPSILON)
306 bool XYOverlap(SortPrimitive poly2)
308 if(min.x > poly2.max.x - EPSILON || poly2.min.x > max.x - EPSILON )
310 if(min.y > poly2.max.y - EPSILON || poly2.min.y > max.y - EPSILON )
315 bool SurfaceOutside(SortPrimitive poly2)
319 PrimitiveSingle * primitive = triangle;
320 Mesh mesh = object.mesh;
321 Matrix * matrix = &object.matrix;
323 double a = poly2.plane.a, b = poly2.plane.b, c = poly2.plane.c, d = poly2.plane.d;
329 d = - (a * poly2.middle.x + b * poly2.middle.y + c * poly2.middle.z);
332 for(v = 0; v < primitive->nIndices; v++)
335 Vector3Df * local = &mesh.vertices[primitive->indices[v]];
338 vertex.MultMatrix(local, matrix);
340 surface = a * vertex.x + b * vertex.y + c * vertex.z + d;
342 if(surface < EPSILON)
355 bool SurfaceInside(SortPrimitive poly2)
359 PrimitiveSingle * primitive = poly2.triangle;
360 Mesh mesh = poly2.object.mesh;
361 Matrix * matrix = &poly2.object.matrix;
363 double a = plane.a, b = plane.b, c = plane.c, d = plane.d;
369 d = - (a * middle.x + b * middle.y + c * middle.z);
372 for(v = 0; v < primitive->nIndices; v++)
375 Vector3Df * local = &mesh.vertices[primitive->indices[v]];
378 vertex.MultMatrix(local, matrix);
380 surface = a * vertex.x + b * vertex.y + c * vertex.z + d;
381 if(surface > -EPSILON)
394 bool ShouldBeSwapped(SortPrimitive poly2)
396 if (!XYOverlap(poly2)) return false;
397 if (SurfaceOutside(poly2)) return false;
398 if (SurfaceInside(poly2)) return false;
406 #define MAX_CLIP_POINTS 50
415 displaySystem.numDisplays--;
416 displaySystem.driver.DestroyDisplay(this);
418 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
423 bool Create(DisplaySystem displaySystem, void * window)
428 this.displaySystem = displaySystem;
429 this.window = window;
430 displaySystem.numDisplays++;
431 if(displaySystem.driver.CreateDisplay(this))
433 // if(!result) LogErrorCode(DisplayInitFailed, displaySystem.driver.name);
438 Surface GetSurface(int x, int y, Box clip)
440 Surface result = null;
444 Box box { -x, -y, -x + width - 1, -y + height - 1 };
447 surface.width = width - x;
448 surface.height = height - y;
449 surface.driver = displaySystem.driver;
450 surface.displaySystem = displaySystem;
451 surface.display = this;
453 if(displaySystem.driver.GetSurface(this, surface, x, y, box))
461 bool Resize(int width, int height)
463 return displaySystem.driver.DisplaySize(this, width, height);
466 void Position(int x, int y)
468 displaySystem.driver.DisplayPosition(this, x,y);
471 void StartUpdate(void)
473 displaySystem.driver.StartUpdate(this);
476 void Scroll(Box scroll, int x, int y, Extent dirty)
478 displaySystem.driver.Scroll(this, scroll, x, y, dirty);
481 void Update(Box updateBox)
483 displaySystem.driver.Update(this, updateBox);
488 displaySystem.driver.EndUpdate(this);
493 displaySystem.driver.NextPage(this);
496 bool Grab(Bitmap bitmap, int x, int y, int w, int h)
499 if(bitmap && w > 0 && h > 0 &&
500 displaySystem.driver.GrabScreen(this, bitmap, x, y, w, h))
507 void FontExtent(Font font, const char * text, int len, int * width, int * height)
509 // Fix for OnLoadGraphics time alpha blended window text extent on GDI
510 #if defined(__WIN32__) && !defined(ECERE_NOTRUETYPE)
511 if(this && alphaBlend && pixelFormat == pixelFormat888 &&
512 displaySystem.driver == class(GDIDisplayDriver))
514 Surface s = GetSurface(0,0,null);
518 s.TextExtent(text, len, width, height);
524 // TODO: Should really pass display here...
525 DisplaySystem::FontExtent(this ? displaySystem : null, font, text, len, width, height);
528 void SetPalette(ColorAlpha * palette, bool colorMatch)
530 displaySystem.driver.SetPalette(this, palette, colorMatch);
533 void RestorePalette(void)
535 displaySystem.driver.RestorePalette(this);
538 bool Lock(bool render)
543 for(c = 0; c<current; c++)
545 Logf("Locking (%d)\n", current+1);
548 // TOCHECK: Why is displaySystem null with GISDesigner?
549 result = displaySystem && displaySystem.Lock();
555 result = displaySystem.driver.Lock(this);
571 for(c = 0; c<current; c++)
573 Logf("Unlocking (%d)\n", current);
576 if(!current && displaySystem)
577 displaySystem.driver.Unlock(this);
581 displaySystem.Unlock();
584 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
585 // *** 3D GRAPHICS ***
586 void SetCamera(Surface surface, Camera camera)
590 display3D = Display3D { };
592 if(!display3D.selection)
597 if(!display3D.selection)
598 displaySystem.driver.SelectMesh(this, null);
600 display3D.material = null;
601 display3D.mesh = null;
603 if(!display3D.selection)
605 displaySystem.driver.SetCamera(this, surface, camera);
608 this.display3D.camera = camera;
613 camera.Setup(width, height, null);
615 // Always calling Update() here had broken interpolation in OrbitWithMouse!
619 if(display3D.selection)
621 // Compute Picking Planes
623 Vector3D point { 0,0,0 };
625 Angle fovLeft, fovRight, fovTop, fovBottom;
628 double l = camera.origin.x - (display3D.pickX - display3D.pickWidth/2.0f);
629 double r = camera.origin.x - (display3D.pickX + display3D.pickWidth/2.0f);
630 double t = (display3D.pickY - display3D.pickHeight/2.0f) - camera.origin.y;
631 double b = (display3D.pickY + display3D.pickHeight/2.0f) - camera.origin.y;
633 fovLeft = atan(l / camera.focalX);
634 fovRight = atan(r / camera.focalX);
635 fovTop = atan(t / camera.focalY);
636 fovBottom = atan(b / camera.focalY);
639 quat.Yaw(fovLeft - Pi/2);
640 quat.ToDirection(normal);
641 display3D.viewPickingPlanes[left].FromPointNormal(normal, point);
644 quat.Yaw(fovRight + Pi/2);
645 quat.ToDirection(normal);
646 display3D.viewPickingPlanes[right].FromPointNormal(normal, point);
649 quat.Pitch(fovTop + Pi/2);
650 quat.ToDirection(normal);
651 display3D.viewPickingPlanes[top].FromPointNormal(normal, point);
654 quat.Pitch(fovBottom - Pi/2);
655 quat.ToDirection(normal);
656 display3D.viewPickingPlanes[bottom].FromPointNormal(normal, point);
659 normal.x = 0; normal.y = 0; normal.z = 1;
660 point.z = camera.zMin;
661 display3D.viewPickingPlanes[near].FromPointNormal(normal, point);
664 normal.x = 0; normal.y = 0; normal.z = -1;
665 point.z = camera.zMax;
666 display3D.viewPickingPlanes[far].FromPointNormal(normal, point);
668 for(c = 0; c<ClippingPlane::enumSize; c++)
669 display3D.worldPickingPlanes[c].MultMatrix(display3D.viewPickingPlanes[c], camera.inverseTranspose);
671 // Compute picking ray
674 display3D.rayView.p0 = { 0, 0, 0 };
675 p.x = display3D.pickX;
676 p.y = display3D.pickY;
678 camera.Unproject(p, display3D.rayView.delta);
680 // Convert ray to world space
681 camera.Untransform(display3D.rayView.p0, display3D.rayWorld.p0);
682 camera.Untransform(display3D.rayView.delta, p);
683 display3D.rayWorld.delta.Subtract(p, display3D.rayWorld.p0);
690 void SetLight(int id, Light light)
692 displaySystem.driver.SetLight(this, id, light);
695 void SetLights(Object object)
698 display3D._SetLights(this, object, 0);
701 // --- Transformations ---
703 void SetTransform(Matrix matrix, bool viewSpace)
705 if(display3D.selection)
709 transpose.Transpose(matrix);
713 for(c = 0; c<ClippingPlane::enumSize; c++)
714 display3D.localPickingPlanes[c].MultMatrix(display3D.viewPickingPlanes[c], transpose);
718 for(c = 0; c<ClippingPlane::enumSize; c++)
719 display3D.localPickingPlanes[c].MultMatrix(display3D.worldPickingPlanes[c], transpose);
723 if(display3D.intersecting)
727 p2.Add(display3D.rayView.p0, display3D.rayView.delta);
729 p2.Add(display3D.rayWorld.p0, display3D.rayWorld.delta);
731 display3D.rayLocal.p0.DivideMatrix(display3D.rayWorld.p0, matrix);
732 tp2.DivideMatrix(p2, matrix);
733 display3D.rayLocal.delta.Subtract(tp2, display3D.rayLocal.p0);
737 displaySystem.driver.SetTransform(this, matrix, viewSpace, viewSpace ? false : true);
740 void PushMatrix(void)
742 displaySystem.driver.PushMatrix(this);
747 displaySystem.driver.PopMatrix(this, true);
751 void ApplyMaterial(Material material, Mesh mesh)
753 if(material != display3D.material)
755 display3D.material = material;
756 displaySystem.driver.ApplyMaterial(this, material, mesh);
760 void DrawPrimitives(PrimitiveSingle primitive, Mesh mesh)
762 displaySystem.driver.DrawPrimitives(this, primitive, mesh);
765 void SelectMesh(Mesh mesh)
767 displaySystem.driver.SelectMesh(this, mesh);
768 display3D.mesh = mesh;
771 bool DrawMesh(Object object)
774 if(display3D.selection)
775 result = display3D.PickMesh(object, null);
778 Mesh mesh = object.mesh;
779 Material objectMaterial = object.material;
781 if(mesh.groups.first)
783 PrimitiveGroup group;
784 displaySystem.driver.SelectMesh(this, mesh);
785 display3D.mesh = mesh;
787 for(group = mesh.groups.first; group; group = group.next)
789 Material material = group.material ? group.material : objectMaterial;
790 if(!material) material = defaultMaterial;
792 if(material != display3D.material)
794 display3D.material = material;
795 displaySystem.driver.ApplyMaterial(this, material, mesh);
798 // *** Render Vertex Arrays ***
799 displaySystem.driver.DrawPrimitives(this, (PrimitiveSingle *)&group.type, mesh);
803 if(object.flags.translucent)
806 Matrix inverse, inverseTranspose;
809 if(object.flags.viewSpace)
810 matrix = object.matrix;
813 Camera camera = display3D.camera;
814 Matrix temp = object.matrix;
815 temp.m[3][0] -= camera.cPosition.x;
816 temp.m[3][1] -= camera.cPosition.y;
817 temp.m[3][2] -= camera.cPosition.z;
818 matrix.Multiply(temp, camera.viewMatrix);
821 inverse.Inverse(matrix);
822 inverseTranspose.Transpose(inverse);
824 for(c = 0; c < mesh.nPrimitives; c++)
826 PrimitiveSingle * triangle = &mesh.primitives[c];
827 SortPrimitive * sort;
828 Plane * plane = &triangle->plane;
829 if(display3D.nTriangles >= display3D.maxTriangles)
831 display3D.maxTriangles = display3D.maxTriangles ? (display3D.maxTriangles * 3 / 2) : 32768;
832 display3D.triangles = renew display3D.triangles SortPrimitive[display3D.maxTriangles];
834 sort = &display3D.triangles[display3D.nTriangles++];
835 sort->object = object;
836 sort->triangle = triangle;
837 sort->middle.MultMatrix(triangle->middle, matrix);
838 sort->middle.z *= -1;
839 // sort->plane.MultMatrix(triangle->plane, inverseTranspose);
840 sort->plane.d = plane->a * inverseTranspose.m[0][3] +
841 plane->b * inverseTranspose.m[1][3] +
842 plane->c * inverseTranspose.m[2][3] +
843 plane->d * inverseTranspose.m[3][3];
849 displaySystem.driver.SelectMesh(this, mesh);
850 display3D.mesh = mesh;
852 for(c = 0; c<mesh.nPrimitives; c++)
854 PrimitiveSingle * primitive = &mesh.primitives[c];
856 Material material = primitive->material ? primitive->material : objectMaterial;
857 if(!material) material = defaultMaterial;
859 if(material != display3D.material)
861 display3D.material = material;
862 displaySystem.driver.ApplyMaterial(this, material, mesh);
865 displaySystem.driver.DrawPrimitives(this, primitive, display3D.mesh);
873 bool IsObjectVisible(Object object)
876 if(display3D.selection || !display3D.camera)
877 planes = object.flags.viewSpace ? display3D.viewPickingPlanes : display3D.worldPickingPlanes;
879 planes = object.flags.viewSpace ? display3D.camera.viewClippingPlanes : display3D.camera.worldClippingPlanes;
880 return object.InsideFrustum(planes) != outside;
883 bool DrawObject(Object object)
886 if(object && object.volume)
889 FrustumPlacement visible;
891 Camera camera = display3D.camera;
893 if(display3D.selection || !camera)
894 planes = object.flags.viewSpace ? display3D.viewPickingPlanes : display3D.worldPickingPlanes;
896 planes = object.flags.viewSpace ? camera.viewClippingPlanes : camera.worldClippingPlanes;
898 visible = object.InsideFrustum(planes);
900 if(visible || display3D.pickingPlanes)
902 if(display3D.collectingHits && object.tag)
904 /*if(object.flags.root)
905 this.tags[display3D.tagIndex] = object.tag;
907 this.tags[++display3D.tagIndex] = object.tag;
909 display3D.tags[display3D.tagIndex++] = object.tag;
912 if(object.flags.mesh && object.mesh)
914 if(!display3D.selection && displaySystem.driver.PushMatrix)
915 displaySystem.driver.PushMatrix(this);
917 SetTransform(object.matrix, object.flags.viewSpace);
918 if(display3D.selection)
920 if(visible == intersecting || display3D.intersecting)
922 Vector3D rayIntersect;
923 if(display3D.PickMesh(object, rayIntersect))
925 if(display3D.intersecting)
927 Vector3D wresult, vresult;
928 wresult.MultMatrix(rayIntersect, object.matrix);
929 if(!object.flags.viewSpace)
930 camera.TransformPoint(vresult, wresult);
934 if(vresult.z < display3D.rayIntersect.z)
935 display3D.rayIntersect = vresult;
936 display3D.intersected = true;
946 result |= DrawMesh(object);
947 if(displaySystem.driver.PopMatrix)
948 displaySystem.driver.PopMatrix(this, true);
950 if(display3D.collectingHits && result /*&& object.tag*/)
953 HitRecord hit = (HitRecord)new0 byte[sizeof(class HitRecord) + sizeof(void *) * (display3D.tagIndex/*+1*/)];
954 display3D.hitList.Add(hit);
955 hit.pos = display3D.hitList.count-1;
956 hit.numTags = display3D.tagIndex /*+ 1*/;
957 for(c = 0; c</*=*/display3D.tagIndex; c++)
959 hit.tags[c] = display3D.tags[c];
962 if(!object.flags.viewSpace)
963 camera.TransformPoint(hit.center, object.wcenter);
965 hit.center = object.wcenter;
969 for(child = object.children.first; child; child = child.next)
970 result |= DrawObject(child);
972 if(display3D.collectingHits && /*!object.flags.root && */object.tag)
973 display3D.tagIndex--;
979 void DrawTranslucency(void)
983 // *** Render translucent primitives ***
984 if(display3D.nTriangles)
986 Matrix * matrix = null;
991 display3D.SortTriangles();
995 displaySystem.driver.PushMatrix(this);
996 for(c=0; c<display3D.nTriangles; c++)
998 SortPrimitive * sort = &display3D.triangles[c];
999 Mesh mesh = sort->object.mesh;
1000 PrimitiveSingle * primitive = sort->triangle;
1003 if(&sort->object.matrix != matrix)
1005 matrix = &sort->object.matrix;
1007 displaySystem.driver.PopMatrix(this, false);
1008 displaySystem.driver.PushMatrix(this);
1009 SetTransform(matrix, sort->object.flags.viewSpace);
1011 if(mesh != display3D.mesh)
1013 displaySystem.driver.SelectMesh(this, mesh);
1014 display3D.mesh = mesh;
1017 material = primitive->material ? primitive->material : sort->object.material;
1018 if(!material) material = defaultMaterial;
1020 if(material != display3D.material)
1022 displaySystem.driver.ApplyMaterial(this, material, display3D.mesh);
1023 display3D.material = material;
1028 Material testMaterial { };
1031 amount = (display3D.triangles[0].middle.z - display3D.triangles[c].middle.z) /
1032 (display3D.triangles[0].middle.z - display3D.triangles[display3D.nTriangles-1].middle.z);
1034 testMaterial.flags.doubleSided = { doubleSided = true, translucent = true };
1035 testMaterial.diffuse.a = 1;
1036 testMaterial.emissive.r = testMaterial.emissive.g = testMaterial.emissive.b = amount;
1037 testMaterial.baseMap = material->baseMap;
1039 displaySystem.driver.ApplyMaterial(this, testMaterial, display3D.mesh);
1043 // *** Render primitive ***
1044 // if(sort->plane.d > 0)
1045 displaySystem.driver.DrawPrimitives(this, primitive, display3D.mesh);
1047 displaySystem.driver.PopMatrix(this, true);
1049 display3D.nTriangles = 0;
1056 void StartSelection(int pickX, int pickY, int pickW, int pickH)
1060 display3D = Display3D { };
1062 display3D.pickX = (float)pickX;
1063 display3D.pickY = (float)pickY;
1064 display3D.pickWidth = (float)pickW;
1065 display3D.pickHeight = (float)pickH;
1066 display3D.selection = true;
1069 void CollectHits(void)
1071 display3D.collectingHits = true;
1074 int GetHits(OldList list)
1076 display3D.collectingHits = false;
1077 display3D.hitList.Sort(HitRecord::Compare, null);
1078 list = display3D.hitList;
1079 display3D.hitList.Clear();
1083 void IntersectPolygons(void)
1085 display3D.rayIntersect = { MAXFLOAT, MAXFLOAT, MAXFLOAT };
1086 display3D.intersected = false;
1087 display3D.intersecting = true;
1090 bool GetIntersect(Vector3D intersect)
1092 intersect = display3D.rayIntersect;
1093 display3D.intersecting = false;
1094 return display3D.intersected;
1097 void StopSelection(void)
1099 display3D.selection = false;
1102 // --- Rendering States ---
1103 property FillModeValue fillMode { set { displaySystem.driver.SetRenderState(this, fillMode, value); } };
1104 property bool depthTest { set { displaySystem.driver.SetRenderState(this, depthTest, value); } };
1105 property bool depthWrite { set { displaySystem.driver.SetRenderState(this, depthWrite, value); } };
1106 property float fogDensity { set { displaySystem.driver.SetRenderState(this, fogDensity, RenderStateFloat { value }.ui); } };
1107 property Color fogColor { set { displaySystem.driver.SetRenderState(this, fogColor, value); } };
1108 property bool blend { set { displaySystem.driver.SetRenderState(this, blend, value); } };
1109 property Color ambient { set { displaySystem.driver.SetRenderState(this, ambient, value); } };
1110 property bool alphaWrite { set { displaySystem.driver.SetRenderState(this, alphaWrite, value); } };
1111 property bool antiAlias { set { displaySystem.driver.SetRenderState(this, antiAlias, value); } };
1112 property bool vSync { set { displaySystem.driver.SetRenderState(this, vSync, value); } };
1114 property bool pickingPlanes { set { display3D.pickingPlanes = value; } };
1116 property DisplayFlags flags { get { return displaySystem.flags; } }
1117 property PixelFormat pixelFormat { get { return /*alphaBlend ? pixelFormat888 : */displaySystem.pixelFormat; } }
1118 property bool alphaBlend { set { alphaBlend = value; } get { return alphaBlend; } };
1119 property bool useSharedMemory { set { useSharedMemory = value; } get { return useSharedMemory; } };
1120 property void * systemWindow { get { return window; } };
1121 property DisplaySystem displaySystem { get { return displaySystem; } };
1128 DisplaySystem displaySystem;
1134 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
1135 Display3D display3D;
1138 void * windowDriverData;
1139 bool useSharedMemory;
1142 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
1143 private class Display3D
1147 SortPrimitive * triangles;
1149 Vector3D points[MAX_CLIP_POINTS];
1150 Vector3D newPoints[MAX_CLIP_POINTS];
1151 byte goodPoints[MAX_CLIP_POINTS];
1156 Plane viewPickingPlanes[ClippingPlane], worldPickingPlanes[ClippingPlane];
1157 Plane localPickingPlanes[ClippingPlane];
1159 bool collectingHits, selection, intersecting, intersected, pickingPlanes;
1160 float pickX, pickY, pickWidth, pickHeight;
1165 Line rayView, rayWorld, rayLocal;
1166 Vector3D rayIntersect;
1173 int _SetLights(Display display, Object object, int id)
1175 if(id < NumberOfLights)
1179 if(object.flags.light && !object.light.flags.off)
1180 display.SetLight(id++, object.light);
1182 for(child = object.children.first; child; child = child.next)
1184 id = _SetLights(display, child, id);
1190 //#define TRESHOLD -1
1191 //#define TRESHOLD -0.25
1192 #define TRESHOLD -0.0025
1194 bool PickPrimitives(Mesh mesh, PrimitiveSingle primitive, Vector3D rayDiff, Vector3D rayIntersect)
1196 Plane * planes = localPickingPlanes;
1198 int nIndex = 1, nPoints = 1;
1200 bool result = false;
1201 Vector3D * points = this.points;
1202 Vector3D * newPoints = this.newPoints;
1203 byte * goodPoints = this.goodPoints;
1204 int nVertices = primitive.type.vertexRange ? primitive.nVertices : primitive.nIndices;
1207 bool i32bit = primitive.type.indices32bit;
1208 uint32 * indices32 = primitive.indices32;
1209 uint16 * indices16 = primitive.indices;
1211 switch(primitive.type.primitiveType)
1213 case triangles: nIndex = 3; nPoints = 3; break;
1214 case quads: nIndex = 4; nPoints = 4; break;
1217 nIndex = 1; nPoints = 3;
1219 tmp = primitive.type.vertexRange ? mesh.vertices[primitive.first] : mesh.vertices[(i32bit ? indices32[0] : indices16[0])];
1220 points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1221 tmp = primitive.type.vertexRange ? mesh.vertices[primitive.first+1] : mesh.vertices[(i32bit ? indices32[1] : indices16[1])];
1222 points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1226 for(c = offset; c<nVertices; c += nIndex)
1228 bool outside = false;
1235 if(primitive.type.vertexRange)
1237 if(primitive.type.primitiveType == triStrip)
1239 tmp = mesh.vertices[primitive.first + (c & 1) ? (c - 1) : (c - 2)];
1240 points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1241 tmp = mesh.vertices[primitive.first + (c & 1) ? (c - 2) : (c - 1)];
1242 points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1244 else if(primitive.type.primitiveType == triFan)
1246 tmp = mesh.vertices[primitive.first + 0];
1247 points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1248 tmp = mesh.vertices[primitive.first + c - 1];
1249 points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1251 for(i = 0; i<nIndex; i++)
1253 tmp = mesh.vertices[primitive.first + c+i];
1254 points[i + offset] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1259 if(primitive.type.primitiveType == triStrip)
1261 i = (c & 1) ? (c - 1) : (c - 2);
1262 tmp = mesh.vertices[(i32bit ? indices32[i] : indices16[i])];
1263 points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1265 i = (c & 1) ? (c - 2) : (c - 1);
1266 tmp = mesh.vertices[(i32bit ? indices32[i] : indices16[i])];
1267 points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1269 else if(primitive.type.primitiveType == triFan)
1271 tmp = mesh.vertices[(i32bit ? indices32[0] : indices16[0])];
1272 points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1273 tmp = mesh.vertices[(i32bit ? indices32[c-1] : indices16[c-1])];
1274 points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1276 for(i = 0; i<nIndex; i++)
1278 tmp = mesh.vertices[(i32bit ? indices32[c+i] : indices16[c+i])];
1279 points[i + offset] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1283 for(p = 0; p < 6; p++)
1285 Plane * plane = &planes[p];
1287 int numGoodPoints = 0;
1289 memset(goodPoints, 0, n);
1290 for(i = 0; i < n; i++)
1292 double dot = plane->normal.DotProduct(points[i]);
1293 double distance = dot + plane->d;
1294 if(distance > TRESHOLD)
1305 if(numGoodPoints < n)
1316 newPoints[newN++] = points[j];
1325 for(lastGood = n-1; !goodPoints[lastGood]; lastGood--);
1327 edge.p0 = points[lastGood];
1328 edge.delta.Subtract(points[j], edge.p0);
1329 plane->IntersectLine(edge, newPoints[newN++]);
1331 for(next = j+1; next != j; next++)
1333 if(next == n) next = 0;
1334 if(goodPoints[next])
1336 int prev = next - 1;
1337 if(prev < 0) prev = n-1;
1339 edge.p0 = points[prev];
1340 edge.delta.Subtract(points[next], edge.p0);
1341 plane->IntersectLine(edge, newPoints[newN++]);
1351 // Use the new points
1352 memcpy(points, newPoints, newN * sizeof(Vector3D));
1361 // TODO: Implement intersection with TriStrip, TriFan...
1364 // Intersect primitives
1366 Vector3D intersect, diff;
1367 int i0 = c, i1 = c+1, i2 = c+2;
1369 if(primitive.type.primitiveType == triStrip)
1371 i0 = (c & 1) ? (c - 1) : (c - 2);
1372 i1 = (c & 1) ? (c - 2) : (c - 1);
1375 else if(primitive.type.primitiveType == triFan)
1382 if(primitive.type.vertexRange)
1384 mesh.vertices[primitive.first + i0],
1385 mesh.vertices[primitive.first + i1],
1386 mesh.vertices[primitive.first + i2]);
1389 mesh.vertices[(i32bit ? indices32[i0] : indices16[i0])],
1390 mesh.vertices[(i32bit ? indices32[i1] : indices16[i1])],
1391 mesh.vertices[(i32bit ? indices32[i2] : indices16[i2])]);
1393 plane.IntersectLine(rayLocal, intersect);
1394 diff.Subtract(intersect, rayLocal.p0);
1395 diff.x /= rayLocal.delta.x;
1396 diff.y /= rayLocal.delta.y;
1397 diff.z /= rayLocal.delta.z;
1398 if(diff.x < rayDiff.x || diff.y < rayDiff.y || diff.z < rayDiff.z)
1401 rayIntersect = intersect;
1408 switch(primitive.type)
1411 points[strip] = points[2];
1415 points[1] = points[2];
1422 bool PickMesh(Object object, Vector3D rayIntersect)
1424 Mesh mesh = object.mesh;
1425 bool result = false;
1426 Vector3D rayDiff { MAXFLOAT, MAXFLOAT, MAXFLOAT };
1427 if(rayIntersect != null)
1428 rayIntersect = { MAXFLOAT, MAXFLOAT, MAXFLOAT };
1430 if(mesh.groups.first)
1432 PrimitiveGroup group;
1434 for(group = mesh.groups.first; group; group = group.next)
1436 if(PickPrimitives(mesh, (PrimitiveSingle *)&group.type, rayDiff, rayIntersect))
1447 for(c = 0; c < mesh.nPrimitives; c++)
1449 if(PickPrimitives(mesh, mesh.primitives[c], rayDiff, rayIntersect))
1460 void SortTriangles(void)
1463 Object object = null;
1465 for(c=0; c<nTriangles; c++)
1467 SortPrimitive * sort = &triangles[c];
1468 Mesh mesh = sort->object.mesh;
1469 PrimitiveSingle * primitive = sort->triangle;
1470 Vector3Df min { MAXFLOAT, MAXFLOAT, MAXFLOAT };
1471 Vector3Df max { -MAXFLOAT, -MAXFLOAT, -MAXFLOAT };
1473 bool ix32 = primitive->type.indices32bit;
1474 if(object != sort->object)
1476 object = sort->object;
1477 if(object.flags.viewSpace)
1478 matrix = object.matrix;
1481 Camera camera = this.camera;
1482 Matrix temp = object.matrix;
1483 temp.m[3][0] -= camera.cPosition.x;
1484 temp.m[3][1] -= camera.cPosition.y;
1485 temp.m[3][2] -= camera.cPosition.z;
1486 matrix.Multiply(temp, camera.viewMatrix);
1490 for(v = 0; v<primitive->nIndices; v++)
1492 Vector3Df * local = &mesh.vertices[ix32 ? primitive->indices32[v] : primitive->indices[v]];
1495 vertex.MultMatrix(local, &matrix);
1497 if(vertex.x > max.x) max.x = vertex.x;
1498 if(vertex.y > max.y) max.y = vertex.y;
1499 if(vertex.z > max.z) max.z = vertex.z;
1500 if(vertex.x < min.x) min.x = vertex.x;
1501 if(vertex.y < min.y) min.y = vertex.y;
1502 if(vertex.z < min.z) min.z = vertex.z;
1508 sort->marked = false;
1512 Logf("========= Before Sort ==========\n");
1513 for(c=0; c<nTriangles; c++)
1515 SortPrimitive * sort = &triangles[c];
1517 Mesh mesh = sort->mesh;
1518 PrimitiveSingle * primitive = sort->triangle;
1520 Logf("Triangle %d (%s):\n", c, primitive->material->name);
1522 for(v = 0; v<primitive->nIndices; v++)
1524 Vector3Df * local = &mesh.vertices[primitive->indices[v]];
1528 vertex.<MultMatrix(local, sort->matrix);
1530 Logf("Vertex %d:", v);
1532 // Logf(" Local %f, %f, %f:\n", local->x, local->y, local->z);
1533 Logf(" View %f, %f, %f:\n", vertex.x, vertex.y, vertex.z);
1537 Logf("Min %f, %f, %f:\n", sort->min.x, sort->min.y, sort->min.z);
1538 Logf("Max %f, %f, %f:\n", sort->max.x, sort->max.y, sort->max.z);
1542 // *** Sort translucent primitives ***
1543 qsort((void*) triangles, nTriangles, sizeof(SortPrimitive), SortPrimitive::Compare);
1545 Logf("\n\n========= After Sort ==========\n");
1546 for(c=0; c<nTriangles; c++)
1548 SortPrimitive * sort = &triangles[c];
1550 Mesh mesh = sort->mesh;
1551 PrimitiveSingle * primitive = sort->triangle;
1553 Logf("Triangle %d (%s):\n", c, primitive->material->name);
1555 for(v = 0; v<primitive->nIndices; v++)
1557 Vector3Df * local = &mesh.vertices[primitive->indices[v]];
1561 vertex.MultMatrix(local, sort->matrix);
1563 Logf("Vertex %d:", v);
1565 // Logf(" Local %f, %f, %f:\n", local->x, local->y, local->z);
1566 Logf(" View %f, %f, %f:\n", vertex.x, vertex.y, vertex.z);
1570 Logf("Min %f, %f, %f:\n", sort->min.x, sort->min.y, sort->min.z);
1571 Logf("Max %f, %f, %f:\n", sort->max.x, sort->max.y, sort->max.z);
1578 If all five tests fail for a particular Q,
1579 then P might obscure Q. Now Q must be tested.
1580 First, the algorithm checks if Q has been "marked."
1581 If Q is marked, then Q was "moved around" in the list
1582 during a previous iteration of the loop. The algorithm
1583 only allows a polygon to be moved once, to avoid the possibility
1584 of infinite loops. If Q is not marked, it is tested to see
1585 if it might obscure P. If Q cannot obscure P, then Q is possibly
1586 behind P and so it is good candidate to be drawn next.
1587 Therefore, the algorithm "abandons" the current P (that is, it
1588 stops testing Q's against the current P) and moves the current
1589 Q to the end of the list to become the next P.
1594 for(p = 0; p<nTriangles; p++)
1596 SortPrimitive * poly1 = &triangles[p];
1599 for(q = p+1; q<nTriangles; q++)
1603 SortPrimitive * poly2 = &triangles[q];
1604 if(poly1->ZOverlap(poly2) && !poly2->marked)
1606 if(poly1->ShouldBeSwapped(poly2))
1608 if(!poly2->ShouldBeSwapped(poly1))
1610 SortPrimitive temp = *poly2;
1611 memmove(triangles+1, triangles, sizeof(SortPrimitive)*q);
1612 triangles[0] = temp;
1613 triangles[0].marked = true;
1626 for(p = 0; p<nTriangles; p++)
1628 SortPrimitive * poly1 = &triangles[p];
1631 // for(q = p+1; q<nTriangles; q++)
1632 for(q = 0; q<nTriangles; q++)
1636 SortPrimitive * poly2 = &triangles[q];
1637 if(poly1->ZOverlap(poly2) && !poly2->marked)
1639 if(poly1->ShouldBeSwapped(poly2))
1641 if(!poly2->ShouldBeSwapped(poly1))
1643 SortPrimitive temp = *poly2;
1644 memmove(triangles+1, triangles, sizeof(SortPrimitive)*q);
1645 triangles[0] = temp;
1646 triangles[0].marked = true;
1659 for(p = nTriangles-1; p>=0; p--)
1661 SortPrimitive * poly1 = &triangles[p];
1664 for(q = nTriangles-1; q>=0; q--)
1668 SortPrimitive * poly2 = &triangles[q];
1669 if(poly1->ZOverlap(poly2) && !poly2->marked)
1671 if(poly1->ShouldBeSwapped(poly2))
1673 if(!poly2->ShouldBeSwapped(poly1))
1675 SortPrimitive temp = *poly2;
1676 memmove(triangles + q, triangles + q + 1, sizeof(SortPrimitive)*q);
1678 triangles[nTriangles-1] = temp;
1691 for(c=0; c<nTriangles; c++)
1694 SortPrimitive * poly1 = &triangles[c];
1696 // for(b=0; b<nTriangles; b++)
1697 //for(b=c+1; b<nTriangles; b++)
1699 if(b<this.nTriangles)
1701 SortPrimitive * poly2 = &this.triangles[b];
1703 if(poly1->ZOverlap(poly2) && poly1->ShouldBeSwapped(poly2))
1705 SortPrimitive temp = *poly1;
1718 bool IsDriverTextMode(const char * driverName)
1720 subclass(DisplayDriver) driver = GetDisplayDriver(driverName);
1721 return driver ? driver.textMode : false;
1724 bool IsDriverPrinter(const char * driverName)
1726 subclass(DisplayDriver) driver = GetDisplayDriver(driverName);
1727 return driver ? driver.printer : false;
1730 static ColorAlpha defaultPalette[256] =
1734 0xFF000000,0xFF000080,0xFF008000,0xFF008080,0xFF800000,0xFF800080,0xFF808000,0xFFC0C0C0,
1735 0xFF808080,0xFF0000FF,0xFF00FF00,0xFF00FFFF,0xFFFF0000,0xFFFF00FF,0xFFFFFF00,0xFFFFFFFF,
1737 0xFF000000,0xFF0000AA,0xFF00AA00,0xFF00AAAA,0xFFAA0000,0xFFAA00AA,0xFFAAAA00,0xFFABABAB,
1738 0xFF555555,0xFF5555FF,0xFF55FF55,0xFF55FFFF,0xFFFF5555,0xFFFF55FF,0xFFFFFF55,0xFFFFFFFF,
1740 // 6 x 6 x 6 Color Cube
1741 0xFF000000, 0xFF000033, 0xFF000066, 0xFF000099, 0xFF0000CC, 0xFF0000FF,
1742 0xFF003300, 0xFF003333, 0xFF003366, 0xFF003399, 0xFF0033CC, 0xFF0033FF,
1743 0xFF006600, 0xFF006633, 0xFF006666, 0xFF006699, 0xFF0066CC, 0xFF0066FF,
1744 0xFF009900, 0xFF009933, 0xFF009966, 0xFF009999, 0xFF0099CC, 0xFF0099FF,
1745 0xFF00CC00, 0xFF00CC33, 0xFF00CC66, 0xFF00CC99, 0xFF00CCCC, 0xFF00CCFF,
1746 0xFF00FF00, 0xFF00FF33, 0xFF00FF66, 0xFF00FF99, 0xFF00FFCC, 0xFF00FFFF,
1748 0xFF330000, 0xFF330033, 0xFF330066, 0xFF330099, 0xFF3300CC, 0xFF3300FF,
1749 0xFF333300, 0xFF333333, 0xFF333366, 0xFF333399, 0xFF3333CC, 0xFF3333FF,
1750 0xFF336600, 0xFF336633, 0xFF336666, 0xFF336699, 0xFF3366CC, 0xFF3366FF,
1751 0xFF339900, 0xFF339933, 0xFF339966, 0xFF339999, 0xFF3399CC, 0xFF3399FF,
1752 0xFF33CC00, 0xFF33CC33, 0xFF33CC66, 0xFF33CC99, 0xFF33CCCC, 0xFF33CCFF,
1753 0xFF33FF00, 0xFF33FF33, 0xFF33FF66, 0xFF33FF99, 0xFF33FFCC, 0xFF33FFFF,
1755 0xFF660000, 0xFF660033, 0xFF660066, 0xFF660099, 0xFF6600CC, 0xFF6600FF,
1756 0xFF663300, 0xFF663333, 0xFF663366, 0xFF663399, 0xFF6633CC, 0xFF6633FF,
1757 0xFF666600, 0xFF666633, 0xFF666666, 0xFF666699, 0xFF6666CC, 0xFF6666FF,
1758 0xFF669900, 0xFF669933, 0xFF669966, 0xFF669999, 0xFF6699CC, 0xFF6699FF,
1759 0xFF66CC00, 0xFF66CC33, 0xFF66CC66, 0xFF66CC99, 0xFF66CCCC, 0xFF66CCFF,
1760 0xFF66FF00, 0xFF66FF33, 0xFF66FF66, 0xFF66FF99, 0xFF66FFCC, 0xFF66FFFF,
1762 0xFF990000, 0xFF990033, 0xFF990066, 0xFF990099, 0xFF9900CC, 0xFF9900FF,
1763 0xFF993300, 0xFF993333, 0xFF993366, 0xFF993399, 0xFF9933CC, 0xFF9933FF,
1764 0xFF996600, 0xFF996633, 0xFF996666, 0xFF996699, 0xFF9966CC, 0xFF9966FF,
1765 0xFF999900, 0xFF999933, 0xFF999966, 0xFF999999, 0xFF9999CC, 0xFF9999FF,
1766 0xFF99CC00, 0xFF99CC33, 0xFF99CC66, 0xFF99CC99, 0xFF99CCCC, 0xFF99CCFF,
1767 0xFF99FF00, 0xFF99FF33, 0xFF99FF66, 0xFF99FF99, 0xFF99FFCC, 0xFF99FFFF,
1769 0xFFCC0000, 0xFFCC0033, 0xFFCC0066, 0xFFCC0099, 0xFFCC00CC, 0xFFCC00FF,
1770 0xFFCC3300, 0xFFCC3333, 0xFFCC3366, 0xFFCC3399, 0xFFCC33CC, 0xFFCC33FF,
1771 0xFFCC6600, 0xFFCC6633, 0xFFCC6666, 0xFFCC6699, 0xFFCC66CC, 0xFFCC66FF,
1772 0xFFCC9900, 0xFFCC9933, 0xFFCC9966, 0xFFCC9999, 0xFFCC99CC, 0xFFCC99FF,
1773 0xFFCCCC00, 0xFFCCCC33, 0xFFCCCC66, 0xFFCCCC99, 0xFFCCCCCC, 0xFFCCCCFF,
1774 0xFFCCFF00, 0xFFCCFF33, 0xFFCCFF66, 0xFFCCFF99, 0xFFCCFFCC, 0xFFCCFFFF,
1776 0xFFFF0000, 0xFFFF0033, 0xFFFF0066, 0xFFFF0099, 0xFFFF00CC, 0xFFFF00FF,
1777 0xFFFF3300, 0xFFFF3333, 0xFFFF3366, 0xFFFF3399, 0xFFFF33CC, 0xFFFF33FF,
1778 0xFFFF6600, 0xFFFF6633, 0xFFFF6666, 0xFFFF6699, 0xFFFF66CC, 0xFFFF66FF,
1779 0xFFFF9900, 0xFFFF9933, 0xFFFF9966, 0xFFFF9999, 0xFFFF99CC, 0xFFFF99FF,
1780 0xFFFFCC00, 0xFFFFCC33, 0xFFFFCC66, 0xFFFFCC99, 0xFFFFCCCC, 0xFFFFCCFF,
1781 0xFFFFFF00, 0xFFFFFF33, 0xFFFFFF66, 0xFFFFFF99, 0xFFFFFFCC, 0xFFFFFFFF,
1783 // 16 Shades of gray
1784 0xFF000000,0xFF101010,0xFF202020,0xFF303030,0xFF404040,0xFF505050,0xFF606060,0xFF707070,
1785 0xFF808080,0xFF909090,0xFFA0A0A0,0xFFB0B0B0,0xFFC0C0C0,0xFFD0D0D0,0xFFE0E0E0,0xFFF0F0F0,
1788 0xFF080808,0xFF101010,0xFF585858,0xFF606060,0xFFA8A8A8,0xFFB0B0B0,0xFFF8F8F8,0xFFFFFFFF
1792 0xFF080000,0xFF100000,0xFF180000,0xFF200000,0xFF280000,0xFF300000,0xFF380000,0xFF400000,
1793 0xFF480000,0xFF500000,0xFF580000,0xFF600000,0xFF680000,0xFF700000,0xFF780000,0xFF800000,
1794 0xFF880000,0xFF900000,0xFF980000,0xFFA00000,0xFFA80000,0xFFB00000,0xFFB80000,0xFFC00000,
1795 0xFFC80000,0xFFD00000,0xFFD80000,0xFFE00000,0xFFE80000,0xFFF00000,0xFFF80000,0xFFFF0000,
1797 0xFF000800,0xFF001000,0xFF001800,0xFF002000,0xFF002800,0xFF003000,0xFF003800,0xFF004000,
1798 0xFF004800,0xFF005000,0xFF005800,0xFF006000,0xFF006800,0xFF007000,0xFF007800,0xFF008000,
1799 0xFF008800,0xFF009000,0xFF009800,0xFF00A000,0xFF00A800,0xFF00B000,0xFF00B800,0xFF00C000,
1800 0xFF00C800,0xFF00D000,0xFF00D800,0xFF00E000,0xFF00E800,0xFF00F000,0xFF00F800,0xFF00FF00,
1802 0xFF000808,0xFF001010,0xFF001818,0xFF002020,0xFF002828,0xFF003030,0xFF003838,0xFF004040,
1803 0xFF004848,0xFF005050,0xFF005858,0xFF006060,0xFF006868,0xFF007070,0xFF007878,0xFF008080,
1804 0xFF008888,0xFF009090,0xFF009898,0xFF00A0A0,0xFF00A8A8,0xFF00B0B0,0xFF00B8B8,0xFF00C0C0,
1805 0xFF00C8C8,0xFF00D0D0,0xFF00D8D8,0xFF00E0E0,0xFF00E8E8,0xFF00F0F0,0xFF00F8F8,0xFF00FFFF,
1807 0xFF000008,0xFF000010,0xFF000018,0xFF000020,0xFF000028,0xFF000030,0xFF000038,0xFF000040,
1808 0xFF000048,0xFF000050,0xFF000058,0xFF000060,0xFF000068,0xFF000070,0xFF000078,0xFF000080,
1809 0xFF000088,0xFF000090,0xFF000098,0xFF0000A0,0xFF0000A8,0xFF0000B0,0xFF0000B8,0xFF0000C0,
1810 0xFF0000C8,0xFF0000D0,0xFF0000D8,0xFF0000E0,0xFF0000E8,0xFF0000F0,0xFF0000F8,0xFF0000FF,
1812 0xFF080008,0xFF100010,0xFF180018,0xFF200020,0xFF280028,0xFF300030,0xFF380038,0xFF400040,
1813 0xFF480048,0xFF500050,0xFF580058,0xFF600060,0xFF680068,0xFF700070,0xFF780078,0xFF800080,
1814 0xFF880088,0xFF900090,0xFF980098,0xFFA000A0,0xFFA800A8,0xFFB000B0,0xFFB800B8,0xFFC000C0,
1815 0xFFC800C8,0xFFD000D0,0xFFD800D8,0xFFE000E0,0xFFE800E8,0xFFF000F0,0xFFF800F8,0xFFFF00FF,
1817 0xFF080800,0xFF101000,0xFF181800,0xFF202000,0xFF282800,0xFF303000,0xFF383800,0xFF404000,
1818 0xFF484800,0xFF505000,0xFF585800,0xFF606000,0xFF686800,0xFF707000,0xFF787800,0xFF808000,
1819 0xFF888800,0xFF909000,0xFF989800,0xFFA0A000,0xFFA8A800,0xFFB0B000,0xFFB8B800,0xFFC0C000,
1820 0xFFC8C800,0xFFD0D000,0xFFD8D800,0xFFE0E000,0xFFE8E800,0xFFF0F000,0xFFF8F800,0xFFFFFF00,
1822 0xFF080808,0xFF101010,0xFF181818,0xFF202020,0xFF282828,0xFF303030,0xFF383838,0xFF404040,
1823 0xFF484848,0xFF505050,0xFF585858,0xFF606060,0xFF686868,0xFF707070,0xFF787878,0xFF808080,
1824 0xFF888888,0xFF909090,0xFF989898,0xFFA0A0A0,0xFFA8A8A8,0xFFB0B0B0,0xFFB8B8B8,0xFFC0C0C0,
1825 0xFFC8C8C8,0xFFD0D0D0,0xFFD8D8D8,0xFFE0E0E0,0xFFE8E8E8,0xFFF0F0F0,0xFFF8F8F8,0xFFFFFFFF
1829 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
1830 static Material defaultMaterial
1833 diffuse = { 1.0f, 1.0f, 1.0f },
1834 ambient = { 1.0f, 1.0f, 1.0f },
1835 flags = { doubleSided = true, noFog = true };
1839 static byte colorDepthShifts[PixelFormat] = { 0,0,1,1,1,2,0,1,2 };
1840 static Size resolutions[Resolution] =
1843 {320,200},{320,240},{320,400},{360,480},
1844 {400,256},{400,300},{512,256},{512,384},
1845 {640,200},{640,350},{640,400},{640,480},
1846 {720,348},{800,600},{856,480},{960,720},
1847 {1024,768},{1152,864},{1280,1024},{1600,1200},
1850 static int colorDepths[PixelFormat] = {4,8,12,15,16,32,8,16,32};
1852 // --- Query utilities ---
1854 public int GetResolutionWidth(Resolution resolution)
1856 return resolutions[resolution].w;
1859 public int GetResolutionHeight(Resolution resolution)
1861 return resolutions[resolution].h;
1864 public int GetDepthBits(PixelFormat colorDepth)
1866 return colorDepths[colorDepth];
1869 public byte GetColorDepthShifts(PixelFormat format)
1871 return colorDepthShifts[format];
1874 public ColorAlpha * GetDefaultPalette()
1876 return (ColorAlpha *)defaultPalette;
1878 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
1879 public Material GetDefaultMaterial()
1881 return defaultMaterial;
1884 public int BestColorMatch(ColorAlpha * palette, int start, int end, Color rgb)
1890 int bestscore = MAXINT,score;
1891 byte r = rgb.r, g = rgb.g, b = rgb.b;
1894 for(c = start; c <= end; c++)
1897 current = palette[c];
1898 if(rgb && !c) continue;
1902 score = Abs(dr) + Abs(dg) + Abs(db);
1903 if(score <= bestscore)