import "Vector3D"
#endif
+#if (!defined(ECERE_VANILLA) && !defined(ECERE_ONEDRIVER))
+import "OpenGLDisplayDriver"
+
+#define near _near
+#define far _far
+#include "gl123es.h"
+#undef near
+#undef far
+#endif
+
+public class GLCapabilities : uint
+{
+public:
+ // Expect reloading graphics
+ bool compatible :1;
+ bool vertexBuffer :1;
+ bool quads :1;
+ bool intAndDouble :1;
+ bool legacyFormats :1;
+ bool nonPow2Textures :1;
+ bool vertexPointer :1;
+
+ // Should be able to toggle without reloading
+ bool legacy :1;
+ bool shaders :1;
+ bool fixedFunction :1;
+ bool immediate :1;
+ bool frameBuffer :1;
+ bool pointSize :1;
+ bool vao :1;
+ bool select :1;
+ // bool mapBuffer :1;
+
+ bool debug :1;
+};
+
public enum RenderState { fillMode = 1, depthTest, depthWrite, fogDensity, fogColor, blend, ambient, alphaWrite, antiAlias, vSync };
+public union RenderStateFloat { float f; uint ui; };
+
public enum FillModeValue { solid, wireframe };
public class DisplayFlags
public bool bold:1, italic:1, underline:1;
};
-static void DummyFunction()
+__attribute__((unused)) static void DummyFunction()
{
- Mutex mutex { };
+#if !defined(__EMSCRIPTEN__)
+ Mutex { };
+#endif
}
public class DisplayDriver
{
public:
- class_data char * name;
+ class_data const char * name;
class_data bool textMode;
class_data bool printer;
class_data DisplaySystem displaySystem;
get { return class_data(displaySystem); }
};
- class_property char * name
+ class_property const char * name
{
set { class_data(name) = value; }
get { return class_data(name); }
virtual bool ::ConvertBitmap(DisplaySystem, Bitmap, PixelFormat, ColorAlpha *);
// Converts an LFB bitmap into an offscreen bitmap for this device
- virtual bool ::MakeDDBitmap(DisplaySystem, Bitmap, bool);
+ virtual bool ::MakeDDBitmap(DisplaySystem, Bitmap, bool mipMaps, int cubeMapFace);
// Font loading
- virtual Font ::LoadFont(DisplaySystem displaySystem, char * faceName, float size, FontFlags flags);
+ virtual Font ::LoadFont(DisplaySystem displaySystem, const char * faceName, float size, FontFlags flags, float outlineSize, float outlineFade);
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 ::LineStipple(Display, Surface, uint pattern);
+ virtual ColorAlpha ::GetPixel(Display, Surface, int x, int y);
+ virtual void ::PutPixel(Display, Surface, int x, int y);
+ virtual void ::DrawLine(Display, Surface, int x1, int y1, int x2, int y2);
+ virtual void ::Rectangle(Display, Surface, int x1, int y1, int x2, int y2);
+ virtual void ::Area(Display, Surface, int x1, int y1, int x2, int y2);
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 ::Blit(Display, Surface, Bitmap, int dx, int dy, int sx, int sy, int w, int h);
+ virtual void ::Stretch(Display, Surface, Bitmap, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh);
+ virtual void ::Filter(Display, Surface, Bitmap, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh);
+ virtual void ::BlitDI(Display, Surface, Bitmap, int dx, int dy, int sx, int sy, int w, int h);
+ virtual void ::StretchDI(Display, Surface, Bitmap, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh);
+ virtual void ::FilterDI(Display, Surface, Bitmap, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh);
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 ::WriteText(Display, Surface, int x, int y, const String text, int len, int prevGlyph, int * rPrevGlyph);
+ virtual void ::TextExtent(Display, Surface, const String text, int len, int * tw, int * th, int prevGlyph, int * rPrevGlyph, int * overHang);
+ virtual void ::FontExtent(DisplaySystem, Font, const String text, int len, int * tw, int * th, int prevGlyph, int * rPrevGlyph, int * overHang);
+ virtual void ::DrawingChar(Display, Surface, char ch);
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 bool ::AllocateMesh(DisplaySystem, Mesh, MeshFeatures, int nVertices);
virtual void ::FreeMesh(DisplaySystem, Mesh);
virtual bool ::LockMesh(DisplaySystem, Mesh, MeshFeatures flags);
virtual void ::UnlockMesh(DisplaySystem, Mesh, MeshFeatures flags);
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;
float multiplier;
};
-define NumberOfLights = 8;
+public define NumberOfLights = 8;
// Painter's algorithm
Surface GetSurface(int x, int y, Box clip)
{
Surface result = null;
- Surface surface { };
+ Surface surface { _refCount = 1 };
if(surface)
{
Box box { -x, -y, -x + width - 1, -y + height - 1 };
return result;
}
- void FontExtent(Font font, char * text, int len, int * width, int * height)
+ void FontExtent(Font font, const char * text, int len, int * width, int * height)
+ {
+ int overHang = 0;
+ FontExtent2(font, text, len, width, height, 0, null, &overHang);
+ if(width) *width += overHang;
+ }
+
+ void FontExtent2(Font font, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * overHang)
{
// Fix for OnLoadGraphics time alpha blended window text extent on GDI
#if defined(__WIN32__) && !defined(ECERE_NOTRUETYPE)
if(s)
{
s.font = font;
- s.TextExtent(text, len, width, height);
+ s.TextExtent2(text, len, width, height, prevGlyph, rPrevGlyph, overHang);
delete s;
}
}
else
#endif
// TODO: Should really pass display here...
- DisplaySystem::FontExtent(this ? displaySystem : null, font, text, len, width, height);
+ DisplaySystem::FontExtent2(this ? displaySystem : null, font, text, len, width, height, prevGlyph, rPrevGlyph, overHang);
}
void SetPalette(ColorAlpha * palette, bool colorMatch)
result = displaySystem && displaySystem.Lock();
if(result && render)
{
+#if !defined(__EMSCRIPTEN__)
mutex.Wait();
+#endif
if(!current)
result = displaySystem.driver.Lock(this);
*/
if(!current && displaySystem)
displaySystem.driver.Unlock(this);
+#if !defined(__EMSCRIPTEN__)
mutex.Release();
+#endif
}
if(displaySystem)
displaySystem.Unlock();
camera.Setup(width, height, null);
// Always calling Update() here had broken interpolation in OrbitWithMouse!
- if(!camera.cAngle.w)
+ if(!camera.cAngle.w && surface)
camera.Update();
if(display3D.selection)
// --- Lights ---
void SetLight(int id, Light light)
{
+ if(!display3D)
+ {
+ display3D = Display3D { };
+ }
displaySystem.driver.SetLight(this, id, light);
}
if(!display3D.selection && displaySystem.driver.PushMatrix)
displaySystem.driver.PushMatrix(this);
+#if ENABLE_GL_FFP
+ if(object.mesh.tangents && object.mesh.normals && object.flags.computeLightVectors)
+ {
+ Mesh mesh = object.mesh;
+ if(!glCaps_shaders)
+ {
+ int count = mesh.nVertices;
+ Vector3Df * normals = mesh.normals;
+ Vector3Df * vertices = mesh.vertices;
+ ColorRGB * lightVectors;
+ Vector3Df * tangents = mesh.tangents;
+ int i;
+ float * l = display3D.light0Pos;
+ Vector3Df light { l[0], l[1], l[2] };
+ Matrix o = object.matrix;
+ Matrix t, inv = camera.viewMatrix;
+ Vector3D ot { };
+ Vector3D cPos = camera.cPosition;
+ Vector3D pos;
+ bool positional = l[3] ? true : false;
+
+ inv.Scale(1.0/nearPlane, -1.0/nearPlane,-1.0/nearPlane);
+
+ pos.MultMatrix(cPos, camera.viewMatrix);
+
+ ot.x = o.m[3][0] + pos.x;
+ ot.y = o.m[3][1] + pos.y;
+ ot.z = o.m[3][2] + pos.z;
+ o.m[3][0] = 0;
+ o.m[3][1] = 0;
+ o.m[3][2] = 0;
+ t.Multiply(o, inv);
+ inv = t;
+ t.Transpose(inv);
+ inv.Inverse(t);
+
+ mesh.Allocate({ lightVectors = true }, mesh.nVertices, displaySystem);
+ mesh.Lock({ lightVectors = true });
+ lightVectors = mesh.lightVectors;
+ for(i = 0; i < count; i++)
+ {
+ Vector3Df tangent1 = tangents[i*2 + 0];
+ Vector3Df tangent2 = tangents[i*2 + 1];
+ Vector3Df normal = normals[i];
+ Vector3Df tTangent1, tTangent2, tNormal;
+
+ tTangent1.MultMatrix(tangent1, inv);
+ tTangent2.MultMatrix(tangent2, inv);
+ tNormal .MultMatrix(normal, inv);
+
+ tTangent1.Normalize(tTangent1);
+ tTangent2.Normalize(tTangent2);
+ tNormal .Normalize(tNormal);
+
+ {
+ Matrix tbn
+ { {
+ tTangent1.x, tTangent2.x, tNormal.x, 0,
+ tTangent1.y, tTangent2.y, tNormal.y, 0,
+ tTangent1.z, tTangent2.z, tNormal.z, 1
+ } };
+ Vector3Df n;
+ if(positional)
+ {
+ Vector3Df tPos = vertices[i];
+ tPos.x += ot.x, tPos.y += ot.y, tPos.z += ot.z;
+
+ // Subtract vertex from light for positional lights
+ light.x = l[0] - tPos.x;
+ light.y = l[1] + tPos.y;
+ light.z = l[2] - tPos.z;
+ }
+ n.MultMatrix(light, tbn);
+ if(positional)
+ n.Normalize(n);
+ lightVectors[i] = { n.x / 2 + 0.5f, n.y / 2 + 0.5f, n.z / 2 + 0.5f };
+ }
+ }
+ mesh.Unlock({ lightVectors = true });
+
+ // Create normalization cube map
+ /*
+ if(!mesh.normMap)
+ mesh.normMap = { };
+ {
+ int w = 256, h = 256, d = 256;
+ Vector3Df min = mesh.min, max = mesh.max;
+ Vector3Df delta
+ {
+ (max.x - min.x) / w,
+ (max.y - min.y) / h,
+ (max.z - min.z) / d
+ };
+ int i;
+ for(i = 0; i < 6; i++)
+ {
+ Bitmap face = i > 0 ? { } : mesh.normMap;
+ int x, y;
+ ColorAlpha * p;
+ face.Free();
+ face.Allocate(null, w, h, 0, pixelFormat888, false);
+ face.driverData = mesh.normMap.driverData;
+ p = (ColorAlpha *)face.picture;
+ for(y = 0; y < h; y++)
+ {
+ for(x = 0; x < w; x++, p++)
+ {
+ Vector3Df v { min.x + x * delta.x, min.y + y * delta.y, min.z };
+ v.Normalize(v);
+ *p = ColorAlpha { 255, {
+ (byte)((v.x / 2.0 + 0.5) * 255),
+ (byte)((v.y / 2.0 + 0.5) * 255),
+ (byte)((v.z / 2.0 + 0.5) * 255) } };
+ }
+ }
+ displaySystem.driver.MakeDDBitmap(displaySystem, face, true, (i + 1));
+ if(i > 0)
+ {
+ face.driverData = 0;
+ delete face;
+ }
+ }
+ }
+ */
+ }
+ else
+ mesh.Free({ lightVectors = true });
+ }
+#endif
+
SetTransform(object.matrix, object.flags.viewSpace);
if(display3D.selection)
{
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 float fogDensity { set { displaySystem.driver.SetRenderState(this, fogDensity, RenderStateFloat { value }.ui); } };
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 useSharedMemory { set { useSharedMemory = value; } get { return useSharedMemory; } };
property void * systemWindow { get { return window; } };
property DisplaySystem displaySystem { get { return displaySystem; } };
+#ifndef ECERE_VANILLA
+ property GLCapabilities glCapabilities
+ {
+ get { return ((OGLDisplay)driverData).capabilities; }
+ set
+ {
+ glCapabilities = value;
+ if(driverData && displaySystem.driver == class(OpenGLDisplayDriver))
+ {
+ OGLDisplay oglDisplay = driverData;
+ if(!oglDisplay.originalCapabilities.fixedFunction)
+ value.shaders = true;
+ if(!oglDisplay.originalCapabilities.shaders)
+ value.fixedFunction = true;
+ // Disable things that don't work with shaders
+ if(value.shaders)
+ {
+ value.fixedFunction = false;
+ value.legacy = false;
+ value.immediate = false;
+ }
+ oglDisplay.capabilities = oglDisplay.originalCapabilities & value;
+
+ Lock(true);
+ OpenGLDisplayDriver::initialDisplaySetup(this, true, false);
+ Unlock();
+ }
+ }
+ };
+#endif
int width, height;
void * driverData;
DisplaySystem displaySystem;
void * window;
+#if !defined(__EMSCRIPTEN__)
Mutex mutex { };
+#endif
int current;
#if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
bool alphaBlend;
void * windowDriverData;
bool useSharedMemory;
+ GLCapabilities glCapabilities;
+ glCapabilities = { true, true, true, true, true, true, true, true };
};
#if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
-private class Display3D
+private class Display3D : struct
{
// 3D Display
int nTriangles;
Line rayView, rayWorld, rayLocal;
Vector3D rayIntersect;
+ float light0Pos[4];
~Display3D()
{
int strip = 1;
Vector3Df tmp;
bool i32bit = primitive.type.indices32bit;
- uint32 * indices32 = primitive.indices;
+ uint32 * indices32 = primitive.indices32;
uint16 * indices16 = primitive.indices;
switch(primitive.type.primitiveType)
Vector3Df min { MAXFLOAT, MAXFLOAT, MAXFLOAT };
Vector3Df max { -MAXFLOAT, -MAXFLOAT, -MAXFLOAT };
int v;
+ bool ix32 = primitive->type.indices32bit;
if(object != sort->object)
{
object = sort->object;
for(v = 0; v<primitive->nIndices; v++)
{
- Vector3Df * local = &mesh.vertices[primitive->indices[v]];
+ Vector3Df * local = &mesh.vertices[ix32 ? primitive->indices32[v] : primitive->indices[v]];
Vector3Df vertex;
vertex.MultMatrix(local, &matrix);
};
#endif
-bool IsDriverTextMode(char * driverName)
+bool IsDriverTextMode(const char * driverName)
{
subclass(DisplayDriver) driver = GetDisplayDriver(driverName);
return driver ? driver.textMode : false;
}
-bool IsDriverPrinter(char * driverName)
+bool IsDriverPrinter(const char * driverName)
{
subclass(DisplayDriver) driver = GetDisplayDriver(driverName);
return driver ? driver.printer : false;
}
return best;
}
+
+// had to move this here due to compiler ordering issue for "get property" symbol
+subclass(DisplayDriver) GetDisplayDriver(const 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(const char * driverName)
+{
+ subclass(DisplayDriver) displayDriver = GetDisplayDriver(driverName);
+ return displayDriver ? displayDriver.displaySystem : null;
+}