/ecere/src/gfx/Display.ec
C | 1593 lines | 1144 code | 185 blank | 264 comment | 197 complexity | d235e357d547425d4c31e9b725969030 MD5 | raw file
- namespace gfx;
- #if (defined(ECERE_VANILLA) || defined(ECERE_ONEDRIVER)) && defined(__WIN32__)
- #define ECERE_NOTRUETYPE
- #endif
- import "System"
- import "Color"
- import "Bitmap"
- import "Surface"
- import "DisplaySystem"
- import "Resource"
- import "FontResource"
- import "BitmapResource"
- import "LFBDisplayDriver"
- // TOFIX: Temporary until we pass Display instead of DisplaySystem to FontExtent
- #if defined(__WIN32__) && !defined(ECERE_NOTRUETYPE)
- import "GDIDisplayDriver"
- #endif
- #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
- import "Camera"
- import "Plane"
- import "Matrix"
- import "Mesh"
- import "Object"
- import "Quaternion"
- import "Vector3D"
- #endif
- public enum RenderState { fillMode = 1, depthTest, depthWrite, fogDensity, fogColor, blend, ambient, alphaWrite, antiAlias, vSync };
- public enum FillModeValue { solid, wireframe };
- public class DisplayFlags
- {
- public bool fullScreen:1, flipping:1, alpha:1, memBackBuffer:1, text:1, scrolling:1, printer:1;
- };
- public class FontFlags
- {
- public bool bold:1, italic:1, underline:1;
- };
- static void DummyFunction()
- {
- Mutex mutex { };
- }
- public class DisplayDriver
- {
- public:
- class_data char * name;
- class_data bool textMode;
- class_data bool printer;
- class_data DisplaySystem displaySystem;
- class_property DisplaySystem displaySystem
- {
- set { class_data(displaySystem) = value; }
- get { return class_data(displaySystem); }
- };
- class_property char * name
- {
- set { class_data(name) = value; }
- get { return class_data(name); }
- };
- class_property bool printer
- {
- set { class_data(printer) = value; }
- get { return class_data(printer); }
- };
- // Constructor / Destructor
- virtual bool ::CreateDisplaySystem(DisplaySystem);
- virtual void ::DestroyDisplaySystem(DisplaySystem);
- virtual bool ::CreateDisplay(Display);
- virtual void ::DestroyDisplay(Display);
- // Display Position and Size
- virtual bool ::DisplaySize(Display, int, int);
- virtual void ::DisplayPosition(Display, int, int);
- // Palettes
- virtual void ::SetPalette(Display, ColorAlpha *, bool);
- virtual void ::RestorePalette(Display);
- // Display the back buffer content
- virtual void ::StartUpdate(Display);
- virtual void ::Scroll(Display, Box, int, int, Extent);
- virtual void ::Update(Display, Box);
- virtual void ::EndUpdate(Display);
-
- // Allocate/free a bitmap
- virtual bool ::AllocateBitmap(DisplaySystem, Bitmap, int, int, int, PixelFormat, bool);
- virtual void ::FreeBitmap(DisplaySystem, Bitmap);
- // Lock
- virtual bool ::LockSystem(DisplaySystem displaySystem);
- virtual void ::UnlockSystem(DisplaySystem displaySystem);
- virtual bool ::Lock(Display);
- virtual void ::Unlock(Display);
- // Get/release a surface
- virtual bool ::GetSurface(Display, Surface surface, int,int,Box);
- virtual bool ::GetBitmapSurface(DisplaySystem displaySystem, Surface surface, Bitmap bitmap, int,int,Box);
- virtual void ::ReleaseSurface(Display this, Surface);
- // Clip a surface
- virtual void ::Clip(Display, Surface, Box);
- // Grab from the screen
- virtual bool ::GrabScreen(Display, Bitmap, int, int, unsigned int, unsigned int);
-
- // Converts a bitmap format
- virtual bool ::ConvertBitmap(DisplaySystem, Bitmap, PixelFormat, ColorAlpha *);
- // Converts an LFB bitmap into an offscreen bitmap for this device
- virtual bool ::MakeDDBitmap(DisplaySystem, Bitmap, bool);
- // Font loading
- virtual Font ::LoadFont(DisplaySystem displaySystem, char * faceName, float size, FontFlags flags);
- virtual void ::UnloadFont(DisplaySystem, Font);
- // 2D Drawing
- virtual void ::SetForeground(Display, Surface, ColorAlpha);
- virtual void ::SetBackground(Display, Surface, ColorAlpha);
- virtual void ::LineStipple(Display, Surface, uint);
- virtual ColorAlpha ::GetPixel(Display, Surface, int, int);
- virtual void ::PutPixel(Display, Surface, int, int);
- virtual void ::DrawLine(Display, Surface, int, int, int, int);
- virtual void ::Rectangle(Display, Surface,int,int,int,int);
- virtual void ::Area(Display, Surface,int,int,int,int);
- virtual void ::Clear(Display, Surface, ClearType);
- virtual void ::Blit(Display, Surface, Bitmap, int, int, int, int, int, int);
- virtual void ::Stretch(Display, Surface, Bitmap, int, int, int, int, int, int,int,int);
- virtual void ::Filter(Display, Surface, Bitmap, int, int, int, int, int, int,int,int);
- virtual void ::BlitDI(Display, Surface, Bitmap, int, int, int, int, int, int);
- virtual void ::StretchDI(Display, Surface, Bitmap, int, int, int, int, int, int,int,int);
- virtual void ::FilterDI(Display, Surface, Bitmap, int, int, int, int, int, int, int,int);
- virtual void ::TextFont(Display, Surface, Font);
- virtual void ::TextOpacity(Display, Surface, bool);
- virtual void ::WriteText(Display, Surface, int, int, char *, int);
- virtual void ::TextExtent(Display, Surface, char *, int, int *, int *);
- virtual void ::FontExtent(DisplaySystem, Font, char *, int, int *, int *);
- virtual void ::DrawingChar(Display, Surface, char);
- virtual void ::NextPage(Display);
- #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
- // 3D Graphics
- virtual void ::SetRenderState(Display, RenderState, uint);
- virtual void ::SetLight(Display, int, Light);
- virtual void ::SetCamera(Display, Surface, Camera);
- virtual bool ::AllocateMesh(DisplaySystem, Mesh);
- virtual void ::FreeMesh(DisplaySystem, Mesh);
- virtual bool ::LockMesh(DisplaySystem, Mesh, MeshFeatures flags);
- virtual void ::UnlockMesh(DisplaySystem, Mesh, MeshFeatures flags);
- virtual void * ::AllocateIndices(DisplaySystem, int nIndices, bool indices32bit);
- virtual void ::FreeIndices(DisplaySystem, void * indices);
- virtual uint16 * ::LockIndices(DisplaySystem, void * indices);
- virtual void ::UnlockIndices(DisplaySystem, void * indices, bool indices32bit, int nIndices);
- virtual void ::SelectMesh(Display, Mesh);
- virtual void ::ApplyMaterial(Display, Material, Mesh);
- virtual void ::DrawPrimitives(Display, PrimitiveSingle *, Mesh mesh);
- virtual void ::PushMatrix(Display);
- virtual void ::PopMatrix(Display, bool);
- virtual void ::SetTransform(Display, Matrix, bool, bool);
- #endif
- virtual void ::SetBlitTint(Display, Surface, ColorAlpha);
- };
- public enum Alignment { left, right, center };
- public enum ClearType { colorBuffer, depthBuffer, colorAndDepth };
- subclass(DisplayDriver) GetDisplayDriver(char * driverName)
- {
- if(driverName)
- {
- OldLink link;
- for(link = class(DisplayDriver).derivatives.first; link; link = link.next)
- {
- subclass(DisplayDriver) displayDriver = link.data;
- if(displayDriver && displayDriver.name && !strcmp(displayDriver.name, driverName))
- return displayDriver;
- }
- }
- return null;
- }
- DisplaySystem GetDisplaySystem(char * driverName)
- {
- subclass(DisplayDriver) displayDriver = GetDisplayDriver(driverName);
- return displayDriver ? displayDriver.displaySystem : null;
- }
- define textCellW = 8;
- define textCellH = 16;
- public enum PixelFormat // : byte MESSES UP GuiApplication
- {
- pixelFormat4, pixelFormat8, pixelFormat444, pixelFormat555, pixelFormat565, pixelFormat888, pixelFormatAlpha, pixelFormatText, pixelFormatRGBA
- };
- public enum Resolution : int
- {
- resText80x25, res320x200, res320x240, res320x400, res360x480, res400x256, res400x300, res512x256, res512x384,
- res640x200, res640x350, res640x400, res640x480, res720x348, res800x600, res856x480, res960x720, res1024x768,
- res1152x864, res1280x1024, res1600x1200, res768x480
- };
- #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
- public class LightFlags
- {
- public bool off:1, spot:1, omni:1, attenuation:1;
- };
- public struct Light
- {
- LightFlags flags;
- ColorRGB ambient;
- ColorRGB diffuse;
- ColorRGB specular;
- Vector3D direction;
- Quaternion orientation;
- Object lightObject;
- Object target;
- Degrees fallOff;
- Degrees hotSpot;
- float Kc;
- float Kl;
- float Kq;
- Degrees start;
- Degrees end;
- float multiplier;
- };
- define NumberOfLights = 8;
- // Painter's algorithm
- public class HitRecord : struct
- {
- public:
- HitRecord prev, next;
- uint pos;
- uint numTags;
- Vector3D center;
- void * tags[1]; // More tags may follow
- int Compare(HitRecord recordB, void * unused)
- {
- if(center.z > recordB.center.z)
- return 1;
- else if(center.z < recordB.center.z)
- return -1;
- else if(pos > recordB.pos)
- return 1;
- else if(pos < recordB.pos)
- return -1;
- else
- return 0;
- }
- };
- #define EPSILON 0.00001
- struct SortPrimitive
- {
- PrimitiveSingle * triangle;
- Object object;
- Vector3Df middle;
- Vector3Df min, max;
- Plane plane;
- bool marked;
- int Compare(SortPrimitive primitive2)
- {
- double value;
- if(ZOverlap(primitive2) && Sgn(plane.d) != Sgn(primitive2.plane.d))
- value = plane.d - primitive2.plane.d;
- else
- value = middle.z - primitive2.middle.z;
- if(value > EPSILON)
- return 1;
- else if(value<-EPSILON)
- return -1;
- else
- return 0;
- }
- bool ZOverlap(SortPrimitive poly2)
- {
- if(min.z > poly2.max.z - EPSILON || poly2.min.z > max.z - EPSILON)
- return false;
- return true;
- }
- /*
- bool XYOverlap(SortPrimitive poly2)
- {
- if(min.x > poly2.max.x - EPSILON || poly2.min.x > max.x - EPSILON )
- return false;
- if(min.y > poly2.max.y - EPSILON || poly2.min.y > max.y - EPSILON )
- return false;
- return true;
- }
- bool SurfaceOutside(SortPrimitive poly2)
- {
- bool result = true;
- PrimitiveSingle * primitive = triangle;
- Mesh mesh = object.mesh;
- Matrix * matrix = &object.matrix;
- int v;
- float a = poly2.plane.a, b = poly2.plane.b, c = poly2.plane.c, d = poly2.plane.d;
- if(d < 0)
- {
- a*=-1;
- b*=-1;
- c*=-1;
- d = - (a * poly2.middle.x + b * poly2.middle.y + c * poly2.middle.z);
- }
- for(v = 0; v < primitive->nIndices; v++)
- {
- double surface;
- Vector3Df * local = &mesh.vertices[primitive->indices[v]];
- Vector3Df vertex;
- vertex.MultMatrix(local, matrix);
- surface = a * vertex.x + b * vertex.y + c * vertex.z + d;
- if(surface < EPSILON)
- {
- result = false;
- break;
- }
- }
- if(result == true)
- return true;
- else
- return result;
- }
- int SurfaceInside(SortPrimitive poly2)
- {
- bool result = true;
- PrimitiveSingle * primitive = poly2.triangle;
- Mesh mesh = poly2.object.mesh;
- Matrix * matrix = &poly2.object.matrix;
- int v;
- float a = plane.a, b = plane.b, c = plane.c, d = plane.d;
- if(d < 0)
- {
- a*=-1;
- b*=-1;
- c*=-1;
- d = - (a * middle.x + b * middle.y + c * middle.z);
- }
-
- for(v = 0; v < primitive->nIndices; v++)
- {
- double surface;
- Vector3Df * local = &mesh.vertices[primitive->indices[v]];
- Vector3Df vertex;
- vertex.Transform(local, matrix);
- surface = a * vertex.x + b * vertex.y + c * vertex.z + d;
- if(surface > -EPSILON)
- {
- result = false;
- break;
- }
- }
- if(result == true)
- return true;
- else
- return result;
- }
- bool ShouldBeSwapped(SortPrimitive poly2)
- {
- if (!XYOverlap(poly2)) return false;
- if (SurfaceOutside(poly2)) return false;
- if (SurfaceInside(poly2)) return false;
- return true;
- }
- */
- };
- #endif
- #define MAX_CLIP_POINTS 50
- public class Display
- {
- public:
- ~Display()
- {
- if(displaySystem)
- {
- displaySystem.numDisplays--;
- displaySystem.driver.DestroyDisplay(this);
- }
- #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
- delete display3D;
- #endif
- }
- bool Create(DisplaySystem displaySystem, void * window)
- {
- bool result = false;
- if(displaySystem)
- {
- this.displaySystem = displaySystem;
- this.window = window;
- displaySystem.numDisplays++;
- if(displaySystem.driver.CreateDisplay(this))
- result = true;
- // if(!result) LogErrorCode(DisplayInitFailed, displaySystem.driver.name);
- }
- return result;
- }
- Surface GetSurface(int x, int y, Box clip)
- {
- Surface result = null;
- Surface surface { };
- if(surface)
- {
- Box box { -x, -y, -x + width - 1, -y + height - 1 };
- box.Clip(clip);
- surface.width = width - x;
- surface.height = height - y;
- surface.driver = displaySystem.driver;
- surface.displaySystem = displaySystem;
- surface.display = this;
- if(displaySystem.driver.GetSurface(this, surface, x, y, box))
- result = surface;
- if(!result)
- delete surface;
- }
- return result;
- }
- bool Resize(int width, int height)
- {
- return displaySystem.driver.DisplaySize(this, width, height);
- }
- void Position(int x, int y)
- {
- displaySystem.driver.DisplayPosition(this, x,y);
- }
- void StartUpdate(void)
- {
- displaySystem.driver.StartUpdate(this);
- }
- void Scroll(Box scroll, int x, int y, Extent dirty)
- {
- displaySystem.driver.Scroll(this, scroll, x, y, dirty);
- }
- void Update(Box updateBox)
- {
- displaySystem.driver.Update(this, updateBox);
- }
- void EndUpdate(void)
- {
- displaySystem.driver.EndUpdate(this);
- }
- void NextPage(void)
- {
- displaySystem.driver.NextPage(this);
- }
- bool Grab(Bitmap bitmap, int x, int y, int w, int h)
- {
- bool result = false;
- if(bitmap && w > 0 && h > 0 &&
- displaySystem.driver.GrabScreen(this, bitmap, x, y, w, h))
- result = true;
- else
- bitmap.Free();
- return result;
- }
- void FontExtent(Font font, char * text, int len, int * width, int * height)
- {
- // Fix for OnLoadGraphics time alpha blended window text extent on GDI
- #if defined(__WIN32__) && !defined(ECERE_NOTRUETYPE)
- if(this && alphaBlend && pixelFormat == pixelFormat888 &&
- displaySystem.driver == class(GDIDisplayDriver))
- {
- Surface s = GetSurface(0,0,null);
- if(s)
- {
- s.font = font;
- s.TextExtent(text, len, width, height);
- delete s;
- }
- }
- else
- #endif
- // TODO: Should really pass display here...
- DisplaySystem::FontExtent(this ? displaySystem : null, font, text, len, width, height);
- }
- void SetPalette(ColorAlpha * palette, bool colorMatch)
- {
- displaySystem.driver.SetPalette(this, palette, colorMatch);
- }
-
- void RestorePalette(void)
- {
- displaySystem.driver.RestorePalette(this);
- }
- bool Lock(bool render)
- {
- bool result = false;
- /*
- int c;
- for(c = 0; c<current; c++)
- Log(" ");
- Logf("Locking (%d)\n", current+1);
- */
-
- // TOCHECK: Why is displaySystem null with GISDesigner?
- result = displaySystem && displaySystem.Lock();
- if(result && render)
- {
- mutex.Wait();
- if(!current)
- result = displaySystem.driver.Lock(this);
- else
- result = true;
- current++;
- }
- return result;
- }
- void Unlock(void)
- {
- if(current)
- {
- current--;
- /*{
- int c;
-
- for(c = 0; c<current; c++)
- Log(" ");
- Logf("Unlocking (%d)\n", current);
- }
- */
- if(!current && displaySystem)
- displaySystem.driver.Unlock(this);
- mutex.Release();
- }
- if(displaySystem)
- displaySystem.Unlock();
- }
- #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
- // *** 3D GRAPHICS ***
- void SetCamera(Surface surface, Camera camera)
- {
- if(!display3D)
- {
- display3D = Display3D { };
- }
- if(!display3D.selection)
- DrawTranslucency();
- if(!camera)
- {
- if(!display3D.selection)
- displaySystem.driver.SelectMesh(this, null);
-
- display3D.material = null;
- display3D.mesh = null;
- }
- if(!display3D.selection)
- {
- displaySystem.driver.SetCamera(this, surface, camera);
- }
- this.display3D.camera = camera;
- if(camera)
- {
- if(!camera.focalX)
- camera.Setup(width, height, null);
- // Always calling Update() here had broken interpolation in OrbitWithMouse!
- if(!camera.cAngle.w)
- camera.Update();
- if(display3D.selection)
- {
- // Compute Picking Planes
- Vector3D normal;
- Vector3D point { 0,0,0 };
- Quaternion quat;
- Angle fovLeft, fovRight, fovTop, fovBottom;
- ClippingPlane c;
- double l = camera.origin.x - (display3D.pickX - display3D.pickWidth/2.0f);
- double r = camera.origin.x - (display3D.pickX + display3D.pickWidth/2.0f);
- double t = (display3D.pickY - display3D.pickHeight/2.0f) - camera.origin.y;
- double b = (display3D.pickY + display3D.pickHeight/2.0f) - camera.origin.y;
-
- fovLeft = atan(l / camera.focalX);
- fovRight = atan(r / camera.focalX);
- fovTop = atan(t / camera.focalY);
- fovBottom = atan(b / camera.focalY);
-
- // --- Left ---
- quat.Yaw(fovLeft - Pi/2);
- quat.ToDirection(normal);
- display3D.viewPickingPlanes[left].FromPointNormal(normal, point);
- // --- Right ---
- quat.Yaw(fovRight + Pi/2);
- quat.ToDirection(normal);
- display3D.viewPickingPlanes[right].FromPointNormal(normal, point);
- // --- Top ---
- quat.Pitch(fovTop + Pi/2);
- quat.ToDirection(normal);
- display3D.viewPickingPlanes[top].FromPointNormal(normal, point);
- // --- Bottom ---
- quat.Pitch(fovBottom - Pi/2);
- quat.ToDirection(normal);
- display3D.viewPickingPlanes[bottom].FromPointNormal(normal, point);
- // --- Near ---
- normal.x = 0; normal.y = 0; normal.z = 1;
- point.z = camera.zMin;
- display3D.viewPickingPlanes[near].FromPointNormal(normal, point);
- // --- Far ---
- normal.x = 0; normal.y = 0; normal.z = -1;
- point.z = camera.zMax;
- display3D.viewPickingPlanes[far].FromPointNormal(normal, point);
- for(c = 0; c<ClippingPlane::enumSize; c++)
- display3D.worldPickingPlanes[c].MultMatrix(display3D.viewPickingPlanes[c], camera.inverseTranspose);
- // Compute picking ray
- {
- Vector3D p;
- display3D.rayView.p0 = { 0, 0, 0 };
- p.x = display3D.pickX;
- p.y = display3D.pickY;
- p.z = 0.0f;
- camera.Unproject(p, display3D.rayView.delta);
- // Convert ray to world space
- camera.Untransform(display3D.rayView.p0, display3D.rayWorld.p0);
- camera.Untransform(display3D.rayView.delta, p);
- display3D.rayWorld.delta.Subtract(p, display3D.rayWorld.p0);
- }
- }
- }
- }
- // --- Lights ---
- void SetLight(int id, Light light)
- {
- displaySystem.driver.SetLight(this, id, light);
- }
- void SetLights(Object object)
- {
- if(object)
- display3D._SetLights(this, object, 0);
- }
- // --- Transformations ---
- void SetTransform(Matrix matrix, bool viewSpace)
- {
- if(display3D.selection)
- {
- ClippingPlane c;
- Matrix transpose;
- transpose.Transpose(matrix);
- if(viewSpace)
- {
- for(c = 0; c<ClippingPlane::enumSize; c++)
- display3D.localPickingPlanes[c].MultMatrix(display3D.viewPickingPlanes[c], transpose);
- }
- else
- {
- for(c = 0; c<ClippingPlane::enumSize; c++)
- display3D.localPickingPlanes[c].MultMatrix(display3D.worldPickingPlanes[c], transpose);
- }
- // Transform ray
- if(display3D.intersecting)
- {
- Vector3D p2, tp2;
- if(viewSpace)
- p2.Add(display3D.rayView.p0, display3D.rayView.delta);
- else
- p2.Add(display3D.rayWorld.p0, display3D.rayWorld.delta);
- display3D.rayLocal.p0.DivideMatrix(display3D.rayWorld.p0, matrix);
- tp2.DivideMatrix(p2, matrix);
- display3D.rayLocal.delta.Subtract(tp2, display3D.rayLocal.p0);
- }
- }
- else
- displaySystem.driver.SetTransform(this, matrix, viewSpace, viewSpace ? false : true);
- }
- void PushMatrix(void)
- {
- displaySystem.driver.PushMatrix(this);
- }
- void PopMatrix(void)
- {
- displaySystem.driver.PopMatrix(this, true);
- }
- // --- Drawing ---
- void ApplyMaterial(Material material, Mesh mesh)
- {
- if(material != display3D.material)
- {
- display3D.material = material;
- displaySystem.driver.ApplyMaterial(this, material, mesh);
- }
- }
- void DrawPrimitives(PrimitiveSingle primitive, Mesh mesh)
- {
- displaySystem.driver.DrawPrimitives(this, primitive, mesh);
- }
- void SelectMesh(Mesh mesh)
- {
- displaySystem.driver.SelectMesh(this, mesh);
- display3D.mesh = mesh;
- }
- bool DrawMesh(Object object)
- {
- bool result = false;
- if(display3D.selection)
- result = display3D.PickMesh(object, null);
- else
- {
- Mesh mesh = object.mesh;
- Material objectMaterial = object.material;
- if(mesh.groups.first)
- {
- PrimitiveGroup group;
- displaySystem.driver.SelectMesh(this, mesh);
- display3D.mesh = mesh;
- for(group = mesh.groups.first; group; group = group.next)
- {
- Material material = group.material ? group.material : objectMaterial;
- if(!material) material = defaultMaterial;
- if(material != display3D.material)
- {
- display3D.material = material;
- displaySystem.driver.ApplyMaterial(this, material, mesh);
- }
- // *** Render Vertex Arrays ***
- displaySystem.driver.DrawPrimitives(this, (PrimitiveSingle *)&group.type, mesh);
- }
- }
- if(object.flags.translucent)
- {
- Matrix matrix;
- Matrix inverse, inverseTranspose;
- int c;
-
- if(object.flags.viewSpace)
- matrix = object.matrix;
- else
- {
- Camera camera = display3D.camera;
- Matrix temp = object.matrix;
- temp.m[3][0] -= camera.cPosition.x;
- temp.m[3][1] -= camera.cPosition.y;
- temp.m[3][2] -= camera.cPosition.z;
- matrix.Multiply(temp, camera.viewMatrix);
- }
- inverse.Inverse(matrix);
- inverseTranspose.Transpose(inverse);
- for(c = 0; c < mesh.nPrimitives; c++)
- {
- PrimitiveSingle * triangle = &mesh.primitives[c];
- SortPrimitive * sort;
- Plane * plane = &triangle->plane;
- if(display3D.nTriangles >= display3D.maxTriangles)
- {
- display3D.maxTriangles = display3D.maxTriangles ? (display3D.maxTriangles * 3 / 2) : 32768;
- display3D.triangles = renew display3D.triangles SortPrimitive[display3D.maxTriangles];
- }
- sort = &display3D.triangles[display3D.nTriangles++];
- sort->object = object;
- sort->triangle = triangle;
- sort->middle.MultMatrix(triangle->middle, matrix);
- sort->middle.z *= -1;
- // sort->plane.MultMatrix(triangle->plane, inverseTranspose);
- sort->plane.d = plane->a * inverseTranspose.m[0][3] +
- plane->b * inverseTranspose.m[1][3] +
- plane->c * inverseTranspose.m[2][3] +
- plane->d * inverseTranspose.m[3][3];
- }
- }
- else
- {
- int c;
- displaySystem.driver.SelectMesh(this, mesh);
- display3D.mesh = mesh;
- for(c = 0; c<mesh.nPrimitives; c++)
- {
- PrimitiveSingle * primitive = &mesh.primitives[c];
- Material material = primitive->material ? primitive->material : objectMaterial;
- if(!material) material = defaultMaterial;
- if(material != display3D.material)
- {
- display3D.material = material;
- displaySystem.driver.ApplyMaterial(this, material, mesh);
- }
- displaySystem.driver.DrawPrimitives(this, primitive, display3D.mesh);
- }
- }
- result = true;
- }
- return result;
- }
- bool IsObjectVisible(Object object)
- {
- Plane * planes;
- if(display3D.selection || !display3D.camera)
- planes = object.flags.viewSpace ? display3D.viewPickingPlanes : display3D.worldPickingPlanes;
- else
- planes = object.flags.viewSpace ? display3D.camera.viewClippingPlanes : display3D.camera.worldClippingPlanes;
- return object.InsideFrustum(planes) != outside;
- }
- bool DrawObject(Object object)
- {
- bool result = false;
- if(object && object.volume)
- {
- Object child;
- FrustumPlacement visible;
- Plane * planes;
- Camera camera = display3D.camera;
- if(display3D.selection || !camera)
- planes = object.flags.viewSpace ? display3D.viewPickingPlanes : display3D.worldPickingPlanes;
- else
- planes = object.flags.viewSpace ? camera.viewClippingPlanes : camera.worldClippingPlanes;
-
- visible = object.InsideFrustum(planes);
- if(visible || display3D.pickingPlanes)
- {
- if(display3D.collectingHits && object.tag)
- {
- /*if(object.flags.root)
- this.tags[display3D.tagIndex] = object.tag;
- else if(object.tag)
- this.tags[++display3D.tagIndex] = object.tag;
- */
- display3D.tags[display3D.tagIndex++] = object.tag;
- }
- if(object.flags.mesh && object.mesh)
- {
- if(!display3D.selection && displaySystem.driver.PushMatrix)
- displaySystem.driver.PushMatrix(this);
- SetTransform(object.matrix, object.flags.viewSpace);
- if(display3D.selection)
- {
- if(visible == intersecting || display3D.intersecting)
- {
- Vector3D rayIntersect;
- if(display3D.PickMesh(object, rayIntersect))
- {
- if(display3D.intersecting)
- {
- Vector3D wresult, vresult;
- wresult.MultMatrix(rayIntersect, object.matrix);
- if(!object.flags.viewSpace)
- camera.TransformPoint(vresult, wresult);
- else
- vresult = wresult;
- if(vresult.z < display3D.rayIntersect.z)
- display3D.rayIntersect = vresult;
- display3D.intersected = true;
- }
- result = true;
- }
- }
- else
- result = true;
- }
- else
- {
- result |= DrawMesh(object);
- if(displaySystem.driver.PopMatrix)
- displaySystem.driver.PopMatrix(this, true);
- }
- if(display3D.collectingHits && result /*&& object.tag*/)
- {
- int c;
- HitRecord hit = (HitRecord)new0 byte[sizeof(class HitRecord) + sizeof(void *) * (display3D.tagIndex/*+1*/)];
- display3D.hitList.Add(hit);
- hit.pos = display3D.hitList.count-1;
- hit.numTags = display3D.tagIndex /*+ 1*/;
- for(c = 0; c</*=*/display3D.tagIndex; c++)
- {
- hit.tags[c] = display3D.tags[c];
- }
- if(!object.flags.viewSpace)
- camera.TransformPoint(hit.center, object.wcenter);
- else
- hit.center = object.wcenter;
- }
- }
- for(child = object.children.first; child; child = child.next)
- result |= DrawObject(child);
- if(display3D.collectingHits && /*!object.flags.root && */object.tag)
- display3D.tagIndex--;
- }
- }
- return result;
- }
- void DrawTranslucency(void)
- {
- if(display3D.camera)
- {
- // *** Render translucent primitives ***
- if(display3D.nTriangles)
- {
- Matrix * matrix = null;
- int c;
- blend = true;
- display3D.SortTriangles();
- depthWrite = false;
- displaySystem.driver.PushMatrix(this);
- for(c=0; c<display3D.nTriangles; c++)
- {
- SortPrimitive * sort = &display3D.triangles[c];
- Mesh mesh = sort->object.mesh;
- PrimitiveSingle * primitive = sort->triangle;
- Material material;
- if(&sort->object.matrix != matrix)
- {
- matrix = &sort->object.matrix;
- displaySystem.driver.PopMatrix(this, false);
- displaySystem.driver.PushMatrix(this);
- SetTransform(matrix, sort->object.flags.viewSpace);
- }
- if(mesh != display3D.mesh)
- {
- displaySystem.driver.SelectMesh(this, mesh);
- display3D.mesh = mesh;
- }
- material = primitive->material ? primitive->material : sort->object.material;
- if(!material) material = defaultMaterial;
- if(material != display3D.material)
- {
- displaySystem.driver.ApplyMaterial(this, material, display3D.mesh);
- display3D.material = material;
- }
- /*
- {
- Material testMaterial { };
- float amount;
- amount = (display3D.triangles[0].middle.z - display3D.triangles[c].middle.z) /
- (display3D.triangles[0].middle.z - display3D.triangles[display3D.nTriangles-1].middle.z);
- testMaterial.flags.doubleSided = { doubleSided = true, translucent = true };
- testMaterial.diffuse.a = 1;
- testMaterial.emissive.r = testMaterial.emissive.g = testMaterial.emissive.b = amount;
- testMaterial.baseMap = material->baseMap;
- displaySystem.driver.ApplyMaterial(this, testMaterial, display3D.mesh);
- }
- */
- // *** Render primitive ***
- // if(sort->plane.d > 0)
- displaySystem.driver.DrawPrimitives(this, primitive, display3D.mesh);
- }
- displaySystem.driver.PopMatrix(this, true);
- display3D.nTriangles = 0;
- blend = false;
- }
- }
- }
- // --- Picking ---
- void StartSelection(int pickX, int pickY, int pickW, int pickH)
- {
- if(!display3D)
- {
- display3D = Display3D { };
- }
- display3D.pickX = (float)pickX;
- display3D.pickY = (float)pickY;
- display3D.pickWidth = (float)pickW;
- display3D.pickHeight = (float)pickH;
- display3D.selection = true;
- }
- void CollectHits(void)
- {
- display3D.collectingHits = true;
- }
- int GetHits(OldList list)
- {
- display3D.collectingHits = false;
- display3D.hitList.Sort(HitRecord::Compare, null);
- list = display3D.hitList;
- display3D.hitList.Clear();
- return list.count;
- }
- void IntersectPolygons(void)
- {
- display3D.rayIntersect = { MAXFLOAT, MAXFLOAT, MAXFLOAT };
- display3D.intersected = false;
- display3D.intersecting = true;
- }
- bool GetIntersect(Vector3D intersect)
- {
- intersect = display3D.rayIntersect;
- display3D.intersecting = false;
- return display3D.intersected;
- }
- void StopSelection(void)
- {
- display3D.selection = false;
- }
- // --- Rendering States ---
- property FillModeValue fillMode { set { displaySystem.driver.SetRenderState(this, fillMode, value); } };
- property bool depthTest { set { displaySystem.driver.SetRenderState(this, depthTest, value); } };
- property bool depthWrite { set { displaySystem.driver.SetRenderState(this, depthWrite, value); } };
- property float fogDensity { set { displaySystem.driver.SetRenderState(this, fogDensity, *(uint *)(void *)&value); } };
- property Color fogColor { set { displaySystem.driver.SetRenderState(this, fogColor, value); } };
- property bool blend { set { displaySystem.driver.SetRenderState(this, blend, value); } };
- property Color ambient { set { displaySystem.driver.SetRenderState(this, ambient, value); } };
- property bool alphaWrite { set { displaySystem.driver.SetRenderState(this, alphaWrite, value); } };
- property bool antiAlias { set { displaySystem.driver.SetRenderState(this, antiAlias, value); } };
- property bool vSync { set { displaySystem.driver.SetRenderState(this, vSync, value); } };
- property bool pickingPlanes { set { display3D.pickingPlanes = value; } };
- #endif
- property DisplayFlags flags { get { return displaySystem.flags; } }
- property PixelFormat pixelFormat { get { return /*alphaBlend ? pixelFormat888 : */displaySystem.pixelFormat; } }
- property bool alphaBlend { set { alphaBlend = value; } get { return alphaBlend; } };
- property bool useSharedMemory { set { useSharedMemory = value; } get { return useSharedMemory; } };
- property void * systemWindow { get { return window; } };
- property DisplaySystem displaySystem { get { return displaySystem; } };
- int width, height;
- void * driverData;
- private:
- DisplaySystem displaySystem;
- void * window;
- Mutex mutex { };
- int current;
- #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
- Display3D display3D;
- #endif
- bool alphaBlend;
- void * windowDriverData;
- bool useSharedMemory;
- };
- #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
- private class Display3D
- {
- // 3D Display
- int nTriangles;
- SortPrimitive * triangles;
- int maxTriangles;
- Vector3D points[MAX_CLIP_POINTS];
- Vector3D newPoints[MAX_CLIP_POINTS];
- byte goodPoints[MAX_CLIP_POINTS];
- Material material;
- Mesh mesh;
- Camera camera;
- Plane viewPickingPlanes[ClippingPlane], worldPickingPlanes[ClippingPlane];
- Plane localPickingPlanes[ClippingPlane];
- bool collectingHits, selection, intersecting, intersected, pickingPlanes;
- float pickX, pickY, pickWidth, pickHeight;
- OldList hitList;
- void * tags[64];
- int tagIndex;
- Line rayView, rayWorld, rayLocal;
- Vector3D rayIntersect;
- ~Display3D()
- {
- delete triangles;
- }
- int _SetLights(Display display, Object object, int id)
- {
- if(id < NumberOfLights)
- {
- Object child;
- if(object.flags.light && !object.light.flags.off)
- display.SetLight(id++, object.light);
-
- for(child = object.children.first; child; child = child.next)
- {
- id = _SetLights(display, child, id);
- }
- }
- return id;
- }
- //#define TRESHOLD -1
- //#define TRESHOLD -0.25
- #define TRESHOLD -0.0025
- bool PickPrimitives(Mesh mesh, PrimitiveSingle primitive, Vector3D rayDiff, Vector3D rayIntersect)
- {
- Plane * planes = localPickingPlanes;
- int c = 0;
- int nIndex = 1, nPoints = 1;
- int offset = 0;
- bool result = false;
- Vector3D * points = this.points;
- Vector3D * newPoints = this.newPoints;
- byte * goodPoints = this.goodPoints;
- int nVertices = primitive.type.vertexRange ? primitive.nVertices : primitive.nIndices;
- int strip = 1;
- Vector3Df tmp;
- bool i32bit = primitive.type.indices32bit;
- uint32 * indices32 = primitive.indices;
- uint16 * indices16 = primitive.indices;
-
- switch(primitive.type.primitiveType)
- {
- case triangles: nIndex = 3; nPoints = 3; break;
- case quads: nIndex = 4; nPoints = 4; break;
- case triStrip:
- case triFan:
- nIndex = 1; nPoints = 3;
- offset = 2;
- tmp = primitive.type.vertexRange ? mesh.vertices[primitive.first] : mesh.vertices[(i32bit ? indices32[0] : indices16[0])];
- points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
- tmp = primitive.type.vertexRange ? mesh.vertices[primitive.first+1] : mesh.vertices[(i32bit ? indices32[1] : indices16[1])];
- points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
- break;
- }
-
- for(c = offset; c<nVertices; c += nIndex)
- {
- bool outside = false;
- if(!pickingPlanes)
- {
- int p;
- int n = nPoints;
- int i;
- if(primitive.type.vertexRange)
- {
- if(primitive.type.primitiveType == triStrip)
- {
- tmp = mesh.vertices[primitive.first + (c & 1) ? (c - 1) : (c - 2)];
- points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
- tmp = mesh.vertices[primitive.first + (c & 1) ? (c - 2) : (c - 1)];
- points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
- }
- else if(primitive.type.primitiveType == triFan)
- {
- tmp = mesh.vertices[primitive.first + 0];
- points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
- tmp = mesh.vertices[primitive.first + c - 1];
- points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
- }
- for(i = 0; i<nIndex; i++)
- {
- tmp = mesh.vertices[primitive.first + c+i];
- points[i + offset] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
- }
- }
- else
- {
- if(primitive.type.primitiveType == triStrip)
- {
- i = (c & 1) ? (c - 1) : (c - 2);
- tmp = mesh.vertices[(i32bit ? indices32[i] : indices16[i])];
- points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
- i = (c & 1) ? (c - 2) : (c - 1);
- tmp = mesh.vertices[(i32bit ? indices32[i] : indices16[i])];
- points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
- }
- else if(primitive.type.primitiveType == triFan)
- {
- tmp = mesh.vertices[(i32bit ? indices32[0] : indices16[0])];
- points[0] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
- tmp = mesh.vertices[(i32bit ? indices32[c-1] : indices16[c-1])];
- points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
- }
- for(i = 0; i<nIndex; i++)
- {
- tmp = mesh.vertices[(i32bit ? indices32[c+i] : indices16[c+i])];
- points[i + offset] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
- }
- }
- for(p = 0; p < 6; p++)
- {
- Plane * plane = &planes[p];
- int i;
- int numGoodPoints = 0;
-
- memset(goodPoints, 0, n);
- for(i = 0; i < n; i++)
- {
- double dot = plane->normal.DotProduct(points[i]);
- double distance = dot + plane->d;
- if(distance > TRESHOLD)
- {
- numGoodPoints++;
- goodPoints[i] = 1;
- }
- }
- if(!numGoodPoints)
- {
- outside = true;
- break;
- }
- if(numGoodPoints < n)
- {
- // Clip the polygon
- int newN = 0;
- int lastGood = -1;
- int j;
- for(j = 0; j<n; )
- {
- if(goodPoints[j])
- {
- newPoints[newN++] = points[j];
- lastGood = j++;
- }
- else
- {
- Line edge;
- int next;
- if(lastGood == -1)
- for(lastGood = n-1; !goodPoints[lastGood]; lastGood--);
- edge.p0 = points[lastGood];
- edge.delta.Subtract(points[j], edge.p0);
- plane->IntersectLine(edge, newPoints[newN++]);
- for(next = j+1; next != j; next++)
- {
- if(next == n) next = 0;
- if(goodPoints[next])
- {
- int prev = next - 1;
- if(prev < 0) prev = n-1;
- edge.p0 = points[prev];
- edge.delta.Subtract(points[next], edge.p0);
- plane->IntersectLine(edge, newPoints[newN++]);
- break;
- }
- }
- if(next <= j)
- break;
- else
- j = next;
- }
- }
- // Use the new points
- memcpy(points, newPoints, newN * sizeof(Vector3D));
- n = newN;
- }
- }
- }
- if(!outside)
- {
- result = true;
- // TODO: Implement intersection with TriStrip, TriFan...
- if(intersecting)
- {
- // Intersect primitives
- Plane plane;
- Vector3D intersect, diff;
- int i0 = c, i1 = c+1, i2 = c+2;
- if(primitive.type.primitiveType == triStrip)
- {
- i0 = (c & 1) ? (c - 1) : (c - 2);
- i1 = (c & 1) ? (c - 2) : (c - 1);
- i2 = c;
- }
- else if(primitive.type.primitiveType == triFan)
- {
- i0 = 0;
- i1 = c - 1;
- i2 = c;
- }
- if(primitive.type.vertexRange)
- plane.FromPointsf(
- mesh.vertices[primitive.first + i0],
- mesh.vertices[primitive.first + i1],
- mesh.vertices[primitive.first + i2]);
- else
- plane.FromPointsf(
- mesh.vertices[(i32bit ? indices32[i0] : indices16[i0])],
- mesh.vertices[(i32bit ? indices32[i1] : indices16[i1])],
- mesh.vertices[(i32bit ? indices32[i2] : indices16[i2])]);
- plane.IntersectLine(rayLocal, intersect);
- diff.Subtract(intersect, rayLocal.p0);
- diff.x /= rayLocal.delta.x;
- diff.y /= rayLocal.delta.y;
- diff.z /= rayLocal.delta.z;
- if(diff.x < rayDiff.x || diff.y < rayDiff.y || diff.z < rayDiff.z)
- {
- rayDiff = diff;
- rayIntersect = intersect;
- }
- }
- else
- break;
- }
- switch(primitive.type)
- {
- case triStrip:
- points[strip] = points[2];
- strip ^= 1;
- break;
- case triFan:
- points[1] = points[2];
- break;
- }
- }
- return result;
- }
- bool PickMesh(Object object, Vector3D rayIntersect)
- {
- Mesh mesh = object.mesh;
- bool result = false;
- Vector3D rayDiff { MAXFLOAT, MAXFLOAT, MAXFLOAT };
- if(rayIntersect != null)
- rayIntersect = { MAXFLOAT, MAXFLOAT, MAXFLOAT };
- if(mesh.groups.first)
- {
- PrimitiveGroup group;
- for(group = mesh.groups.first; group; group = group.next)
- {
- if(PickPrimitives(mesh, (PrimitiveSingle *)&group.type, rayDiff, rayIntersect))
- {
- result = true;
- if(!intersecting)
- break;
- }
- }
- }
- else
- {
- int c;
- for(c = 0; c < mesh.nPrimitives; c++)
- {
- if(PickPrimitives(mesh, mesh.primitives[c], rayDiff, rayIntersect))
- {
- result = true;
- if(!intersecting)
- break;
- }
- }
- }
- return result;
- }
- void SortTriangles(void)
- {
- Matrix matrix;
- Object object = null;
- int c;
- for(c=0; c<nTriangles; c++)
- {
- SortPrimitive * sort = &triangles[c];
- Mesh mesh = sort->object.mesh;
- PrimitiveSingle * primitive = sort->triangle;
- Vector3Df min { MAXFLOAT, MAXFLOAT, MAXFLOAT };
- Vector3Df max { -MAXFLOAT, -MAXFLOAT, -MAXFLOAT };
- int v;
- if(object != sort->object)
- {
- object = sort->object;
- if(object.flags.viewSpace)
- matrix = object.matrix;
- else
- {
- Camera camera = this.camera;
- Matrix temp = object.matrix;
- temp.m[3][0] -= camera.cPosition.x;
- temp.m[3][1] -= camera.cPosition.y;
- temp.m[3][2] -= camera.cPosition.z;
- matrix.Multiply(temp, camera.viewMatrix);
- }
- }
- for(v = 0; v<primitive->nIndices; v++)
- {
- Vector3Df * local = &mesh.vertices[primitive->indices[v]];
- Vector3Df vertex;
- vertex.MultMatrix(local, &matrix);
- if(vertex.x > max.x) max.x = vertex.x;
- if(vertex.y > max.y) max.y = vertex.y;
- if(vertex.z > max.z) max.z = vertex.z;
- if(vertex.x < min.x) min.x = vertex.x;
- if(vertex.y < min.y) min.y = vertex.y;
- if(vertex.z < min.z) min.z = vertex.z;
- }
- sort->min = min;
- sort->max = max;
- sort->marked = false;
- }
- /*
- Logf("========= Before Sort ==========\n");
- for(c=0; c<nTriangles; c++)
- {
- SortPrimitive * sort = &triangles[c];
- int v;
- Mesh mesh = sort->mesh;
- PrimitiveSingle * primitive = sort->triangle;
- Logf("Triangle %d (%s):\n", c, primitive->material->name);
- for(v = 0; v<primitive->nIndices; v++)
- {
- Vector3Df * local = &mesh.vertices[primitive->indices[v]];
- Vector3Df vertex;
- vertex.<MultMatrix(local, sort->matrix);
- Logf("Vertex %d:", v);
- // Logf(" Local %f, %f, %f:\n", local->x, local->y, local->z);
- Logf(" View %f, %f, %f:\n", vertex.x, vertex.y, vertex.z);
- }
- Logf("Min %f, %f, %f:\n", sort->min.x, sort->min.y, sort->min.z);
- Logf("Max %f, %f, %f:\n", sort->max.x, sort->max.y, sort->max.z);
- Logf("\n", c);
- }*/
- // *** Sort translucent primitives ***
- qsort((void*) triangles, nTriangles, sizeof(SortPrimitive), SortPrimitive::Compare);
- /*
- Logf("\n\n========= After Sort ==========\n");
- for(c=0; c<nTriangles; c++)
- {
- SortPrimitive * sort = &triangles[c];
- int v;
- Mesh mesh = sort->mesh;
- PrimitiveSingle * primitive = sort->triangle;
- Logf("Triangle %d (%s):\n", c, primitive->material->name);
- for(v = 0; v<primitive->nIndices; v++)
- {
- Vector3Df * local = &mesh.vertices[primitive->indices[v]];
- Vector3Df vertex;
- vertex.MultMatrix(local, sort->matrix);
- Logf("Vertex %d:", v);
- // Logf(" Local %f, %f, %f:\n", local->x, local->y, local->z);
- Logf(" View %f, %f, %f:\n", vertex.x, vertex.y, vertex.z);
- }
- Logf("Min %f, %f, %f:\n", sort->min.x, sort->min.y, sort->min.z);
- Logf("Max %f, %f, %f:\n", sort->max.x, sort->max.y, sort->max.z);
- Logf("\n", c);
- }
- */
- //exit(0);
- /*
- If all five tests fail for a particular Q,
- then P might obscure Q. Now Q must be tested.
- First, the algorithm checks if Q has been "marked."
- If Q is marked, then Q was "moved around" in the list
- during a previous iteration of the loop. The algorithm
- only allows a polygon to be moved once, to avoid the possibility
- of infinite loops. If Q is not marked, it is tested to see
- if it might obscure P. If Q cannot obscure P, then Q is possibly
- behind P and so it is good candidate to be drawn next.
- Therefore, the algorithm "abandons" the current P (that is, it
- stops testing Q's against the current P) and moves the current
- Q to the end of the list to become the next P.
- */
- /*
- {
- int p;
- for(p = 0; p<nTriangles; p++)
- {
- SortPrimitive * poly1 =