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 enum FillModeValue { solid, wireframe };
38 public class DisplayFlags
40 public bool fullScreen:1, flipping:1, alpha:1, memBackBuffer:1, text:1, scrolling:1, printer:1;
42 public class FontFlags
44 public bool bold:1, italic:1, underline:1;
47 __attribute__((unused)) static void DummyFunction()
52 public class DisplayDriver
55 class_data char * name;
56 class_data bool textMode;
57 class_data bool printer;
58 class_data DisplaySystem displaySystem;
60 class_property DisplaySystem displaySystem
62 set { class_data(displaySystem) = value; }
63 get { return class_data(displaySystem); }
66 class_property char * name
68 set { class_data(name) = value; }
69 get { return class_data(name); }
72 class_property bool printer
74 set { class_data(printer) = value; }
75 get { return class_data(printer); }
78 // Constructor / Destructor
79 virtual bool ::CreateDisplaySystem(DisplaySystem);
80 virtual void ::DestroyDisplaySystem(DisplaySystem);
82 virtual bool ::CreateDisplay(Display);
83 virtual void ::DestroyDisplay(Display);
85 // Display Position and Size
86 virtual bool ::DisplaySize(Display, int, int);
87 virtual void ::DisplayPosition(Display, int, int);
90 virtual void ::SetPalette(Display, ColorAlpha *, bool);
91 virtual void ::RestorePalette(Display);
93 // Display the back buffer content
94 virtual void ::StartUpdate(Display);
95 virtual void ::Scroll(Display, Box, int, int, Extent);
96 virtual void ::Update(Display, Box);
97 virtual void ::EndUpdate(Display);
99 // Allocate/free a bitmap
100 virtual bool ::AllocateBitmap(DisplaySystem, Bitmap, int, int, int, PixelFormat, bool);
101 virtual void ::FreeBitmap(DisplaySystem, Bitmap);
104 virtual bool ::LockSystem(DisplaySystem displaySystem);
105 virtual void ::UnlockSystem(DisplaySystem displaySystem);
107 virtual bool ::Lock(Display);
108 virtual void ::Unlock(Display);
110 // Get/release a surface
111 virtual bool ::GetSurface(Display, Surface surface, int,int,Box);
112 virtual bool ::GetBitmapSurface(DisplaySystem displaySystem, Surface surface, Bitmap bitmap, int,int,Box);
113 virtual void ::ReleaseSurface(Display this, Surface);
116 virtual void ::Clip(Display, Surface, Box);
118 // Grab from the screen
119 virtual bool ::GrabScreen(Display, Bitmap, int, int, unsigned int, unsigned int);
121 // Converts a bitmap format
122 virtual bool ::ConvertBitmap(DisplaySystem, Bitmap, PixelFormat, ColorAlpha *);
124 // Converts an LFB bitmap into an offscreen bitmap for this device
125 virtual bool ::MakeDDBitmap(DisplaySystem, Bitmap, bool);
128 virtual Font ::LoadFont(DisplaySystem displaySystem, char * faceName, float size, FontFlags flags);
129 virtual void ::UnloadFont(DisplaySystem, Font);
132 virtual void ::SetForeground(Display, Surface, ColorAlpha);
133 virtual void ::SetBackground(Display, Surface, ColorAlpha);
134 virtual void ::LineStipple(Display, Surface, uint);
135 virtual ColorAlpha ::GetPixel(Display, Surface, int, int);
136 virtual void ::PutPixel(Display, Surface, int, int);
137 virtual void ::DrawLine(Display, Surface, int, int, int, int);
138 virtual void ::Rectangle(Display, Surface,int,int,int,int);
139 virtual void ::Area(Display, Surface,int,int,int,int);
140 virtual void ::Clear(Display, Surface, ClearType);
141 virtual void ::Blit(Display, Surface, Bitmap, int, int, int, int, int, int);
142 virtual void ::Stretch(Display, Surface, Bitmap, int, int, int, int, int, int,int,int);
143 virtual void ::Filter(Display, Surface, Bitmap, int, int, int, int, int, int,int,int);
144 virtual void ::BlitDI(Display, Surface, Bitmap, int, int, int, int, int, int);
145 virtual void ::StretchDI(Display, Surface, Bitmap, int, int, int, int, int, int,int,int);
146 virtual void ::FilterDI(Display, Surface, Bitmap, int, int, int, int, int, int, int,int);
147 virtual void ::TextFont(Display, Surface, Font);
148 virtual void ::TextOpacity(Display, Surface, bool);
149 virtual void ::WriteText(Display, Surface, int, int, char *, int);
150 virtual void ::TextExtent(Display, Surface, char *, int, int *, int *);
151 virtual void ::FontExtent(DisplaySystem, Font, char *, int, int *, int *);
152 virtual void ::DrawingChar(Display, Surface, char);
153 virtual void ::NextPage(Display);
154 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
156 virtual void ::SetRenderState(Display, RenderState, uint);
157 virtual void ::SetLight(Display, int, Light);
158 virtual void ::SetCamera(Display, Surface, Camera);
159 virtual bool ::AllocateMesh(DisplaySystem, Mesh);
160 virtual void ::FreeMesh(DisplaySystem, Mesh);
161 virtual bool ::LockMesh(DisplaySystem, Mesh, MeshFeatures flags);
162 virtual void ::UnlockMesh(DisplaySystem, Mesh, MeshFeatures flags);
163 virtual void * ::AllocateIndices(DisplaySystem, int nIndices, bool indices32bit);
164 virtual void ::FreeIndices(DisplaySystem, void * indices);
165 virtual uint16 * ::LockIndices(DisplaySystem, void * indices);
166 virtual void ::UnlockIndices(DisplaySystem, void * indices, bool indices32bit, int nIndices);
167 virtual void ::SelectMesh(Display, Mesh);
168 virtual void ::ApplyMaterial(Display, Material, Mesh);
169 virtual void ::DrawPrimitives(Display, PrimitiveSingle *, Mesh mesh);
170 virtual void ::PushMatrix(Display);
171 virtual void ::PopMatrix(Display, bool);
172 virtual void ::SetTransform(Display, Matrix, bool, bool);
174 virtual void ::SetBlitTint(Display, Surface, ColorAlpha);
177 public enum Alignment { left, right, center };
178 public enum ClearType { colorBuffer, depthBuffer, colorAndDepth };
180 subclass(DisplayDriver) GetDisplayDriver(char * driverName)
185 for(link = class(DisplayDriver).derivatives.first; link; link = link.next)
187 subclass(DisplayDriver) displayDriver = link.data;
188 if(displayDriver && displayDriver.name && !strcmp(displayDriver.name, driverName))
189 return displayDriver;
195 DisplaySystem GetDisplaySystem(char * driverName)
197 subclass(DisplayDriver) displayDriver = GetDisplayDriver(driverName);
198 return displayDriver ? displayDriver.displaySystem : null;
201 define textCellW = 8;
202 define textCellH = 16;
204 public enum PixelFormat // : byte MESSES UP GuiApplication
206 pixelFormat4, pixelFormat8, pixelFormat444, pixelFormat555, pixelFormat565, pixelFormat888, pixelFormatAlpha, pixelFormatText, pixelFormatRGBA
208 public enum Resolution : int
210 resText80x25, res320x200, res320x240, res320x400, res360x480, res400x256, res400x300, res512x256, res512x384,
211 res640x200, res640x350, res640x400, res640x480, res720x348, res800x600, res856x480, res960x720, res1024x768,
212 res1152x864, res1280x1024, res1600x1200, res768x480
215 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
216 public class LightFlags
218 public bool off:1, spot:1, omni:1, attenuation:1;
228 Quaternion orientation;
241 define NumberOfLights = 8;
243 // Painter's algorithm
245 public class HitRecord : struct
248 HitRecord prev, next;
252 void * tags[1]; // More tags may follow
254 int Compare(HitRecord recordB, void * unused)
256 if(center.z > recordB.center.z)
258 else if(center.z < recordB.center.z)
260 else if(pos > recordB.pos)
262 else if(pos < recordB.pos)
269 #define EPSILON 0.00001
273 PrimitiveSingle * triangle;
280 int Compare(SortPrimitive primitive2)
283 if(ZOverlap(primitive2) && Sgn(plane.d) != Sgn(primitive2.plane.d))
284 value = plane.d - primitive2.plane.d;
286 value = middle.z - primitive2.middle.z;
290 else if(value<-EPSILON)
296 bool ZOverlap(SortPrimitive poly2)
298 if(min.z > poly2.max.z - EPSILON || poly2.min.z > max.z - EPSILON)
304 bool XYOverlap(SortPrimitive poly2)
306 if(min.x > poly2.max.x - EPSILON || poly2.min.x > max.x - EPSILON )
308 if(min.y > poly2.max.y - EPSILON || poly2.min.y > max.y - EPSILON )
313 bool SurfaceOutside(SortPrimitive poly2)
317 PrimitiveSingle * primitive = triangle;
318 Mesh mesh = object.mesh;
319 Matrix * matrix = &object.matrix;
321 double a = poly2.plane.a, b = poly2.plane.b, c = poly2.plane.c, d = poly2.plane.d;
327 d = - (a * poly2.middle.x + b * poly2.middle.y + c * poly2.middle.z);
330 for(v = 0; v < primitive->nIndices; v++)
333 Vector3Df * local = &mesh.vertices[primitive->indices[v]];
336 vertex.MultMatrix(local, matrix);
338 surface = a * vertex.x + b * vertex.y + c * vertex.z + d;
340 if(surface < EPSILON)
353 bool SurfaceInside(SortPrimitive poly2)
357 PrimitiveSingle * primitive = poly2.triangle;
358 Mesh mesh = poly2.object.mesh;
359 Matrix * matrix = &poly2.object.matrix;
361 double a = plane.a, b = plane.b, c = plane.c, d = plane.d;
367 d = - (a * middle.x + b * middle.y + c * middle.z);
370 for(v = 0; v < primitive->nIndices; v++)
373 Vector3Df * local = &mesh.vertices[primitive->indices[v]];
376 vertex.MultMatrix(local, matrix);
378 surface = a * vertex.x + b * vertex.y + c * vertex.z + d;
379 if(surface > -EPSILON)
392 bool ShouldBeSwapped(SortPrimitive poly2)
394 if (!XYOverlap(poly2)) return false;
395 if (SurfaceOutside(poly2)) return false;
396 if (SurfaceInside(poly2)) return false;
404 #define MAX_CLIP_POINTS 50
413 displaySystem.numDisplays--;
414 displaySystem.driver.DestroyDisplay(this);
416 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
421 bool Create(DisplaySystem displaySystem, void * window)
426 this.displaySystem = displaySystem;
427 this.window = window;
428 displaySystem.numDisplays++;
429 if(displaySystem.driver.CreateDisplay(this))
431 // if(!result) LogErrorCode(DisplayInitFailed, displaySystem.driver.name);
436 Surface GetSurface(int x, int y, Box clip)
438 Surface result = null;
442 Box box { -x, -y, -x + width - 1, -y + height - 1 };
445 surface.width = width - x;
446 surface.height = height - y;
447 surface.driver = displaySystem.driver;
448 surface.displaySystem = displaySystem;
449 surface.display = this;
451 if(displaySystem.driver.GetSurface(this, surface, x, y, box))
459 bool Resize(int width, int height)
461 return displaySystem.driver.DisplaySize(this, width, height);
464 void Position(int x, int y)
466 displaySystem.driver.DisplayPosition(this, x,y);
469 void StartUpdate(void)
471 displaySystem.driver.StartUpdate(this);
474 void Scroll(Box scroll, int x, int y, Extent dirty)
476 displaySystem.driver.Scroll(this, scroll, x, y, dirty);
479 void Update(Box updateBox)
481 displaySystem.driver.Update(this, updateBox);
486 displaySystem.driver.EndUpdate(this);
491 displaySystem.driver.NextPage(this);
494 bool Grab(Bitmap bitmap, int x, int y, int w, int h)
497 if(bitmap && w > 0 && h > 0 &&
498 displaySystem.driver.GrabScreen(this, bitmap, x, y, w, h))
505 void FontExtent(Font font, char * text, int len, int * width, int * height)
507 // Fix for OnLoadGraphics time alpha blended window text extent on GDI
508 #if defined(__WIN32__) && !defined(ECERE_NOTRUETYPE)
509 if(this && alphaBlend && pixelFormat == pixelFormat888 &&
510 displaySystem.driver == class(GDIDisplayDriver))
512 Surface s = GetSurface(0,0,null);
516 s.TextExtent(text, len, width, height);
522 // TODO: Should really pass display here...
523 DisplaySystem::FontExtent(this ? displaySystem : null, font, text, len, width, height);
526 void SetPalette(ColorAlpha * palette, bool colorMatch)
528 displaySystem.driver.SetPalette(this, palette, colorMatch);
531 void RestorePalette(void)
533 displaySystem.driver.RestorePalette(this);
536 bool Lock(bool render)
541 for(c = 0; c<current; c++)
543 Logf("Locking (%d)\n", current+1);
546 // TOCHECK: Why is displaySystem null with GISDesigner?
547 result = displaySystem && displaySystem.Lock();
553 result = displaySystem.driver.Lock(this);
569 for(c = 0; c<current; c++)
571 Logf("Unlocking (%d)\n", current);
574 if(!current && displaySystem)
575 displaySystem.driver.Unlock(this);
579 displaySystem.Unlock();
582 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
583 // *** 3D GRAPHICS ***
584 void SetCamera(Surface surface, Camera camera)
588 display3D = Display3D { };
590 if(!display3D.selection)
595 if(!display3D.selection)
596 displaySystem.driver.SelectMesh(this, null);
598 display3D.material = null;
599 display3D.mesh = null;
601 if(!display3D.selection)
603 displaySystem.driver.SetCamera(this, surface, camera);
606 this.display3D.camera = camera;
611 camera.Setup(width, height, null);
613 // Always calling Update() here had broken interpolation in OrbitWithMouse!
617 if(display3D.selection)
619 // Compute Picking Planes
621 Vector3D point { 0,0,0 };
623 Angle fovLeft, fovRight, fovTop, fovBottom;
626 double l = camera.origin.x - (display3D.pickX - display3D.pickWidth/2.0f);
627 double r = camera.origin.x - (display3D.pickX + display3D.pickWidth/2.0f);
628 double t = (display3D.pickY - display3D.pickHeight/2.0f) - camera.origin.y;
629 double b = (display3D.pickY + display3D.pickHeight/2.0f) - camera.origin.y;
631 fovLeft = atan(l / camera.focalX);
632 fovRight = atan(r / camera.focalX);
633 fovTop = atan(t / camera.focalY);
634 fovBottom = atan(b / camera.focalY);
637 quat.Yaw(fovLeft - Pi/2);
638 quat.ToDirection(normal);
639 display3D.viewPickingPlanes[left].FromPointNormal(normal, point);
642 quat.Yaw(fovRight + Pi/2);
643 quat.ToDirection(normal);
644 display3D.viewPickingPlanes[right].FromPointNormal(normal, point);
647 quat.Pitch(fovTop + Pi/2);
648 quat.ToDirection(normal);
649 display3D.viewPickingPlanes[top].FromPointNormal(normal, point);
652 quat.Pitch(fovBottom - Pi/2);
653 quat.ToDirection(normal);
654 display3D.viewPickingPlanes[bottom].FromPointNormal(normal, point);
657 normal.x = 0; normal.y = 0; normal.z = 1;
658 point.z = camera.zMin;
659 display3D.viewPickingPlanes[near].FromPointNormal(normal, point);
662 normal.x = 0; normal.y = 0; normal.z = -1;
663 point.z = camera.zMax;
664 display3D.viewPickingPlanes[far].FromPointNormal(normal, point);
666 for(c = 0; c<ClippingPlane::enumSize; c++)
667 display3D.worldPickingPlanes[c].MultMatrix(display3D.viewPickingPlanes[c], camera.inverseTranspose);
669 // Compute picking ray
672 display3D.rayView.p0 = { 0, 0, 0 };
673 p.x = display3D.pickX;
674 p.y = display3D.pickY;
676 camera.Unproject(p, display3D.rayView.delta);
678 // Convert ray to world space
679 camera.Untransform(display3D.rayView.p0, display3D.rayWorld.p0);
680 camera.Untransform(display3D.rayView.delta, p);
681 display3D.rayWorld.delta.Subtract(p, display3D.rayWorld.p0);
688 void SetLight(int id, Light light)
690 displaySystem.driver.SetLight(this, id, light);
693 void SetLights(Object object)
696 display3D._SetLights(this, object, 0);
699 // --- Transformations ---
701 void SetTransform(Matrix matrix, bool viewSpace)
703 if(display3D.selection)
707 transpose.Transpose(matrix);
711 for(c = 0; c<ClippingPlane::enumSize; c++)
712 display3D.localPickingPlanes[c].MultMatrix(display3D.viewPickingPlanes[c], transpose);
716 for(c = 0; c<ClippingPlane::enumSize; c++)
717 display3D.localPickingPlanes[c].MultMatrix(display3D.worldPickingPlanes[c], transpose);
721 if(display3D.intersecting)
725 p2.Add(display3D.rayView.p0, display3D.rayView.delta);
727 p2.Add(display3D.rayWorld.p0, display3D.rayWorld.delta);
729 display3D.rayLocal.p0.DivideMatrix(display3D.rayWorld.p0, matrix);
730 tp2.DivideMatrix(p2, matrix);
731 display3D.rayLocal.delta.Subtract(tp2, display3D.rayLocal.p0);
735 displaySystem.driver.SetTransform(this, matrix, viewSpace, viewSpace ? false : true);
738 void PushMatrix(void)
740 displaySystem.driver.PushMatrix(this);
745 displaySystem.driver.PopMatrix(this, true);
749 void ApplyMaterial(Material material, Mesh mesh)
751 if(material != display3D.material)
753 display3D.material = material;
754 displaySystem.driver.ApplyMaterial(this, material, mesh);
758 void DrawPrimitives(PrimitiveSingle primitive, Mesh mesh)
760 displaySystem.driver.DrawPrimitives(this, primitive, mesh);
763 void SelectMesh(Mesh mesh)
765 displaySystem.driver.SelectMesh(this, mesh);
766 display3D.mesh = mesh;
769 bool DrawMesh(Object object)
772 if(display3D.selection)
773 result = display3D.PickMesh(object, null);
776 Mesh mesh = object.mesh;
777 Material objectMaterial = object.material;
779 if(mesh.groups.first)
781 PrimitiveGroup group;
782 displaySystem.driver.SelectMesh(this, mesh);
783 display3D.mesh = mesh;
785 for(group = mesh.groups.first; group; group = group.next)
787 Material material = group.material ? group.material : objectMaterial;
788 if(!material) material = defaultMaterial;
790 if(material != display3D.material)
792 display3D.material = material;
793 displaySystem.driver.ApplyMaterial(this, material, mesh);
796 // *** Render Vertex Arrays ***
797 displaySystem.driver.DrawPrimitives(this, (PrimitiveSingle *)&group.type, mesh);
801 if(object.flags.translucent)
804 Matrix inverse, inverseTranspose;
807 if(object.flags.viewSpace)
808 matrix = object.matrix;
811 Camera camera = display3D.camera;
812 Matrix temp = object.matrix;
813 temp.m[3][0] -= camera.cPosition.x;
814 temp.m[3][1] -= camera.cPosition.y;
815 temp.m[3][2] -= camera.cPosition.z;
816 matrix.Multiply(temp, camera.viewMatrix);
819 inverse.Inverse(matrix);
820 inverseTranspose.Transpose(inverse);
822 for(c = 0; c < mesh.nPrimitives; c++)
824 PrimitiveSingle * triangle = &mesh.primitives[c];
825 SortPrimitive * sort;
826 Plane * plane = &triangle->plane;
827 if(display3D.nTriangles >= display3D.maxTriangles)
829 display3D.maxTriangles = display3D.maxTriangles ? (display3D.maxTriangles * 3 / 2) : 32768;
830 display3D.triangles = renew display3D.triangles SortPrimitive[display3D.maxTriangles];
832 sort = &display3D.triangles[display3D.nTriangles++];
833 sort->object = object;
834 sort->triangle = triangle;
835 sort->middle.MultMatrix(triangle->middle, matrix);
836 sort->middle.z *= -1;
837 // sort->plane.MultMatrix(triangle->plane, inverseTranspose);
838 sort->plane.d = plane->a * inverseTranspose.m[0][3] +
839 plane->b * inverseTranspose.m[1][3] +
840 plane->c * inverseTranspose.m[2][3] +
841 plane->d * inverseTranspose.m[3][3];
847 displaySystem.driver.SelectMesh(this, mesh);
848 display3D.mesh = mesh;
850 for(c = 0; c<mesh.nPrimitives; c++)
852 PrimitiveSingle * primitive = &mesh.primitives[c];
854 Material material = primitive->material ? primitive->material : objectMaterial;
855 if(!material) material = defaultMaterial;
857 if(material != display3D.material)
859 display3D.material = material;
860 displaySystem.driver.ApplyMaterial(this, material, mesh);
863 displaySystem.driver.DrawPrimitives(this, primitive, display3D.mesh);
871 bool IsObjectVisible(Object object)
874 if(display3D.selection || !display3D.camera)
875 planes = object.flags.viewSpace ? display3D.viewPickingPlanes : display3D.worldPickingPlanes;
877 planes = object.flags.viewSpace ? display3D.camera.viewClippingPlanes : display3D.camera.worldClippingPlanes;
878 return object.InsideFrustum(planes) != outside;
881 bool DrawObject(Object object)
884 if(object && object.volume)
887 FrustumPlacement visible;
889 Camera camera = display3D.camera;
891 if(display3D.selection || !camera)
892 planes = object.flags.viewSpace ? display3D.viewPickingPlanes : display3D.worldPickingPlanes;
894 planes = object.flags.viewSpace ? camera.viewClippingPlanes : camera.worldClippingPlanes;
896 visible = object.InsideFrustum(planes);
898 if(visible || display3D.pickingPlanes)
900 if(display3D.collectingHits && object.tag)
902 /*if(object.flags.root)
903 this.tags[display3D.tagIndex] = object.tag;
905 this.tags[++display3D.tagIndex] = object.tag;
907 display3D.tags[display3D.tagIndex++] = object.tag;
910 if(object.flags.mesh && object.mesh)
912 if(!display3D.selection && displaySystem.driver.PushMatrix)
913 displaySystem.driver.PushMatrix(this);
915 SetTransform(object.matrix, object.flags.viewSpace);
916 if(display3D.selection)
918 if(visible == intersecting || display3D.intersecting)
920 Vector3D rayIntersect;
921 if(display3D.PickMesh(object, rayIntersect))
923 if(display3D.intersecting)
925 Vector3D wresult, vresult;
926 wresult.MultMatrix(rayIntersect, object.matrix);
927 if(!object.flags.viewSpace)
928 camera.TransformPoint(vresult, wresult);
932 if(vresult.z < display3D.rayIntersect.z)
933 display3D.rayIntersect = vresult;
934 display3D.intersected = true;
944 result |= DrawMesh(object);
945 if(displaySystem.driver.PopMatrix)
946 displaySystem.driver.PopMatrix(this, true);
948 if(display3D.collectingHits && result /*&& object.tag*/)
951 HitRecord hit = (HitRecord)new0 byte[sizeof(class HitRecord) + sizeof(void *) * (display3D.tagIndex/*+1*/)];
952 display3D.hitList.Add(hit);
953 hit.pos = display3D.hitList.count-1;
954 hit.numTags = display3D.tagIndex /*+ 1*/;
955 for(c = 0; c</*=*/display3D.tagIndex; c++)
957 hit.tags[c] = display3D.tags[c];
960 if(!object.flags.viewSpace)
961 camera.TransformPoint(hit.center, object.wcenter);
963 hit.center = object.wcenter;
967 for(child = object.children.first; child; child = child.next)
968 result |= DrawObject(child);
970 if(display3D.collectingHits && /*!object.flags.root && */object.tag)
971 display3D.tagIndex--;
977 void DrawTranslucency(void)
981 // *** Render translucent primitives ***
982 if(display3D.nTriangles)
984 Matrix * matrix = null;
989 display3D.SortTriangles();
993 displaySystem.driver.PushMatrix(this);
994 for(c=0; c<display3D.nTriangles; c++)
996 SortPrimitive * sort = &display3D.triangles[c];
997 Mesh mesh = sort->object.mesh;
998 PrimitiveSingle * primitive = sort->triangle;
1001 if(&sort->object.matrix != matrix)
1003 matrix = &sort->object.matrix;
1005 displaySystem.driver.PopMatrix(this, false);
1006 displaySystem.driver.PushMatrix(this);
1007 SetTransform(matrix, sort->object.flags.viewSpace);
1009 if(mesh != display3D.mesh)
1011 displaySystem.driver.SelectMesh(this, mesh);
1012 display3D.mesh = mesh;
1015 material = primitive->material ? primitive->material : sort->object.material;
1016 if(!material) material = defaultMaterial;
1018 if(material != display3D.material)
1020 displaySystem.driver.ApplyMaterial(this, material, display3D.mesh);
1021 display3D.material = material;
1026 Material testMaterial { };
1029 amount = (display3D.triangles[0].middle.z - display3D.triangles[c].middle.z) /
1030 (display3D.triangles[0].middle.z - display3D.triangles[display3D.nTriangles-1].middle.z);
1032 testMaterial.flags.doubleSided = { doubleSided = true, translucent = true };
1033 testMaterial.diffuse.a = 1;
1034 testMaterial.emissive.r = testMaterial.emissive.g = testMaterial.emissive.b = amount;
1035 testMaterial.baseMap = material->baseMap;
1037 displaySystem.driver.ApplyMaterial(this, testMaterial, display3D.mesh);
1041 // *** Render primitive ***
1042 // if(sort->plane.d > 0)
1043 displaySystem.driver.DrawPrimitives(this, primitive, display3D.mesh);
1045 displaySystem.driver.PopMatrix(this, true);
1047 display3D.nTriangles = 0;
1054 void StartSelection(int pickX, int pickY, int pickW, int pickH)
1058 display3D = Display3D { };
1060 display3D.pickX = (float)pickX;
1061 display3D.pickY = (float)pickY;
1062 display3D.pickWidth = (float)pickW;
1063 display3D.pickHeight = (float)pickH;
1064 display3D.selection = true;
1067 void CollectHits(void)
1069 display3D.collectingHits = true;
1072 int GetHits(OldList list)
1074 display3D.collectingHits = false;
1075 display3D.hitList.Sort(HitRecord::Compare, null);
1076 list = display3D.hitList;
1077 display3D.hitList.Clear();
1081 void IntersectPolygons(void)
1083 display3D.rayIntersect = { MAXFLOAT, MAXFLOAT, MAXFLOAT };
1084 display3D.intersected = false;
1085 display3D.intersecting = true;
1088 bool GetIntersect(Vector3D intersect)
1090 intersect = display3D.rayIntersect;
1091 display3D.intersecting = false;
1092 return display3D.intersected;
1095 void StopSelection(void)
1097 display3D.selection = false;
1100 // --- Rendering States ---
1101 property FillModeValue fillMode { set { displaySystem.driver.SetRenderState(this, fillMode, value); } };
1102 property bool depthTest { set { displaySystem.driver.SetRenderState(this, depthTest, value); } };
1103 property bool depthWrite { set { displaySystem.driver.SetRenderState(this, depthWrite, value); } };
1104 property float fogDensity { set { displaySystem.driver.SetRenderState(this, fogDensity, *(uint *)(void *)&value); } };
1105 property Color fogColor { set { displaySystem.driver.SetRenderState(this, fogColor, value); } };
1106 property bool blend { set { displaySystem.driver.SetRenderState(this, blend, value); } };
1107 property Color ambient { set { displaySystem.driver.SetRenderState(this, ambient, value); } };
1108 property bool alphaWrite { set { displaySystem.driver.SetRenderState(this, alphaWrite, value); } };
1109 property bool antiAlias { set { displaySystem.driver.SetRenderState(this, antiAlias, value); } };
1110 property bool vSync { set { displaySystem.driver.SetRenderState(this, vSync, value); } };
1112 property bool pickingPlanes { set { display3D.pickingPlanes = value; } };
1114 property DisplayFlags flags { get { return displaySystem.flags; } }
1115 property PixelFormat pixelFormat { get { return /*alphaBlend ? pixelFormat888 : */displaySystem.pixelFormat; } }
1116 property bool alphaBlend { set { alphaBlend = value; } get { return alphaBlend; } };
1117 property bool useSharedMemory { set { useSharedMemory = value; } get { return useSharedMemory; } };
1118 property void * systemWindow { get { return window; } };
1119 property DisplaySystem displaySystem { get { return displaySystem; } };
1126 DisplaySystem displaySystem;
1132 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
1133 Display3D display3D;
1136 void * windowDriverData;
1137 bool useSharedMemory;
1140 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
1141 private class Display3D
1145 SortPrimitive * triangles;
1147 Vector3D points[MAX_CLIP_POINTS];
1148 Vector3D newPoints[MAX_CLIP_POINTS];
1149 byte goodPoints[MAX_CLIP_POINTS];
1154 Plane viewPickingPlanes[ClippingPlane], worldPickingPlanes[ClippingPlane];
1155 Plane localPickingPlanes[ClippingPlane];
1157 bool collectingHits, selection, intersecting, intersected, pickingPlanes;
1158 float pickX, pickY, pickWidth, pickHeight;
1163 Line rayView, rayWorld, rayLocal;
1164 Vector3D rayIntersect;
1171 int _SetLights(Display display, Object object, int id)
1173 if(id < NumberOfLights)
1177 if(object.flags.light && !object.light.flags.off)
1178 display.SetLight(id++, object.light);
1180 for(child = object.children.first; child; child = child.next)
1182 id = _SetLights(display, child, id);
1188 //#define TRESHOLD -1
1189 //#define TRESHOLD -0.25
1190 #define TRESHOLD -0.0025
1192 bool PickPrimitives(Mesh mesh, PrimitiveSingle primitive, Vector3D rayDiff, Vector3D rayIntersect)
1194 Plane * planes = localPickingPlanes;
1196 int nIndex = 1, nPoints = 1;
1198 bool result = false;
1199 Vector3D * points = this.points;
1200 Vector3D * newPoints = this.newPoints;
1201 byte * goodPoints = this.goodPoints;
1202 int nVertices = primitive.type.vertexRange ? primitive.nVertices : primitive.nIndices;
1205 bool i32bit = primitive.type.indices32bit;
1206 uint32 * indices32 = primitive.indices;
1207 uint16 * indices16 = primitive.indices;
1209 switch(primitive.type.primitiveType)
1211 case triangles: nIndex = 3; nPoints = 3; break;
1212 case quads: nIndex = 4; nPoints = 4; break;
1215 nIndex = 1; nPoints = 3;
1217 tmp = primitive.type.vertexRange ? mesh.vertices[primitive.first] : mesh.vertices[(i32bit ? indices32[0] : indices16[0])];
1218 points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1219 tmp = primitive.type.vertexRange ? mesh.vertices[primitive.first+1] : mesh.vertices[(i32bit ? indices32[1] : indices16[1])];
1220 points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1224 for(c = offset; c<nVertices; c += nIndex)
1226 bool outside = false;
1233 if(primitive.type.vertexRange)
1235 if(primitive.type.primitiveType == triStrip)
1237 tmp = mesh.vertices[primitive.first + (c & 1) ? (c - 1) : (c - 2)];
1238 points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1239 tmp = mesh.vertices[primitive.first + (c & 1) ? (c - 2) : (c - 1)];
1240 points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1242 else if(primitive.type.primitiveType == triFan)
1244 tmp = mesh.vertices[primitive.first + 0];
1245 points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1246 tmp = mesh.vertices[primitive.first + c - 1];
1247 points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1249 for(i = 0; i<nIndex; i++)
1251 tmp = mesh.vertices[primitive.first + c+i];
1252 points[i + offset] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1257 if(primitive.type.primitiveType == triStrip)
1259 i = (c & 1) ? (c - 1) : (c - 2);
1260 tmp = mesh.vertices[(i32bit ? indices32[i] : indices16[i])];
1261 points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1263 i = (c & 1) ? (c - 2) : (c - 1);
1264 tmp = mesh.vertices[(i32bit ? indices32[i] : indices16[i])];
1265 points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1267 else if(primitive.type.primitiveType == triFan)
1269 tmp = mesh.vertices[(i32bit ? indices32[0] : indices16[0])];
1270 points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1271 tmp = mesh.vertices[(i32bit ? indices32[c-1] : indices16[c-1])];
1272 points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1274 for(i = 0; i<nIndex; i++)
1276 tmp = mesh.vertices[(i32bit ? indices32[c+i] : indices16[c+i])];
1277 points[i + offset] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
1281 for(p = 0; p < 6; p++)
1283 Plane * plane = &planes[p];
1285 int numGoodPoints = 0;
1287 memset(goodPoints, 0, n);
1288 for(i = 0; i < n; i++)
1290 double dot = plane->normal.DotProduct(points[i]);
1291 double distance = dot + plane->d;
1292 if(distance > TRESHOLD)
1303 if(numGoodPoints < n)
1314 newPoints[newN++] = points[j];
1323 for(lastGood = n-1; !goodPoints[lastGood]; lastGood--);
1325 edge.p0 = points[lastGood];
1326 edge.delta.Subtract(points[j], edge.p0);
1327 plane->IntersectLine(edge, newPoints[newN++]);
1329 for(next = j+1; next != j; next++)
1331 if(next == n) next = 0;
1332 if(goodPoints[next])
1334 int prev = next - 1;
1335 if(prev < 0) prev = n-1;
1337 edge.p0 = points[prev];
1338 edge.delta.Subtract(points[next], edge.p0);
1339 plane->IntersectLine(edge, newPoints[newN++]);
1349 // Use the new points
1350 memcpy(points, newPoints, newN * sizeof(Vector3D));
1359 // TODO: Implement intersection with TriStrip, TriFan...
1362 // Intersect primitives
1364 Vector3D intersect, diff;
1365 int i0 = c, i1 = c+1, i2 = c+2;
1367 if(primitive.type.primitiveType == triStrip)
1369 i0 = (c & 1) ? (c - 1) : (c - 2);
1370 i1 = (c & 1) ? (c - 2) : (c - 1);
1373 else if(primitive.type.primitiveType == triFan)
1380 if(primitive.type.vertexRange)
1382 mesh.vertices[primitive.first + i0],
1383 mesh.vertices[primitive.first + i1],
1384 mesh.vertices[primitive.first + i2]);
1387 mesh.vertices[(i32bit ? indices32[i0] : indices16[i0])],
1388 mesh.vertices[(i32bit ? indices32[i1] : indices16[i1])],
1389 mesh.vertices[(i32bit ? indices32[i2] : indices16[i2])]);
1391 plane.IntersectLine(rayLocal, intersect);
1392 diff.Subtract(intersect, rayLocal.p0);
1393 diff.x /= rayLocal.delta.x;
1394 diff.y /= rayLocal.delta.y;
1395 diff.z /= rayLocal.delta.z;
1396 if(diff.x < rayDiff.x || diff.y < rayDiff.y || diff.z < rayDiff.z)
1399 rayIntersect = intersect;
1406 switch(primitive.type)
1409 points[strip] = points[2];
1413 points[1] = points[2];
1420 bool PickMesh(Object object, Vector3D rayIntersect)
1422 Mesh mesh = object.mesh;
1423 bool result = false;
1424 Vector3D rayDiff { MAXFLOAT, MAXFLOAT, MAXFLOAT };
1425 if(rayIntersect != null)
1426 rayIntersect = { MAXFLOAT, MAXFLOAT, MAXFLOAT };
1428 if(mesh.groups.first)
1430 PrimitiveGroup group;
1432 for(group = mesh.groups.first; group; group = group.next)
1434 if(PickPrimitives(mesh, (PrimitiveSingle *)&group.type, rayDiff, rayIntersect))
1445 for(c = 0; c < mesh.nPrimitives; c++)
1447 if(PickPrimitives(mesh, mesh.primitives[c], rayDiff, rayIntersect))
1458 void SortTriangles(void)
1461 Object object = null;
1463 for(c=0; c<nTriangles; c++)
1465 SortPrimitive * sort = &triangles[c];
1466 Mesh mesh = sort->object.mesh;
1467 PrimitiveSingle * primitive = sort->triangle;
1468 Vector3Df min { MAXFLOAT, MAXFLOAT, MAXFLOAT };
1469 Vector3Df max { -MAXFLOAT, -MAXFLOAT, -MAXFLOAT };
1471 bool ix32 = primitive->type.indices32bit;
1472 if(object != sort->object)
1474 object = sort->object;
1475 if(object.flags.viewSpace)
1476 matrix = object.matrix;
1479 Camera camera = this.camera;
1480 Matrix temp = object.matrix;
1481 temp.m[3][0] -= camera.cPosition.x;
1482 temp.m[3][1] -= camera.cPosition.y;
1483 temp.m[3][2] -= camera.cPosition.z;
1484 matrix.Multiply(temp, camera.viewMatrix);
1488 for(v = 0; v<primitive->nIndices; v++)
1490 Vector3Df * local = &mesh.vertices[ix32 ? primitive->indices32[v] : primitive->indices[v]];
1493 vertex.MultMatrix(local, &matrix);
1495 if(vertex.x > max.x) max.x = vertex.x;
1496 if(vertex.y > max.y) max.y = vertex.y;
1497 if(vertex.z > max.z) max.z = vertex.z;
1498 if(vertex.x < min.x) min.x = vertex.x;
1499 if(vertex.y < min.y) min.y = vertex.y;
1500 if(vertex.z < min.z) min.z = vertex.z;
1506 sort->marked = false;
1510 Logf("========= Before Sort ==========\n");
1511 for(c=0; c<nTriangles; c++)
1513 SortPrimitive * sort = &triangles[c];
1515 Mesh mesh = sort->mesh;
1516 PrimitiveSingle * primitive = sort->triangle;
1518 Logf("Triangle %d (%s):\n", c, primitive->material->name);
1520 for(v = 0; v<primitive->nIndices; v++)
1522 Vector3Df * local = &mesh.vertices[primitive->indices[v]];
1526 vertex.<MultMatrix(local, sort->matrix);
1528 Logf("Vertex %d:", v);
1530 // Logf(" Local %f, %f, %f:\n", local->x, local->y, local->z);
1531 Logf(" View %f, %f, %f:\n", vertex.x, vertex.y, vertex.z);
1535 Logf("Min %f, %f, %f:\n", sort->min.x, sort->min.y, sort->min.z);
1536 Logf("Max %f, %f, %f:\n", sort->max.x, sort->max.y, sort->max.z);
1540 // *** Sort translucent primitives ***
1541 qsort((void*) triangles, nTriangles, sizeof(SortPrimitive), SortPrimitive::Compare);
1543 Logf("\n\n========= After Sort ==========\n");
1544 for(c=0; c<nTriangles; c++)
1546 SortPrimitive * sort = &triangles[c];
1548 Mesh mesh = sort->mesh;
1549 PrimitiveSingle * primitive = sort->triangle;
1551 Logf("Triangle %d (%s):\n", c, primitive->material->name);
1553 for(v = 0; v<primitive->nIndices; v++)
1555 Vector3Df * local = &mesh.vertices[primitive->indices[v]];
1559 vertex.MultMatrix(local, sort->matrix);
1561 Logf("Vertex %d:", v);
1563 // Logf(" Local %f, %f, %f:\n", local->x, local->y, local->z);
1564 Logf(" View %f, %f, %f:\n", vertex.x, vertex.y, vertex.z);
1568 Logf("Min %f, %f, %f:\n", sort->min.x, sort->min.y, sort->min.z);
1569 Logf("Max %f, %f, %f:\n", sort->max.x, sort->max.y, sort->max.z);
1576 If all five tests fail for a particular Q,
1577 then P might obscure Q. Now Q must be tested.
1578 First, the algorithm checks if Q has been "marked."
1579 If Q is marked, then Q was "moved around" in the list
1580 during a previous iteration of the loop. The algorithm
1581 only allows a polygon to be moved once, to avoid the possibility
1582 of infinite loops. If Q is not marked, it is tested to see
1583 if it might obscure P. If Q cannot obscure P, then Q is possibly
1584 behind P and so it is good candidate to be drawn next.
1585 Therefore, the algorithm "abandons" the current P (that is, it
1586 stops testing Q's against the current P) and moves the current
1587 Q to the end of the list to become the next P.
1592 for(p = 0; p<nTriangles; p++)
1594 SortPrimitive * poly1 = &triangles[p];
1597 for(q = p+1; q<nTriangles; q++)
1601 SortPrimitive * poly2 = &triangles[q];
1602 if(poly1->ZOverlap(poly2) && !poly2->marked)
1604 if(poly1->ShouldBeSwapped(poly2))
1606 if(!poly2->ShouldBeSwapped(poly1))
1608 SortPrimitive temp = *poly2;
1609 memmove(triangles+1, triangles, sizeof(SortPrimitive)*q);
1610 triangles[0] = temp;
1611 triangles[0].marked = true;
1624 for(p = 0; p<nTriangles; p++)
1626 SortPrimitive * poly1 = &triangles[p];
1629 // for(q = p+1; q<nTriangles; q++)
1630 for(q = 0; q<nTriangles; q++)
1634 SortPrimitive * poly2 = &triangles[q];
1635 if(poly1->ZOverlap(poly2) && !poly2->marked)
1637 if(poly1->ShouldBeSwapped(poly2))
1639 if(!poly2->ShouldBeSwapped(poly1))
1641 SortPrimitive temp = *poly2;
1642 memmove(triangles+1, triangles, sizeof(SortPrimitive)*q);
1643 triangles[0] = temp;
1644 triangles[0].marked = true;
1657 for(p = nTriangles-1; p>=0; p--)
1659 SortPrimitive * poly1 = &triangles[p];
1662 for(q = nTriangles-1; q>=0; q--)
1666 SortPrimitive * poly2 = &triangles[q];
1667 if(poly1->ZOverlap(poly2) && !poly2->marked)
1669 if(poly1->ShouldBeSwapped(poly2))
1671 if(!poly2->ShouldBeSwapped(poly1))
1673 SortPrimitive temp = *poly2;
1674 memmove(triangles + q, triangles + q + 1, sizeof(SortPrimitive)*q);
1676 triangles[nTriangles-1] = temp;
1689 for(c=0; c<nTriangles; c++)
1692 SortPrimitive * poly1 = &triangles[c];
1694 // for(b=0; b<nTriangles; b++)
1695 //for(b=c+1; b<nTriangles; b++)
1697 if(b<this.nTriangles)
1699 SortPrimitive * poly2 = &this.triangles[b];
1701 if(poly1->ZOverlap(poly2) && poly1->ShouldBeSwapped(poly2))
1703 SortPrimitive temp = *poly1;
1716 bool IsDriverTextMode(char * driverName)
1718 subclass(DisplayDriver) driver = GetDisplayDriver(driverName);
1719 return driver ? driver.textMode : false;
1722 bool IsDriverPrinter(char * driverName)
1724 subclass(DisplayDriver) driver = GetDisplayDriver(driverName);
1725 return driver ? driver.printer : false;
1728 static ColorAlpha defaultPalette[256] =
1732 0xFF000000,0xFF000080,0xFF008000,0xFF008080,0xFF800000,0xFF800080,0xFF808000,0xFFC0C0C0,
1733 0xFF808080,0xFF0000FF,0xFF00FF00,0xFF00FFFF,0xFFFF0000,0xFFFF00FF,0xFFFFFF00,0xFFFFFFFF,
1735 0xFF000000,0xFF0000AA,0xFF00AA00,0xFF00AAAA,0xFFAA0000,0xFFAA00AA,0xFFAAAA00,0xFFABABAB,
1736 0xFF555555,0xFF5555FF,0xFF55FF55,0xFF55FFFF,0xFFFF5555,0xFFFF55FF,0xFFFFFF55,0xFFFFFFFF,
1738 // 6 x 6 x 6 Color Cube
1739 0xFF000000, 0xFF000033, 0xFF000066, 0xFF000099, 0xFF0000CC, 0xFF0000FF,
1740 0xFF003300, 0xFF003333, 0xFF003366, 0xFF003399, 0xFF0033CC, 0xFF0033FF,
1741 0xFF006600, 0xFF006633, 0xFF006666, 0xFF006699, 0xFF0066CC, 0xFF0066FF,
1742 0xFF009900, 0xFF009933, 0xFF009966, 0xFF009999, 0xFF0099CC, 0xFF0099FF,
1743 0xFF00CC00, 0xFF00CC33, 0xFF00CC66, 0xFF00CC99, 0xFF00CCCC, 0xFF00CCFF,
1744 0xFF00FF00, 0xFF00FF33, 0xFF00FF66, 0xFF00FF99, 0xFF00FFCC, 0xFF00FFFF,
1746 0xFF330000, 0xFF330033, 0xFF330066, 0xFF330099, 0xFF3300CC, 0xFF3300FF,
1747 0xFF333300, 0xFF333333, 0xFF333366, 0xFF333399, 0xFF3333CC, 0xFF3333FF,
1748 0xFF336600, 0xFF336633, 0xFF336666, 0xFF336699, 0xFF3366CC, 0xFF3366FF,
1749 0xFF339900, 0xFF339933, 0xFF339966, 0xFF339999, 0xFF3399CC, 0xFF3399FF,
1750 0xFF33CC00, 0xFF33CC33, 0xFF33CC66, 0xFF33CC99, 0xFF33CCCC, 0xFF33CCFF,
1751 0xFF33FF00, 0xFF33FF33, 0xFF33FF66, 0xFF33FF99, 0xFF33FFCC, 0xFF33FFFF,
1753 0xFF660000, 0xFF660033, 0xFF660066, 0xFF660099, 0xFF6600CC, 0xFF6600FF,
1754 0xFF663300, 0xFF663333, 0xFF663366, 0xFF663399, 0xFF6633CC, 0xFF6633FF,
1755 0xFF666600, 0xFF666633, 0xFF666666, 0xFF666699, 0xFF6666CC, 0xFF6666FF,
1756 0xFF669900, 0xFF669933, 0xFF669966, 0xFF669999, 0xFF6699CC, 0xFF6699FF,
1757 0xFF66CC00, 0xFF66CC33, 0xFF66CC66, 0xFF66CC99, 0xFF66CCCC, 0xFF66CCFF,
1758 0xFF66FF00, 0xFF66FF33, 0xFF66FF66, 0xFF66FF99, 0xFF66FFCC, 0xFF66FFFF,
1760 0xFF990000, 0xFF990033, 0xFF990066, 0xFF990099, 0xFF9900CC, 0xFF9900FF,
1761 0xFF993300, 0xFF993333, 0xFF993366, 0xFF993399, 0xFF9933CC, 0xFF9933FF,
1762 0xFF996600, 0xFF996633, 0xFF996666, 0xFF996699, 0xFF9966CC, 0xFF9966FF,
1763 0xFF999900, 0xFF999933, 0xFF999966, 0xFF999999, 0xFF9999CC, 0xFF9999FF,
1764 0xFF99CC00, 0xFF99CC33, 0xFF99CC66, 0xFF99CC99, 0xFF99CCCC, 0xFF99CCFF,
1765 0xFF99FF00, 0xFF99FF33, 0xFF99FF66, 0xFF99FF99, 0xFF99FFCC, 0xFF99FFFF,
1767 0xFFCC0000, 0xFFCC0033, 0xFFCC0066, 0xFFCC0099, 0xFFCC00CC, 0xFFCC00FF,
1768 0xFFCC3300, 0xFFCC3333, 0xFFCC3366, 0xFFCC3399, 0xFFCC33CC, 0xFFCC33FF,
1769 0xFFCC6600, 0xFFCC6633, 0xFFCC6666, 0xFFCC6699, 0xFFCC66CC, 0xFFCC66FF,
1770 0xFFCC9900, 0xFFCC9933, 0xFFCC9966, 0xFFCC9999, 0xFFCC99CC, 0xFFCC99FF,
1771 0xFFCCCC00, 0xFFCCCC33, 0xFFCCCC66, 0xFFCCCC99, 0xFFCCCCCC, 0xFFCCCCFF,
1772 0xFFCCFF00, 0xFFCCFF33, 0xFFCCFF66, 0xFFCCFF99, 0xFFCCFFCC, 0xFFCCFFFF,
1774 0xFFFF0000, 0xFFFF0033, 0xFFFF0066, 0xFFFF0099, 0xFFFF00CC, 0xFFFF00FF,
1775 0xFFFF3300, 0xFFFF3333, 0xFFFF3366, 0xFFFF3399, 0xFFFF33CC, 0xFFFF33FF,
1776 0xFFFF6600, 0xFFFF6633, 0xFFFF6666, 0xFFFF6699, 0xFFFF66CC, 0xFFFF66FF,
1777 0xFFFF9900, 0xFFFF9933, 0xFFFF9966, 0xFFFF9999, 0xFFFF99CC, 0xFFFF99FF,
1778 0xFFFFCC00, 0xFFFFCC33, 0xFFFFCC66, 0xFFFFCC99, 0xFFFFCCCC, 0xFFFFCCFF,
1779 0xFFFFFF00, 0xFFFFFF33, 0xFFFFFF66, 0xFFFFFF99, 0xFFFFFFCC, 0xFFFFFFFF,
1781 // 16 Shades of gray
1782 0xFF000000,0xFF101010,0xFF202020,0xFF303030,0xFF404040,0xFF505050,0xFF606060,0xFF707070,
1783 0xFF808080,0xFF909090,0xFFA0A0A0,0xFFB0B0B0,0xFFC0C0C0,0xFFD0D0D0,0xFFE0E0E0,0xFFF0F0F0,
1786 0xFF080808,0xFF101010,0xFF585858,0xFF606060,0xFFA8A8A8,0xFFB0B0B0,0xFFF8F8F8,0xFFFFFFFF
1790 0xFF080000,0xFF100000,0xFF180000,0xFF200000,0xFF280000,0xFF300000,0xFF380000,0xFF400000,
1791 0xFF480000,0xFF500000,0xFF580000,0xFF600000,0xFF680000,0xFF700000,0xFF780000,0xFF800000,
1792 0xFF880000,0xFF900000,0xFF980000,0xFFA00000,0xFFA80000,0xFFB00000,0xFFB80000,0xFFC00000,
1793 0xFFC80000,0xFFD00000,0xFFD80000,0xFFE00000,0xFFE80000,0xFFF00000,0xFFF80000,0xFFFF0000,
1795 0xFF000800,0xFF001000,0xFF001800,0xFF002000,0xFF002800,0xFF003000,0xFF003800,0xFF004000,
1796 0xFF004800,0xFF005000,0xFF005800,0xFF006000,0xFF006800,0xFF007000,0xFF007800,0xFF008000,
1797 0xFF008800,0xFF009000,0xFF009800,0xFF00A000,0xFF00A800,0xFF00B000,0xFF00B800,0xFF00C000,
1798 0xFF00C800,0xFF00D000,0xFF00D800,0xFF00E000,0xFF00E800,0xFF00F000,0xFF00F800,0xFF00FF00,
1800 0xFF000808,0xFF001010,0xFF001818,0xFF002020,0xFF002828,0xFF003030,0xFF003838,0xFF004040,
1801 0xFF004848,0xFF005050,0xFF005858,0xFF006060,0xFF006868,0xFF007070,0xFF007878,0xFF008080,
1802 0xFF008888,0xFF009090,0xFF009898,0xFF00A0A0,0xFF00A8A8,0xFF00B0B0,0xFF00B8B8,0xFF00C0C0,
1803 0xFF00C8C8,0xFF00D0D0,0xFF00D8D8,0xFF00E0E0,0xFF00E8E8,0xFF00F0F0,0xFF00F8F8,0xFF00FFFF,
1805 0xFF000008,0xFF000010,0xFF000018,0xFF000020,0xFF000028,0xFF000030,0xFF000038,0xFF000040,
1806 0xFF000048,0xFF000050,0xFF000058,0xFF000060,0xFF000068,0xFF000070,0xFF000078,0xFF000080,
1807 0xFF000088,0xFF000090,0xFF000098,0xFF0000A0,0xFF0000A8,0xFF0000B0,0xFF0000B8,0xFF0000C0,
1808 0xFF0000C8,0xFF0000D0,0xFF0000D8,0xFF0000E0,0xFF0000E8,0xFF0000F0,0xFF0000F8,0xFF0000FF,
1810 0xFF080008,0xFF100010,0xFF180018,0xFF200020,0xFF280028,0xFF300030,0xFF380038,0xFF400040,
1811 0xFF480048,0xFF500050,0xFF580058,0xFF600060,0xFF680068,0xFF700070,0xFF780078,0xFF800080,
1812 0xFF880088,0xFF900090,0xFF980098,0xFFA000A0,0xFFA800A8,0xFFB000B0,0xFFB800B8,0xFFC000C0,
1813 0xFFC800C8,0xFFD000D0,0xFFD800D8,0xFFE000E0,0xFFE800E8,0xFFF000F0,0xFFF800F8,0xFFFF00FF,
1815 0xFF080800,0xFF101000,0xFF181800,0xFF202000,0xFF282800,0xFF303000,0xFF383800,0xFF404000,
1816 0xFF484800,0xFF505000,0xFF585800,0xFF606000,0xFF686800,0xFF707000,0xFF787800,0xFF808000,
1817 0xFF888800,0xFF909000,0xFF989800,0xFFA0A000,0xFFA8A800,0xFFB0B000,0xFFB8B800,0xFFC0C000,
1818 0xFFC8C800,0xFFD0D000,0xFFD8D800,0xFFE0E000,0xFFE8E800,0xFFF0F000,0xFFF8F800,0xFFFFFF00,
1820 0xFF080808,0xFF101010,0xFF181818,0xFF202020,0xFF282828,0xFF303030,0xFF383838,0xFF404040,
1821 0xFF484848,0xFF505050,0xFF585858,0xFF606060,0xFF686868,0xFF707070,0xFF787878,0xFF808080,
1822 0xFF888888,0xFF909090,0xFF989898,0xFFA0A0A0,0xFFA8A8A8,0xFFB0B0B0,0xFFB8B8B8,0xFFC0C0C0,
1823 0xFFC8C8C8,0xFFD0D0D0,0xFFD8D8D8,0xFFE0E0E0,0xFFE8E8E8,0xFFF0F0F0,0xFFF8F8F8,0xFFFFFFFF
1827 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
1828 static Material defaultMaterial
1831 diffuse = { 1.0f, 1.0f, 1.0f },
1832 ambient = { 1.0f, 1.0f, 1.0f },
1833 flags = { doubleSided = true, noFog = true };
1837 static byte colorDepthShifts[PixelFormat] = { 0,0,1,1,1,2,0,1,2 };
1838 static Size resolutions[Resolution] =
1841 {320,200},{320,240},{320,400},{360,480},
1842 {400,256},{400,300},{512,256},{512,384},
1843 {640,200},{640,350},{640,400},{640,480},
1844 {720,348},{800,600},{856,480},{960,720},
1845 {1024,768},{1152,864},{1280,1024},{1600,1200},
1848 static int colorDepths[PixelFormat] = {4,8,12,15,16,32,8,16,32};
1850 // --- Query utilities ---
1852 public int GetResolutionWidth(Resolution resolution)
1854 return resolutions[resolution].w;
1857 public int GetResolutionHeight(Resolution resolution)
1859 return resolutions[resolution].h;
1862 public int GetDepthBits(PixelFormat colorDepth)
1864 return colorDepths[colorDepth];
1867 public byte GetColorDepthShifts(PixelFormat format)
1869 return colorDepthShifts[format];
1872 public ColorAlpha * GetDefaultPalette()
1874 return (ColorAlpha *)defaultPalette;
1876 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
1877 public Material GetDefaultMaterial()
1879 return defaultMaterial;
1882 public int BestColorMatch(ColorAlpha * palette, int start, int end, Color rgb)
1888 int bestscore = MAXINT,score;
1889 byte r = rgb.r, g = rgb.g, b = rgb.b;
1892 for(c = start; c <= end; c++)
1895 current = palette[c];
1896 if(rgb && !c) continue;
1900 score = Abs(dr) + Abs(dg) + Abs(db);
1901 if(score <= bestscore)