mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-17 19:23:51 +02:00
Doom 3 RTX Initial Checkin.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
static const UINT QD3D12_ARB_MAX_PROGRAM_PARAMETERS = 128;
|
||||
static const UINT QD3D12_ARB_MAX_VERTEX_ATTRIBS = 16;
|
||||
static const UINT QD3D12_ARB_MAX_TEXTURE_UNITS = 8;
|
||||
|
||||
struct QD3D12ARBDrawConstantArrays
|
||||
{
|
||||
float env[QD3D12_ARB_MAX_PROGRAM_PARAMETERS][4];
|
||||
float vertexLocal[QD3D12_ARB_MAX_PROGRAM_PARAMETERS][4];
|
||||
float fragmentLocal[QD3D12_ARB_MAX_PROGRAM_PARAMETERS][4];
|
||||
};
|
||||
|
||||
|
||||
void QD3D12ARB_Init(void);
|
||||
void QD3D12ARB_Shutdown(void);
|
||||
void QD3D12ARB_DeviceLost(void);
|
||||
|
||||
void QD3D12ARB_SetEnabled(GLenum cap, bool enabled);
|
||||
bool QD3D12ARB_IsVertexEnabled(void);
|
||||
bool QD3D12ARB_IsFragmentEnabled(void);
|
||||
bool QD3D12ARB_IsActive(void);
|
||||
|
||||
GLuint QD3D12ARB_GetBoundVertexProgram(void);
|
||||
GLuint QD3D12ARB_GetBoundFragmentProgram(void);
|
||||
uint32_t QD3D12ARB_GetBoundVertexRevision(void);
|
||||
uint32_t QD3D12ARB_GetBoundFragmentRevision(void);
|
||||
|
||||
ID3DBlob* QD3D12ARB_GetVertexShaderBlob(void);
|
||||
ID3DBlob* QD3D12ARB_GetFragmentShaderBlob(void);
|
||||
void QD3D12ARB_FillDrawConstantArrays(QD3D12ARBDrawConstantArrays* outArrays);
|
||||
|
||||
GLenum QD3D12ARB_ConsumeError(void);
|
||||
GLint QD3D12ARB_GetProgramErrorPosition(void);
|
||||
const char* QD3D12ARB_GetProgramErrorString(void);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,222 @@
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include "tess/tess.h"
|
||||
|
||||
struct GLVertex
|
||||
{
|
||||
float px, py, pz;
|
||||
float nx, ny, nz;
|
||||
float u0, v0;
|
||||
float u1, v1;
|
||||
float r, g, b, a;
|
||||
};
|
||||
|
||||
struct TessVertex
|
||||
{
|
||||
GLdouble coords[3];
|
||||
GLVertex vtx;
|
||||
};
|
||||
|
||||
struct TessContext
|
||||
{
|
||||
std::vector<GLVertex>* out = nullptr;
|
||||
std::vector<TessVertex*>* allocated = nullptr;
|
||||
|
||||
GLenum currentPrim = 0;
|
||||
std::vector<GLVertex> primVerts;
|
||||
|
||||
bool failed = false;
|
||||
};
|
||||
|
||||
static void TessBeginCB(GLenum type, void* userData)
|
||||
{
|
||||
TessContext* ctx = reinterpret_cast<TessContext*>(userData);
|
||||
ctx->currentPrim = type;
|
||||
ctx->primVerts.clear();
|
||||
}
|
||||
|
||||
static void TessEndCB(void* userData)
|
||||
{
|
||||
TessContext* ctx = reinterpret_cast<TessContext*>(userData);
|
||||
|
||||
if (ctx->failed)
|
||||
return;
|
||||
|
||||
switch (ctx->currentPrim)
|
||||
{
|
||||
case GL_TRIANGLES:
|
||||
if ((ctx->primVerts.size() % 3) != 0)
|
||||
{
|
||||
ctx->failed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ctx->primVerts.size(); i += 3)
|
||||
{
|
||||
ctx->out->push_back(ctx->primVerts[i + 0]);
|
||||
ctx->out->push_back(ctx->primVerts[i + 1]);
|
||||
ctx->out->push_back(ctx->primVerts[i + 2]);
|
||||
}
|
||||
break;
|
||||
|
||||
case GL_TRIANGLE_FAN:
|
||||
if (ctx->primVerts.size() < 3)
|
||||
break;
|
||||
|
||||
for (size_t i = 1; i + 1 < ctx->primVerts.size(); ++i)
|
||||
{
|
||||
ctx->out->push_back(ctx->primVerts[0]);
|
||||
ctx->out->push_back(ctx->primVerts[i]);
|
||||
ctx->out->push_back(ctx->primVerts[i + 1]);
|
||||
}
|
||||
break;
|
||||
|
||||
case GL_TRIANGLE_STRIP:
|
||||
if (ctx->primVerts.size() < 3)
|
||||
break;
|
||||
|
||||
for (size_t i = 0; i + 2 < ctx->primVerts.size(); ++i)
|
||||
{
|
||||
if ((i & 1) == 0)
|
||||
{
|
||||
ctx->out->push_back(ctx->primVerts[i + 0]);
|
||||
ctx->out->push_back(ctx->primVerts[i + 1]);
|
||||
ctx->out->push_back(ctx->primVerts[i + 2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->out->push_back(ctx->primVerts[i + 1]);
|
||||
ctx->out->push_back(ctx->primVerts[i + 0]);
|
||||
ctx->out->push_back(ctx->primVerts[i + 2]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ctx->failed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
ctx->primVerts.clear();
|
||||
ctx->currentPrim = 0;
|
||||
}
|
||||
|
||||
static void TessErrorCB(GLenum errorCode, void* userData)
|
||||
{
|
||||
(void)errorCode;
|
||||
TessContext* ctx = reinterpret_cast<TessContext*>(userData);
|
||||
ctx->failed = true;
|
||||
}
|
||||
|
||||
static void TessVertexCB(void* vertexData, void* userData)
|
||||
{
|
||||
TessContext* ctx = reinterpret_cast<TessContext*>(userData);
|
||||
TessVertex* tv = reinterpret_cast<TessVertex*>(vertexData);
|
||||
|
||||
if (!tv)
|
||||
{
|
||||
ctx->failed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->primVerts.push_back(tv->vtx);
|
||||
}
|
||||
|
||||
static void TessCombineCB(GLdouble newVertex[3],
|
||||
void* neighborData[4],
|
||||
GLfloat neighborWeight[4],
|
||||
void** outData,
|
||||
void* userData)
|
||||
{
|
||||
TessContext* ctx = reinterpret_cast<TessContext*>(userData);
|
||||
|
||||
TessVertex* nv = new TessVertex{};
|
||||
nv->coords[0] = newVertex[0];
|
||||
nv->coords[1] = newVertex[1];
|
||||
nv->coords[2] = newVertex[2];
|
||||
|
||||
std::memset(&nv->vtx, 0, sizeof(nv->vtx));
|
||||
nv->vtx.px = static_cast<float>(newVertex[0]);
|
||||
nv->vtx.py = static_cast<float>(newVertex[1]);
|
||||
nv->vtx.pz = static_cast<float>(newVertex[2]);
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if (!neighborData[i])
|
||||
continue;
|
||||
|
||||
TessVertex* src = reinterpret_cast<TessVertex*>(neighborData[i]);
|
||||
const float w = neighborWeight[i];
|
||||
|
||||
nv->vtx.nx += src->vtx.nx * w;
|
||||
nv->vtx.ny += src->vtx.ny * w;
|
||||
nv->vtx.nz += src->vtx.nz * w;
|
||||
|
||||
nv->vtx.u0 += src->vtx.u0 * w;
|
||||
nv->vtx.v0 += src->vtx.v0 * w;
|
||||
nv->vtx.u1 += src->vtx.u1 * w;
|
||||
nv->vtx.v1 += src->vtx.v1 * w;
|
||||
|
||||
nv->vtx.r += src->vtx.r * w;
|
||||
nv->vtx.g += src->vtx.g * w;
|
||||
nv->vtx.b += src->vtx.b * w;
|
||||
nv->vtx.a += src->vtx.a * w;
|
||||
}
|
||||
|
||||
ctx->allocated->push_back(nv);
|
||||
*outData = nv;
|
||||
}
|
||||
|
||||
void TessellatePolygon(const std::vector<GLVertex>& src, std::vector<GLVertex>& out)
|
||||
{
|
||||
out.clear();
|
||||
|
||||
if (src.size() < 3)
|
||||
return;
|
||||
|
||||
GLUtesselator* tess = gluNewTess();
|
||||
if (!tess)
|
||||
return;
|
||||
|
||||
std::vector<TessVertex*> allocated;
|
||||
allocated.reserve(src.size() + 8);
|
||||
|
||||
TessContext ctx;
|
||||
ctx.out = &out;
|
||||
ctx.allocated = &allocated;
|
||||
|
||||
gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
|
||||
gluTessProperty(tess, GLU_TESS_BOUNDARY_ONLY, GL_FALSE);
|
||||
|
||||
gluTessCallback(tess, GLU_TESS_BEGIN_DATA, (_GLUfuncptr)&TessBeginCB);
|
||||
gluTessCallback(tess, GLU_TESS_END_DATA, (_GLUfuncptr)&TessEndCB);
|
||||
gluTessCallback(tess, GLU_TESS_ERROR_DATA, (_GLUfuncptr)&TessErrorCB);
|
||||
gluTessCallback(tess, GLU_TESS_VERTEX_DATA, (_GLUfuncptr)&TessVertexCB);
|
||||
gluTessCallback(tess, GLU_TESS_COMBINE_DATA, (_GLUfuncptr)&TessCombineCB);
|
||||
|
||||
gluTessBeginPolygon(tess, &ctx);
|
||||
gluTessBeginContour(tess);
|
||||
|
||||
for (const GLVertex& v : src)
|
||||
{
|
||||
TessVertex* tv = new TessVertex{};
|
||||
tv->coords[0] = static_cast<GLdouble>(v.px);
|
||||
tv->coords[1] = static_cast<GLdouble>(v.py);
|
||||
tv->coords[2] = static_cast<GLdouble>(v.pz);
|
||||
tv->vtx = v;
|
||||
|
||||
allocated.push_back(tv);
|
||||
gluTessVertex(tess, tv->coords, tv);
|
||||
}
|
||||
|
||||
gluTessEndContour(tess);
|
||||
gluTessEndPolygon(tess);
|
||||
|
||||
gluDeleteTess(tess);
|
||||
|
||||
for (TessVertex* p : allocated)
|
||||
delete p;
|
||||
|
||||
if (ctx.failed)
|
||||
out.clear();
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
#include "opengl.h"
|
||||
|
||||
// Your D3D12 wrapper exports
|
||||
extern bool QD3D12_InitForQuakeWindow(struct QD3D12Window* window, HWND hwnd, int width, int height, bool fastPath);
|
||||
extern void QD3D12_ShutdownForQuake(void);
|
||||
extern void QD3D12_BeginFrame();
|
||||
void APIENTRY glSelectTextureSGIS(GLenum texture);
|
||||
void APIENTRY glMTexCoord2fSGIS(GLenum texture, GLfloat s, GLfloat t);
|
||||
void APIENTRY glActiveTextureARB(GLenum texture);
|
||||
void APIENTRY glMultiTexCoord2fARB(GLenum texture, GLfloat s, GLfloat t);
|
||||
void QD3D12_Resize();
|
||||
|
||||
void QD3D12_Present();
|
||||
void QD3D12_EndFrame();
|
||||
void QD3D12_CollectRetiredResources();
|
||||
|
||||
// Existing GL wrapper function from your compatibility layer
|
||||
void APIENTRY glBindTexture(unsigned int target, unsigned int texture);
|
||||
|
||||
void QD3D12_SetCurrentWindow(struct QD3D12Window* window);
|
||||
|
||||
struct QD3D12FakeContext
|
||||
{
|
||||
HDC dc;
|
||||
HWND hwnd;
|
||||
bool initialized;
|
||||
struct QD3D12Window* window;
|
||||
};
|
||||
|
||||
static QD3D12FakeContext* g_currentContext = nullptr;
|
||||
static HDC g_currentDC = nullptr;
|
||||
|
||||
struct QD3D12Window* AllocD3D12Window();
|
||||
void FreeD3D12Window(struct QD3D12Window* wnd);
|
||||
|
||||
static void QD3D12_GetClientSize(HWND hwnd, int& w, int& h)
|
||||
{
|
||||
RECT rc = {};
|
||||
GetClientRect(hwnd, &rc);
|
||||
w = rc.right - rc.left;
|
||||
h = rc.bottom - rc.top;
|
||||
|
||||
if (w <= 0) w = 640;
|
||||
if (h <= 0) h = 480;
|
||||
}
|
||||
|
||||
QD3D12_HGLRC WINAPI qd3d12_wglCreateContext(HDC hdc)
|
||||
{
|
||||
if (!hdc)
|
||||
return nullptr;
|
||||
|
||||
HWND hwnd = WindowFromDC(hdc);
|
||||
if (!hwnd)
|
||||
return nullptr;
|
||||
|
||||
QD3D12FakeContext* ctx = new QD3D12FakeContext();
|
||||
ctx->dc = hdc;
|
||||
ctx->hwnd = hwnd;
|
||||
ctx->initialized = false;
|
||||
ctx->window = AllocD3D12Window();
|
||||
return (QD3D12_HGLRC)ctx;
|
||||
}
|
||||
|
||||
BOOL WINAPI qd3d12_wglMakeCurrent(HDC hdc, QD3D12_HGLRC hglrc)
|
||||
{
|
||||
static bool basicInitDone = false;
|
||||
|
||||
if (!hdc || !hglrc)
|
||||
{
|
||||
g_currentDC = nullptr;
|
||||
g_currentContext = nullptr;
|
||||
QD3D12_SetCurrentWindow(NULL);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
QD3D12FakeContext* ctx = (QD3D12FakeContext*)hglrc;
|
||||
ctx->dc = hdc;
|
||||
|
||||
|
||||
int w = 640, h = 480;
|
||||
QD3D12_GetClientSize(ctx->hwnd, w, h);
|
||||
|
||||
if (!ctx->initialized)
|
||||
{
|
||||
if (!QD3D12_InitForQuakeWindow(ctx->window, ctx->hwnd, w, h, basicInitDone))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
if (!basicInitDone)
|
||||
{
|
||||
if(!glRaytracingInit())
|
||||
return FALSE;
|
||||
|
||||
if (!glRaytracingLightingInit())
|
||||
return FALSE;
|
||||
|
||||
basicInitDone = true;
|
||||
|
||||
QD3D12_BeginFrame();
|
||||
}
|
||||
|
||||
if (ctx->initialized) {
|
||||
// glFinish();
|
||||
QD3D12_EndFrame();
|
||||
}
|
||||
|
||||
g_currentDC = hdc;
|
||||
g_currentContext = ctx;
|
||||
|
||||
QD3D12_SetCurrentWindow(ctx->window);
|
||||
QD3D12_Resize();
|
||||
|
||||
if (ctx->initialized) {
|
||||
QD3D12_BeginFrame();
|
||||
QD3D12_CollectRetiredResources();
|
||||
}
|
||||
|
||||
ctx->initialized = true;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
HDC WINAPI qd3d12_wglGetCurrentDC(void)
|
||||
{
|
||||
return g_currentDC;
|
||||
}
|
||||
|
||||
QD3D12_HGLRC WINAPI qd3d12_wglGetCurrentContext(void)
|
||||
{
|
||||
return (QD3D12_HGLRC)g_currentContext;
|
||||
}
|
||||
|
||||
BOOL WINAPI qd3d12_wglDeleteContext(QD3D12_HGLRC hglrc)
|
||||
{
|
||||
if (!hglrc)
|
||||
return FALSE;
|
||||
|
||||
QD3D12FakeContext* ctx = (QD3D12FakeContext*)hglrc;
|
||||
|
||||
if (ctx == g_currentContext)
|
||||
{
|
||||
if (ctx->initialized)
|
||||
QD3D12_ShutdownForQuake();
|
||||
|
||||
g_currentContext = nullptr;
|
||||
g_currentDC = nullptr;
|
||||
}
|
||||
|
||||
FreeD3D12Window(ctx->window);
|
||||
|
||||
delete ctx;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void APIENTRY glBindTextureEXT(unsigned int target, unsigned int texture)
|
||||
{
|
||||
glBindTexture(target, texture);
|
||||
}
|
||||
|
||||
int WINAPI qd3d12_wglDescribePixelFormat(HDC hdc, int iPixelFormat, UINT nBytes, LPPIXELFORMATDESCRIPTOR ppfd) {
|
||||
return DescribePixelFormat(hdc, iPixelFormat, nBytes, ppfd);
|
||||
}
|
||||
|
||||
BOOL WINAPI qd3d12_wglSetPixelFormat(HDC hdc, int format, const PIXELFORMATDESCRIPTOR* ppfd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL WINAPI qd3d12_wglSwapIntervalEXT(int interval) {
|
||||
(void)interval;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL WINAPI qd3d12_wglGetDeviceGammaRamp3DFX(HDC hdc, LPVOID ramp) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINAPI qd3d12_wglSetDeviceGammaRamp3DFX(HDC hdc, LPVOID ramp) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
__declspec(dllexport) BOOL WINAPI wglUseFontBitmapsA(HDC, DWORD, DWORD, DWORD) { return FALSE; }
|
||||
__declspec(dllexport) BOOL WINAPI wglUseFontBitmapsW(HDC, DWORD, DWORD, DWORD) { return FALSE; }
|
||||
@@ -0,0 +1,254 @@
|
||||
// glu.cpp
|
||||
//
|
||||
|
||||
#include "opengl.h"
|
||||
|
||||
static void qgluMultMatrixd(const GLdouble a[16], const GLdouble b[16], GLdouble r[16])
|
||||
{
|
||||
for (int col = 0; col < 4; ++col)
|
||||
{
|
||||
for (int row = 0; row < 4; ++row)
|
||||
{
|
||||
r[col * 4 + row] =
|
||||
a[0 * 4 + row] * b[col * 4 + 0] +
|
||||
a[1 * 4 + row] * b[col * 4 + 1] +
|
||||
a[2 * 4 + row] * b[col * 4 + 2] +
|
||||
a[3 * 4 + row] * b[col * 4 + 3];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void qgluMultMatrixVecd(const GLdouble m[16], const GLdouble in[4], GLdouble out[4])
|
||||
{
|
||||
out[0] = m[0] * in[0] + m[4] * in[1] + m[8] * in[2] + m[12] * in[3];
|
||||
out[1] = m[1] * in[0] + m[5] * in[1] + m[9] * in[2] + m[13] * in[3];
|
||||
out[2] = m[2] * in[0] + m[6] * in[1] + m[10] * in[2] + m[14] * in[3];
|
||||
out[3] = m[3] * in[0] + m[7] * in[1] + m[11] * in[2] + m[15] * in[3];
|
||||
}
|
||||
|
||||
static int qgluInvertMatrixd(const GLdouble m[16], GLdouble invOut[16])
|
||||
{
|
||||
GLdouble inv[16];
|
||||
|
||||
inv[0] = m[5] * m[10] * m[15] -
|
||||
m[5] * m[11] * m[14] -
|
||||
m[9] * m[6] * m[15] +
|
||||
m[9] * m[7] * m[14] +
|
||||
m[13] * m[6] * m[11] -
|
||||
m[13] * m[7] * m[10];
|
||||
|
||||
inv[4] = -m[4] * m[10] * m[15] +
|
||||
m[4] * m[11] * m[14] +
|
||||
m[8] * m[6] * m[15] -
|
||||
m[8] * m[7] * m[14] -
|
||||
m[12] * m[6] * m[11] +
|
||||
m[12] * m[7] * m[10];
|
||||
|
||||
inv[8] = m[4] * m[9] * m[15] -
|
||||
m[4] * m[11] * m[13] -
|
||||
m[8] * m[5] * m[15] +
|
||||
m[8] * m[7] * m[13] +
|
||||
m[12] * m[5] * m[11] -
|
||||
m[12] * m[7] * m[9];
|
||||
|
||||
inv[12] = -m[4] * m[9] * m[14] +
|
||||
m[4] * m[10] * m[13] +
|
||||
m[8] * m[5] * m[14] -
|
||||
m[8] * m[6] * m[13] -
|
||||
m[12] * m[5] * m[10] +
|
||||
m[12] * m[6] * m[9];
|
||||
|
||||
inv[1] = -m[1] * m[10] * m[15] +
|
||||
m[1] * m[11] * m[14] +
|
||||
m[9] * m[2] * m[15] -
|
||||
m[9] * m[3] * m[14] -
|
||||
m[13] * m[2] * m[11] +
|
||||
m[13] * m[3] * m[10];
|
||||
|
||||
inv[5] = m[0] * m[10] * m[15] -
|
||||
m[0] * m[11] * m[14] -
|
||||
m[8] * m[2] * m[15] +
|
||||
m[8] * m[3] * m[14] +
|
||||
m[12] * m[2] * m[11] -
|
||||
m[12] * m[3] * m[10];
|
||||
|
||||
inv[9] = -m[0] * m[9] * m[15] +
|
||||
m[0] * m[11] * m[13] +
|
||||
m[8] * m[1] * m[15] -
|
||||
m[8] * m[3] * m[13] -
|
||||
m[12] * m[1] * m[11] +
|
||||
m[12] * m[3] * m[9];
|
||||
|
||||
inv[13] = m[0] * m[9] * m[14] -
|
||||
m[0] * m[10] * m[13] -
|
||||
m[8] * m[1] * m[14] +
|
||||
m[8] * m[2] * m[13] +
|
||||
m[12] * m[1] * m[10] -
|
||||
m[12] * m[2] * m[9];
|
||||
|
||||
inv[2] = m[1] * m[6] * m[15] -
|
||||
m[1] * m[7] * m[14] -
|
||||
m[5] * m[2] * m[15] +
|
||||
m[5] * m[3] * m[14] +
|
||||
m[13] * m[2] * m[7] -
|
||||
m[13] * m[3] * m[6];
|
||||
|
||||
inv[6] = -m[0] * m[6] * m[15] +
|
||||
m[0] * m[7] * m[14] +
|
||||
m[4] * m[2] * m[15] -
|
||||
m[4] * m[3] * m[14] -
|
||||
m[12] * m[2] * m[7] +
|
||||
m[12] * m[3] * m[6];
|
||||
|
||||
inv[10] = m[0] * m[5] * m[15] -
|
||||
m[0] * m[7] * m[13] -
|
||||
m[4] * m[1] * m[15] +
|
||||
m[4] * m[3] * m[13] +
|
||||
m[12] * m[1] * m[7] -
|
||||
m[12] * m[3] * m[5];
|
||||
|
||||
inv[14] = -m[0] * m[5] * m[14] +
|
||||
m[0] * m[6] * m[13] +
|
||||
m[4] * m[1] * m[14] -
|
||||
m[4] * m[2] * m[13] -
|
||||
m[12] * m[1] * m[6] +
|
||||
m[12] * m[2] * m[5];
|
||||
|
||||
inv[3] = -m[1] * m[6] * m[11] +
|
||||
m[1] * m[7] * m[10] +
|
||||
m[5] * m[2] * m[11] -
|
||||
m[5] * m[3] * m[10] -
|
||||
m[9] * m[2] * m[7] +
|
||||
m[9] * m[3] * m[6];
|
||||
|
||||
inv[7] = m[0] * m[6] * m[11] -
|
||||
m[0] * m[7] * m[10] -
|
||||
m[4] * m[2] * m[11] +
|
||||
m[4] * m[3] * m[10] +
|
||||
m[8] * m[2] * m[7] -
|
||||
m[8] * m[3] * m[6];
|
||||
|
||||
inv[11] = -m[0] * m[5] * m[11] +
|
||||
m[0] * m[7] * m[9] +
|
||||
m[4] * m[1] * m[11] -
|
||||
m[4] * m[3] * m[9] -
|
||||
m[8] * m[1] * m[7] +
|
||||
m[8] * m[3] * m[5];
|
||||
|
||||
inv[15] = m[0] * m[5] * m[10] -
|
||||
m[0] * m[6] * m[9] -
|
||||
m[4] * m[1] * m[10] +
|
||||
m[4] * m[2] * m[9] +
|
||||
m[8] * m[1] * m[6] -
|
||||
m[8] * m[2] * m[5];
|
||||
|
||||
GLdouble det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];
|
||||
if (det == 0.0)
|
||||
return GL_FALSE;
|
||||
|
||||
det = 1.0 / det;
|
||||
for (int i = 0; i < 16; ++i)
|
||||
invOut[i] = inv[i] * det;
|
||||
|
||||
return GL_TRUE;
|
||||
}
|
||||
|
||||
extern "C" const GLubyte* APIENTRY gluErrorString(GLenum error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case 0:
|
||||
return (const GLubyte*)"no error";
|
||||
|
||||
#ifdef GLU_INVALID_ENUM
|
||||
case GLU_INVALID_ENUM:
|
||||
return (const GLubyte*)"invalid enum";
|
||||
#endif
|
||||
#ifdef GLU_INVALID_VALUE
|
||||
case GLU_INVALID_VALUE:
|
||||
return (const GLubyte*)"invalid value";
|
||||
#endif
|
||||
#ifdef GLU_OUT_OF_MEMORY
|
||||
case GLU_OUT_OF_MEMORY:
|
||||
return (const GLubyte*)"out of memory";
|
||||
#endif
|
||||
#ifdef GLU_INCOMPATIBLE_GL_VERSION
|
||||
case GLU_INCOMPATIBLE_GL_VERSION:
|
||||
return (const GLubyte*)"incompatible GL version";
|
||||
#endif
|
||||
|
||||
#ifdef GLU_TESS_ERROR1
|
||||
case GLU_TESS_ERROR1: return (const GLubyte*)"gluTessBeginPolygon must precede a gluTessEndPolygon";
|
||||
case GLU_TESS_ERROR2: return (const GLubyte*)"gluTessBeginContour must precede a gluTessEndContour";
|
||||
case GLU_TESS_ERROR3: return (const GLubyte*)"gluTessEndPolygon must follow a gluTessBeginPolygon";
|
||||
case GLU_TESS_ERROR4: return (const GLubyte*)"gluTessEndContour must follow a gluTessBeginContour";
|
||||
case GLU_TESS_ERROR5: return (const GLubyte*)"a coordinate is too large";
|
||||
case GLU_TESS_ERROR6: return (const GLubyte*)"need combine callback";
|
||||
case GLU_TESS_ERROR7: return (const GLubyte*)"missing or bad polygon data";
|
||||
case GLU_TESS_ERROR8: return (const GLubyte*)"missing or bad contour data";
|
||||
#endif
|
||||
|
||||
default:
|
||||
return (const GLubyte*)"unknown GLU error";
|
||||
}
|
||||
}
|
||||
|
||||
void APIENTRY gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)
|
||||
{
|
||||
const GLdouble DEG2RAD = 3.14159265358979323846 / 180.0;
|
||||
|
||||
GLfloat f = 1.0 / tan(fovy * 0.5 * DEG2RAD);
|
||||
|
||||
GLfloat m[16] = { 0 };
|
||||
|
||||
m[0] = f / aspect;
|
||||
m[5] = f;
|
||||
m[10] = (zFar + zNear) / (zNear - zFar);
|
||||
m[11] = -1.0;
|
||||
m[14] = (2.0 * zFar * zNear) / (zNear - zFar);
|
||||
m[15] = 0.0;
|
||||
|
||||
glMultMatrixf(m);
|
||||
}
|
||||
|
||||
extern "C" GLint APIENTRY gluUnProject(GLdouble winx, GLdouble winy, GLdouble winz,
|
||||
const GLdouble modelMatrix[16],
|
||||
const GLdouble projMatrix[16],
|
||||
const GLint viewport[4],
|
||||
GLdouble* objx, GLdouble* objy, GLdouble* objz)
|
||||
{
|
||||
GLdouble finalMatrix[16];
|
||||
GLdouble invMatrix[16];
|
||||
GLdouble in[4];
|
||||
GLdouble out[4];
|
||||
|
||||
if (!objx || !objy || !objz || !modelMatrix || !projMatrix || !viewport)
|
||||
return GL_FALSE;
|
||||
|
||||
qgluMultMatrixd(projMatrix, modelMatrix, finalMatrix);
|
||||
|
||||
if (!qgluInvertMatrixd(finalMatrix, invMatrix))
|
||||
return GL_FALSE;
|
||||
|
||||
in[0] = (winx - (GLdouble)viewport[0]) / (GLdouble)viewport[2];
|
||||
in[1] = (winy - (GLdouble)viewport[1]) / (GLdouble)viewport[3];
|
||||
in[2] = winz;
|
||||
in[3] = 1.0;
|
||||
|
||||
in[0] = in[0] * 2.0 - 1.0;
|
||||
in[1] = in[1] * 2.0 - 1.0;
|
||||
in[2] = in[2] * 2.0 - 1.0;
|
||||
|
||||
qgluMultMatrixVecd(invMatrix, in, out);
|
||||
|
||||
if (out[3] == 0.0)
|
||||
return GL_FALSE;
|
||||
|
||||
out[3] = 1.0 / out[3];
|
||||
|
||||
*objx = out[0] * out[3];
|
||||
*objy = out[1] * out[3];
|
||||
*objz = out[2] * out[3];
|
||||
|
||||
return GL_TRUE;
|
||||
}
|
||||
+2136
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,246 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="gl_d3d12arb.cpp" />
|
||||
<ClCompile Include="gl_d3d12raylight.cpp">
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
|
||||
</ClCompile>
|
||||
<ClCompile Include="gl_d3d12shim.cpp" />
|
||||
<ClCompile Include="gl_d3d12tess.cpp" />
|
||||
<ClCompile Include="gl_d3d12wgl.cpp" />
|
||||
<ClCompile Include="tess\dict.c">
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
|
||||
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Speed</FavorSizeOrSpeed>
|
||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tess\geom.c">
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
|
||||
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Speed</FavorSizeOrSpeed>
|
||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tess\memalloc.c">
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
|
||||
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Speed</FavorSizeOrSpeed>
|
||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tess\mesh.c">
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
|
||||
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Speed</FavorSizeOrSpeed>
|
||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tess\normal.c">
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
|
||||
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Speed</FavorSizeOrSpeed>
|
||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tess\priorityq-heap.c">
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
|
||||
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Speed</FavorSizeOrSpeed>
|
||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tess\priorityq.c">
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
|
||||
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Speed</FavorSizeOrSpeed>
|
||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tess\render.c">
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
|
||||
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Speed</FavorSizeOrSpeed>
|
||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tess\sweep.c">
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
|
||||
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Speed</FavorSizeOrSpeed>
|
||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tess\tess.c">
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
|
||||
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Speed</FavorSizeOrSpeed>
|
||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tess\tessellate.c">
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
|
||||
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Speed</FavorSizeOrSpeed>
|
||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tess\tessmono.c">
|
||||
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
|
||||
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Speed</FavorSizeOrSpeed>
|
||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="gl_d3d12arb.h" />
|
||||
<ClInclude Include="opengl.h" />
|
||||
<ClInclude Include="tess\dict-list.h" />
|
||||
<ClInclude Include="tess\dict.h" />
|
||||
<ClInclude Include="tess\geom.h" />
|
||||
<ClInclude Include="tess\glu.h" />
|
||||
<ClInclude Include="tess\gluos.h" />
|
||||
<ClInclude Include="tess\memalloc.h" />
|
||||
<ClInclude Include="tess\mesh.h" />
|
||||
<ClInclude Include="tess\normal.h" />
|
||||
<ClInclude Include="tess\priorityq-heap.h" />
|
||||
<ClInclude Include="tess\priorityq-sort.h" />
|
||||
<ClInclude Include="tess\priorityq.h" />
|
||||
<ClInclude Include="tess\render.h" />
|
||||
<ClInclude Include="tess\sweep.h" />
|
||||
<ClInclude Include="tess\tess.h" />
|
||||
<ClInclude Include="tess\tessellate.h" />
|
||||
<ClInclude Include="tess\tessmono.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="tess\tessellate.js" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Library Include="streamline\lib\x64\sl.interposer.lib" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>18.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{58320c19-5139-47c5-aafe-4cad2c8ed14d}</ProjectGuid>
|
||||
<RootNamespace>opengl</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v145</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v145</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v145</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v145</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>
|
||||
</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>
|
||||
</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<AdditionalIncludeDirectories>streamline/include</AdditionalIncludeDirectories>
|
||||
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>
|
||||
</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<AdditionalIncludeDirectories>streamline/include</AdditionalIncludeDirectories>
|
||||
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
|
||||
<EnableEnhancedInstructionSet>AdvancedVectorExtensions102</EnableEnhancedInstructionSet>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>
|
||||
</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,116 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="gl_d3d12shim.cpp" />
|
||||
<ClCompile Include="gl_d3d12wgl.cpp" />
|
||||
<ClCompile Include="gl_d3d12raylight.cpp" />
|
||||
<ClCompile Include="gl_d3d12tess.cpp" />
|
||||
<ClCompile Include="tess\dict.c">
|
||||
<Filter>tess</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tess\geom.c">
|
||||
<Filter>tess</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tess\memalloc.c">
|
||||
<Filter>tess</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tess\mesh.c">
|
||||
<Filter>tess</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tess\normal.c">
|
||||
<Filter>tess</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tess\priorityq.c">
|
||||
<Filter>tess</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tess\priorityq-heap.c">
|
||||
<Filter>tess</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tess\render.c">
|
||||
<Filter>tess</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tess\sweep.c">
|
||||
<Filter>tess</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tess\tess.c">
|
||||
<Filter>tess</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tess\tessellate.c">
|
||||
<Filter>tess</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tess\tessmono.c">
|
||||
<Filter>tess</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="gl_d3d12arb.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="opengl.h" />
|
||||
<ClInclude Include="tess\dict.h">
|
||||
<Filter>tess</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="tess\dict-list.h">
|
||||
<Filter>tess</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="tess\geom.h">
|
||||
<Filter>tess</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="tess\glu.h">
|
||||
<Filter>tess</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="tess\gluos.h">
|
||||
<Filter>tess</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="tess\memalloc.h">
|
||||
<Filter>tess</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="tess\mesh.h">
|
||||
<Filter>tess</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="tess\normal.h">
|
||||
<Filter>tess</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="tess\priorityq.h">
|
||||
<Filter>tess</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="tess\priorityq-heap.h">
|
||||
<Filter>tess</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="tess\priorityq-sort.h">
|
||||
<Filter>tess</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="tess\render.h">
|
||||
<Filter>tess</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="tess\sweep.h">
|
||||
<Filter>tess</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="tess\tess.h">
|
||||
<Filter>tess</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="tess\tessellate.h">
|
||||
<Filter>tess</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="tess\tessmono.h">
|
||||
<Filter>tess</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="gl_d3d12arb.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="tess">
|
||||
<UniqueIdentifier>{8e4412d9-8f8f-4888-ab36-4ef36887d7db}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="streamline">
|
||||
<UniqueIdentifier>{ac325e42-ffb4-4bbc-a4ec-b567658773a3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="tess\tessellate.js">
|
||||
<Filter>tess</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Library Include="streamline\lib\x64\sl.interposer.lib">
|
||||
<Filter>streamline</Filter>
|
||||
</Library>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
</Project>
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "sl_struct.h"
|
||||
#include "sl_consts.h"
|
||||
#include "sl_version.h"
|
||||
#include "sl_result.h"
|
||||
#include "sl_appidentity.h"
|
||||
#include "sl_device_wrappers.h"
|
||||
|
||||
#include "sl_core_api.h"
|
||||
#include "sl_core_types.h"
|
||||
|
||||
#define SL_FUN_DECL(name) PFun_##name* name{}
|
||||
//! IMPORTANT: Macros which use `slGetFeatureFunction` can only be used AFTER device is set by calling either slSetD3DDevice or slSetVulkanInfo.
|
||||
#define SL_FEATURE_FUN_IMPORT(feature, func) slGetFeatureFunction(feature, #func, (void*&) ##func)
|
||||
#define SL_FEATURE_FUN_IMPORT_STATIC(feature, func) \
|
||||
static PFun_##func* s_ ##func{}; \
|
||||
if(!s_ ##func) { \
|
||||
sl::Result res = slGetFeatureFunction(feature, #func, (void*&) s_ ##func); \
|
||||
if(res != sl::Result::eOk) return res; \
|
||||
} \
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "sl_struct.h"
|
||||
|
||||
namespace sl
|
||||
{
|
||||
|
||||
//! Engine types
|
||||
//!
|
||||
enum class EngineType : uint32_t
|
||||
{
|
||||
eCustom,
|
||||
eUnreal,
|
||||
eUnity,
|
||||
eCount
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <string>
|
||||
#include "sl_struct.h"
|
||||
|
||||
#define SL_ENUM_OPERATORS_64(T) \
|
||||
inline bool operator&(T a, T b) \
|
||||
{ \
|
||||
return ((uint64_t)a & (uint64_t)b) != 0; \
|
||||
} \
|
||||
\
|
||||
inline T& operator&=(T& a, T b) \
|
||||
{ \
|
||||
a = (T)((uint64_t)a & (uint64_t)b); \
|
||||
return a; \
|
||||
} \
|
||||
\
|
||||
inline T operator|(T a, T b) \
|
||||
{ \
|
||||
return (T)((uint64_t)a | (uint64_t)b); \
|
||||
} \
|
||||
\
|
||||
inline T& operator |= (T& lhs, T rhs) \
|
||||
{ \
|
||||
lhs = (T)((uint64_t)lhs | (uint64_t)rhs); \
|
||||
return lhs; \
|
||||
} \
|
||||
\
|
||||
inline T operator~(T a) \
|
||||
{ \
|
||||
return (T)~((uint64_t)a); \
|
||||
}
|
||||
|
||||
#define SL_ENUM_OPERATORS_32(T) \
|
||||
inline bool operator&(T a, T b) \
|
||||
{ \
|
||||
return ((uint32_t)a & (uint32_t)b) != 0; \
|
||||
} \
|
||||
\
|
||||
inline T& operator&=(T& a, T b) \
|
||||
{ \
|
||||
a = (T)((uint32_t)a & (uint32_t)b); \
|
||||
return a; \
|
||||
} \
|
||||
\
|
||||
inline T operator|(T a, T b) \
|
||||
{ \
|
||||
return (T)((uint32_t)a | (uint32_t)b); \
|
||||
} \
|
||||
\
|
||||
inline T& operator |= (T& lhs, T rhs) \
|
||||
{ \
|
||||
lhs = (T)((uint32_t)lhs | (uint32_t)rhs); \
|
||||
return lhs; \
|
||||
} \
|
||||
\
|
||||
inline T operator~(T a) \
|
||||
{ \
|
||||
return (T)~((uint32_t)a); \
|
||||
}
|
||||
|
||||
namespace sl
|
||||
{
|
||||
|
||||
//! For cases when value has to be provided and we don't have good default
|
||||
constexpr float INVALID_FLOAT = 3.40282346638528859811704183484516925440e38f;
|
||||
constexpr uint32_t INVALID_UINT = 0xffffffff;
|
||||
|
||||
//! Normally host would work with no more than 2 frames at the same time but sl.reflex sometimes
|
||||
//! needs to send markers for previous and next frame so the total number of in-flight frames can be higher
|
||||
constexpr uint32_t MAX_FRAMES_IN_FLIGHT = 6;
|
||||
|
||||
struct uint3
|
||||
{
|
||||
uint32_t x;
|
||||
uint32_t y;
|
||||
uint32_t z;
|
||||
};
|
||||
|
||||
struct float2
|
||||
{
|
||||
float2() : x(INVALID_FLOAT), y(INVALID_FLOAT) {}
|
||||
float2(float _x, float _y) : x(_x), y(_y) {}
|
||||
float x, y;
|
||||
};
|
||||
|
||||
struct float3
|
||||
{
|
||||
float3() : x(INVALID_FLOAT), y(INVALID_FLOAT), z(INVALID_FLOAT) {}
|
||||
float3(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}
|
||||
float x, y, z;
|
||||
};
|
||||
|
||||
struct float4
|
||||
{
|
||||
float4() : x(INVALID_FLOAT), y(INVALID_FLOAT), z(INVALID_FLOAT), w(INVALID_FLOAT) {}
|
||||
float4(float _x, float _y, float _z, float _w) : x(_x), y(_y), z(_z), w(_w) {}
|
||||
float x, y, z, w;
|
||||
};
|
||||
|
||||
struct float4x4
|
||||
{
|
||||
//! All access points take row index as a parameter
|
||||
inline float4& operator[](uint32_t i) { return row[i]; }
|
||||
inline const float4& operator[](uint32_t i) const { return row[i]; }
|
||||
inline void setRow(uint32_t i, const float4& v) { row[i] = v; }
|
||||
inline const float4& getRow(uint32_t i) { return row[i]; }
|
||||
|
||||
//! Row major matrix
|
||||
float4 row[4];
|
||||
};
|
||||
|
||||
struct Extent
|
||||
{
|
||||
uint32_t top{};
|
||||
uint32_t left{};
|
||||
uint32_t width{};
|
||||
uint32_t height{};
|
||||
|
||||
inline operator bool() const { return width != 0 && height != 0; }
|
||||
inline bool operator==(const Extent& rhs) const
|
||||
{
|
||||
return top == rhs.top && left == rhs.left &&
|
||||
width == rhs.width && height == rhs.height;
|
||||
}
|
||||
inline bool operator!=(const Extent& rhs) const
|
||||
{
|
||||
return !operator==(rhs);
|
||||
}
|
||||
inline bool isSameRes(const Extent& rhs) const
|
||||
{
|
||||
return width == rhs.width && height == rhs.height;
|
||||
}
|
||||
|
||||
#if defined(_WINDEF_)
|
||||
// Cast helper for sl::Extent->RECT when windef.h has been included
|
||||
inline operator RECT() const { return RECT { (LONG)left, (LONG)top, (LONG)(left + width), (LONG)(top + height) }; }
|
||||
#endif
|
||||
};
|
||||
|
||||
//! For cases when value has to be provided and we don't have good default
|
||||
enum Boolean : char
|
||||
{
|
||||
eFalse,
|
||||
eTrue,
|
||||
eInvalid
|
||||
};
|
||||
|
||||
//! Common constants, all parameters must be provided unless they are marked as optional
|
||||
//!
|
||||
//! {DCD35AD7-4E4A-4BAD-A90C-E0C49EB23AFE}
|
||||
SL_STRUCT_BEGIN(Constants, StructType({ 0xdcd35ad7, 0x4e4a, 0x4bad, { 0xa9, 0xc, 0xe0, 0xc4, 0x9e, 0xb2, 0x3a, 0xfe } }), kStructVersion2)
|
||||
//! IMPORTANT: All matrices are row major (see float4x4 definition) and
|
||||
//! must NOT contain temporal AA jitter offset (if any). Any jitter offset
|
||||
//! should be provided as the additional parameter Constants::jitterOffset (see below)
|
||||
|
||||
//! Specifies matrix transformation from the camera view to the clip space.
|
||||
float4x4 cameraViewToClip;
|
||||
//! Specifies matrix transformation from the clip space to the camera view space.
|
||||
float4x4 clipToCameraView;
|
||||
//! Optional - Specifies matrix transformation describing lens distortion in clip space.
|
||||
float4x4 clipToLensClip;
|
||||
//! Specifies matrix transformation from the current clip to the previous clip space.
|
||||
//! clipToPrevClip = clipToView * viewToViewPrev * viewToClipPrev
|
||||
//! Sample code can be found in sl_matrix_helpers.h
|
||||
float4x4 clipToPrevClip;
|
||||
//! Specifies matrix transformation from the previous clip to the current clip space.
|
||||
//! prevClipToClip = clipToPrevClip.inverse()
|
||||
float4x4 prevClipToClip;
|
||||
|
||||
//! Specifies pixel space jitter offset
|
||||
float2 jitterOffset;
|
||||
//! Specifies scale factors used to normalize motion vectors (so the values are in [-1,1] range)
|
||||
float2 mvecScale;
|
||||
//! Optional - Specifies camera pinhole offset if used.
|
||||
float2 cameraPinholeOffset;
|
||||
//! Specifies camera position in world space.
|
||||
float3 cameraPos;
|
||||
//! Specifies camera up vector in world space.
|
||||
float3 cameraUp;
|
||||
//! Specifies camera right vector in world space.
|
||||
float3 cameraRight;
|
||||
//! Specifies camera forward vector in world space.
|
||||
float3 cameraFwd;
|
||||
|
||||
//! Specifies camera near view plane distance.
|
||||
float cameraNear = INVALID_FLOAT;
|
||||
//! Specifies camera far view plane distance.
|
||||
float cameraFar = INVALID_FLOAT;
|
||||
//! Specifies camera field of view in radians.
|
||||
float cameraFOV = INVALID_FLOAT;
|
||||
//! Specifies camera aspect ratio defined as view space width divided by height.
|
||||
float cameraAspectRatio = INVALID_FLOAT;
|
||||
//! Specifies which value represents an invalid (un-initialized) value in the motion vectors buffer
|
||||
//! NOTE: This is only required if `cameraMotionIncluded` is set to false and SL needs to compute it.
|
||||
float motionVectorsInvalidValue = INVALID_FLOAT;
|
||||
|
||||
//! Specifies if depth values are inverted (value closer to the camera is higher) or not.
|
||||
Boolean depthInverted = Boolean::eInvalid;
|
||||
//! Specifies if camera motion is included in the MVec buffer.
|
||||
Boolean cameraMotionIncluded = Boolean::eInvalid;
|
||||
//! Specifies if motion vectors are 3D or not.
|
||||
Boolean motionVectors3D = Boolean::eInvalid;
|
||||
//! Specifies if previous frame has no connection to the current one (i.e. motion vectors are invalid)
|
||||
Boolean reset = Boolean::eInvalid;
|
||||
//! Specifies if orthographic projection is used or not.
|
||||
Boolean orthographicProjection = Boolean::eFalse;
|
||||
//! Specifies if motion vectors are already dilated or not.
|
||||
Boolean motionVectorsDilated = Boolean::eFalse;
|
||||
//! Specifies if motion vectors are jittered or not.
|
||||
Boolean motionVectorsJittered = Boolean::eFalse;
|
||||
|
||||
//! Version 2 members:
|
||||
//!
|
||||
//! Optional heuristic that specifies the minimum depth difference between two objects in screen-space.
|
||||
//! The units of the value are in linear depth units.
|
||||
//! Linear depth is computed as:
|
||||
//! if depthInverted is false: `lin_depth = 1 / (1 - depth)`
|
||||
//! if depthInverted is true: `lin_depth = 1 / depth`
|
||||
//!
|
||||
//! Although unlikely to need to be modified, smaller thresholds are useful when depth units are
|
||||
//! unusually compressed into a small dynamic range near 1.
|
||||
//!
|
||||
//! If not specified, the default value is 40.0f.
|
||||
float minRelativeLinearDepthObjectSeparation = 40.0f;
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
}
|
||||
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2024 NVIDIA CORPORATION. All rights reserved
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "sl_struct.h"
|
||||
#include "sl_consts.h"
|
||||
#include "sl_version.h"
|
||||
#include "sl_result.h"
|
||||
#include "sl_appidentity.h"
|
||||
#include "sl_device_wrappers.h"
|
||||
|
||||
#include "sl_core_types.h"
|
||||
|
||||
#if defined(SL_INTERPOSER)
|
||||
#if defined(_WIN32)
|
||||
#define SL_API extern "C" __declspec(dllexport)
|
||||
#else
|
||||
#error Unsupported Platform!
|
||||
#endif
|
||||
#else
|
||||
#define SL_API extern "C"
|
||||
#endif
|
||||
|
||||
#pragma region SL_API
|
||||
|
||||
//! Streamline core API functions (check feature specific headers for additional APIs)
|
||||
//!
|
||||
using PFun_slInit = sl::Result(const sl::Preferences& pref, uint64_t sdkVersion);
|
||||
using PFun_slShutdown = sl::Result();
|
||||
using PFun_slIsFeatureSupported = sl::Result(sl::Feature feature, const sl::AdapterInfo& adapterInfo);
|
||||
using PFun_slIsFeatureLoaded = sl::Result(sl::Feature feature, bool& loaded);
|
||||
using PFun_slSetFeatureLoaded = sl::Result(sl::Feature feature, bool loaded);
|
||||
using PFun_slEvaluateFeature = sl::Result(sl::Feature feature, const sl::FrameToken& frame, const sl::BaseStructure** inputs, uint32_t numInputs, sl::CommandBuffer* cmdBuffer);
|
||||
using PFun_slAllocateResources = sl::Result(sl::CommandBuffer* cmdBuffer, sl::Feature feature, const sl::ViewportHandle& viewport);
|
||||
using PFun_slFreeResources = sl::Result(sl::Feature feature, const sl::ViewportHandle& viewport);
|
||||
using PFun_slSetTag
|
||||
#if __cplusplus >= 201402L
|
||||
[[deprecated("Use the version of this function that takes a sl::FrameToken instead - slSetTagForFrame and set sl::PreferenceFlags::eUseFrameBasedResourceTagging.")]]
|
||||
#endif
|
||||
= sl::Result(const sl::ViewportHandle& viewport, const sl::ResourceTag* tags, uint32_t numTags, sl::CommandBuffer* cmdBuffer);
|
||||
using PFun_slSetTagForFrame = sl::Result(const sl::FrameToken& frame, const sl::ViewportHandle& viewport, const sl::ResourceTag* tags, uint32_t numTags, sl::CommandBuffer* cmdBuffer);
|
||||
using PFun_slGetFeatureRequirements = sl::Result(sl::Feature feature, sl::FeatureRequirements& requirements);
|
||||
using PFun_slGetFeatureVersion = sl::Result(sl::Feature feature, sl::FeatureVersion& version);
|
||||
using PFun_slUpgradeInterface = sl::Result(void** baseInterface);
|
||||
using PFun_slSetConstants = sl::Result(const sl::Constants& values, const sl::FrameToken& frame, const sl::ViewportHandle& viewport);
|
||||
using PFun_slGetNativeInterface = sl::Result(void* proxyInterface, void** baseInterface);
|
||||
using PFun_slGetFeatureFunction = sl::Result(sl::Feature feature, const char* functionName, void*& function);
|
||||
using PFun_slGetNewFrameToken = sl::Result(sl::FrameToken*& token, const uint32_t* frameIndex);
|
||||
using PFun_slSetD3DDevice = sl::Result(void* d3dDevice);
|
||||
|
||||
|
||||
//! Initializes the SL module
|
||||
//!
|
||||
//! Call this method when the game is initializing.
|
||||
//!
|
||||
//! @param pref Specifies preferred behavior for the SL library (SL will keep a copy)
|
||||
//! @param sdkVersion Current SDK version
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is NOT thread safe.
|
||||
SL_API sl::Result slInit(const sl::Preferences &pref, uint64_t sdkVersion = sl::kSDKVersion);
|
||||
|
||||
//! Shuts down the SL module
|
||||
//!
|
||||
//! Call this method when the game is shutting down.
|
||||
//!
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is NOT thread safe.
|
||||
SL_API sl::Result slShutdown();
|
||||
|
||||
//! Checks if a specific feature is supported or not.
|
||||
//!
|
||||
//! Call this method to check if a certain e* (see above) is available.
|
||||
//!
|
||||
//! @param feature Specifies which feature to use
|
||||
//! @param adapterInfo Adapter to check (optional)
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! NOTE: If adapter info is null SL will return general feature compatibility with the OS,
|
||||
//! installed drivers or any other requirements not directly related to the adapter.
|
||||
//!
|
||||
//! This method is NOT thread safe.
|
||||
SL_API sl::Result slIsFeatureSupported(sl::Feature feature, const sl::AdapterInfo& adapterInfo);
|
||||
|
||||
//! Checks if specified feature is loaded or not.
|
||||
//!
|
||||
//! Call this method to check if feature is loaded.
|
||||
//! All requested features are loaded by default and have to be unloaded explicitly if needed.
|
||||
//!
|
||||
//! @param feature Specifies which feature to check
|
||||
//! @param loaded Value specifying if feature is loaded or unloaded.
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is NOT thread safe and requires DX/VK device to be created before calling it.
|
||||
SL_API sl::Result slIsFeatureLoaded(sl::Feature feature, bool& loaded);
|
||||
|
||||
//! Sets the specified feature to either loaded or unloaded state.
|
||||
//!
|
||||
//! Call this method to load or unload certain e*.
|
||||
//!
|
||||
//! NOTE: All requested features are loaded by default and have to be unloaded explicitly if needed.
|
||||
//!
|
||||
//! @param feature Specifies which feature to check
|
||||
//! @param loaded Value specifying if feature should be loaded or unloaded.
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! NOTE: When this method is called no other DXGI/D3D/Vulkan APIs should be invoked in parallel so
|
||||
//! make sure to flush your pipeline before calling this method.
|
||||
//!
|
||||
//! This method is NOT thread safe and requires DX/VK device to be created before calling it.
|
||||
SL_API sl::Result slSetFeatureLoaded(sl::Feature feature, bool loaded);
|
||||
|
||||
//! NOTE: sl::PreferenceFlags::eUseFrameBasedResourceTagging must be set when using this API.
|
||||
//! Tags resource globally
|
||||
//!
|
||||
//! Call this method to tag the appropriate buffers in global scope.
|
||||
//!
|
||||
//! @param frame Specifies the frame this tag applies to. Frame token can be obtained using slGetNewFrameToken API.
|
||||
//! @param viewport Specifies viewport this tag applies to
|
||||
//! @param tags Pointer to resources tags, set to null to remove the specified tag
|
||||
//! @param numTags Number of resource tags in the provided list
|
||||
//! @param cmdBuffer Command buffer to use (optional and can be null if ALL tags are null or have eValidUntilPresent life-cycle)
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! IMPORTANT: GPU payload that generates content for the provided tag(s) MUST be either already submitted to the provided command buffer
|
||||
//! or some other command buffer which is guaranteed, by the host application, to be executed BEFORE the provided command buffer.
|
||||
//!
|
||||
//! This method is thread safe and requires DX/VK device to be created before calling it.
|
||||
SL_API sl::Result slSetTagForFrame(const sl::FrameToken& frame, const sl::ViewportHandle& viewport, const sl::ResourceTag* resources, uint32_t numResources, sl::CommandBuffer* cmdBuffer);
|
||||
|
||||
//! NOTE: This API has now been DEPRECATED in favor of the new slSetTagForFrame API above.
|
||||
//! Tags resource globally
|
||||
//!
|
||||
//! Call this method to tag the appropriate buffers in global scope.
|
||||
//!
|
||||
//! @param viewport Specifies viewport this tag applies to
|
||||
//! @param tags Pointer to resources tags, set to null to remove the specified tag
|
||||
//! @param numTags Number of resource tags in the provided list
|
||||
//! @param cmdBuffer Command buffer to use (optional and can be null if ALL tags are null or have eValidUntilPresent life-cycle)
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! IMPORTANT: GPU payload that generates content for the provided tag(s) MUST be either already submitted to the provided command buffer
|
||||
//! or some other command buffer which is guaranteed, by the host application, to be executed BEFORE the provided command buffer.
|
||||
//!
|
||||
//! This method is thread safe and requires DX/VK device to be created before calling it.
|
||||
SL_API
|
||||
#if __cplusplus >= 201402L
|
||||
[[deprecated("Use the version of this function that takes a sl::FrameToken instead - slSetTagForFrame and set sl::PreferenceFlags::eUseFrameBasedResourceTagging.")]]
|
||||
#endif
|
||||
sl::Result slSetTag(const sl::ViewportHandle& viewport, const sl::ResourceTag* tags, uint32_t numTags, sl::CommandBuffer* cmdBuffer);
|
||||
|
||||
//! Sets common constants.
|
||||
//!
|
||||
//! Call this method to provide the required data (SL will keep a copy).
|
||||
//!
|
||||
//! @param values Common constants required by SL plugins (SL will keep a copy)
|
||||
//! @param frame Index of the current frame
|
||||
//! @param viewport Unique id (can be viewport id | instance id etc.)
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is thread safe and requires DX/VK device to be created before calling it.
|
||||
SL_API sl::Result slSetConstants(const sl::Constants& values, const sl::FrameToken& frame, const sl::ViewportHandle& viewport);
|
||||
|
||||
//! Returns feature's requirements
|
||||
//!
|
||||
//! Call this method to check what is required to run certain eFeature* (see above).
|
||||
//! This method must be called after init otherwise it will always return an error.
|
||||
//!
|
||||
//! @param feature Specifies which feature to check
|
||||
//! @param requirements Data structure with feature's requirements
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is NOT thread safe.
|
||||
SL_API sl::Result slGetFeatureRequirements(sl::Feature feature, sl::FeatureRequirements& requirements);
|
||||
|
||||
//! Returns feature's version
|
||||
//!
|
||||
//! Call this method to check version for a certain eFeature* (see above).
|
||||
//! This method must be called after init otherwise it will always return an error.
|
||||
//!
|
||||
//! @param feature Specifies which feature to check
|
||||
//! @param version Data structure with feature's version
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is thread safe.
|
||||
SL_API sl::Result slGetFeatureVersion(sl::Feature feature, sl::FeatureVersion& version);
|
||||
|
||||
//! Allocates resources for the specified feature.
|
||||
//!
|
||||
//! Call this method to explicitly allocate resources
|
||||
//! for an instance of the specified feature.
|
||||
//!
|
||||
//! @param cmdBuffer Command buffer to use (must be created on device where feature is supported but can be null if not needed)
|
||||
//! @param feature Feature we are working with
|
||||
//! @param viewport Unique id (viewport handle)
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is NOT thread safe and requires DX/VK device to be created before calling it.
|
||||
SL_API sl::Result slAllocateResources(sl::CommandBuffer* cmdBuffer, sl::Feature feature, const sl::ViewportHandle& viewport);
|
||||
|
||||
//! Frees resources for the specified feature.
|
||||
//!
|
||||
//! Call this method to explicitly free resources
|
||||
//! for an instance of the specified feature.
|
||||
//!
|
||||
//! @param feature Feature we are working with
|
||||
//! @param viewport Unique id (viewport handle)
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! IMPORTANT: If slEvaluateFeature is pending on a command list, that command list must be flushed
|
||||
//! before calling this method to prevent invalid resource access on the GPU.
|
||||
//!
|
||||
//! IMPORTANT: If slEvaluateFeature is pending on a command list, that command list must be flushed
|
||||
//! before calling this method to prevent invalid resource access on the GPU.
|
||||
//!
|
||||
//! This method is NOT thread safe and requires DX/VK device to be created before calling it.
|
||||
SL_API sl::Result slFreeResources(sl::Feature feature, const sl::ViewportHandle& viewport);
|
||||
|
||||
//! NOTE: sl::PreferenceFlags::eUseFrameBasedResourceTagging must be set when using this API to do
|
||||
//! frame-based resource tagging for multiple frames in flight at the same time.
|
||||
//! Evaluates feature
|
||||
//!
|
||||
//! Use this method to mark the section in your rendering pipeline
|
||||
//! where specific feature should be injected.
|
||||
//!
|
||||
//! @param feature Feature we are working with
|
||||
//! @param frame Current frame handle obtained from SL
|
||||
//! @param inputs The chained structures providing the input data (viewport, tags, constants etc)
|
||||
//! @param numInputs Number of inputs
|
||||
//! @param cmdBuffer Command buffer to use (must be created on device where feature is supported)
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! IMPORTANT: Frame and viewport must match whatever is used to set common and or feature options and constants (if any)
|
||||
//!
|
||||
//! NOTE: It is allowed to pass in buffer tags as inputs, they are considered to be a "local" tags and do NOT interact with
|
||||
//! same tags sent in the global scope using slSetTag API.
|
||||
//!
|
||||
//! This method is NOT thread safe and requires DX/VK device to be created before calling it.
|
||||
SL_API sl::Result slEvaluateFeature(sl::Feature feature, const sl::FrameToken& frame, const sl::BaseStructure** inputs, uint32_t numInputs, sl::CommandBuffer* cmdBuffer);
|
||||
|
||||
//! Upgrade interface
|
||||
//!
|
||||
//! Use this method to upgrade basic D3D or DXGI interface to an SL proxy.
|
||||
//!
|
||||
//! @param baseInterface Pointer to a pointer to the base interface (for example ID3D12Device etc.) to be replaced in place.
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! IMPORTANT: This method should ONLY be used to support 3rd party SDKs like AMD AGS
|
||||
//! which bypass SL or when using manual hooking.
|
||||
//!
|
||||
//! This method is NOT thread safe and should be called IMMEDIATELY after base interface is created.
|
||||
SL_API sl::Result slUpgradeInterface(void** baseInterface);
|
||||
|
||||
//! Obtain native interface
|
||||
//!
|
||||
//! Use this method to obtain underlying D3D or DXGI interface from an SL proxy.
|
||||
//!
|
||||
//! IMPORTANT: When calling NVAPI or other 3rd party SDKs from your application
|
||||
//! it is recommended to provide native interfaces instead of SL proxies.
|
||||
//!
|
||||
//! @param proxyInterface Pointer to the SL proxy (D3D device, swap-chain etc)
|
||||
//! @param baseInterface Pointer to a pointer to the base interface be returned.
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is NOT thread safe
|
||||
SL_API sl::Result slGetNativeInterface(void* proxyInterface, void** baseInterface);
|
||||
|
||||
//! Gets specific feature's function
|
||||
//!
|
||||
//! Call this method to obtain various functions for the specified feature. See sl_$feature.h for details.
|
||||
//!
|
||||
//! @param feature Feature we are working with
|
||||
//! @param functionName The name of the API to obtain (declared in sl_[$feature].h
|
||||
//! @param function Pointer to the function to return
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! IMPORTANT: Must be called AFTER device is set by calling either slSetD3DDevice or slSetVulkanInfo.
|
||||
//!
|
||||
//! This method is thread safe.
|
||||
SL_API sl::Result slGetFeatureFunction(sl::Feature feature, const char* functionName, void*& function);
|
||||
|
||||
//! Gets unique frame token
|
||||
//!
|
||||
//! Call this method to obtain token for the unique frame identification.
|
||||
//!
|
||||
//! @param handle Frame token to return
|
||||
//! @param frameIndex Frame index (optional, if not provided SL internal frame counting is used)
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! NOTE: Normally SL would not expect more that 3 frames in flight due to added latency.
|
||||
//!
|
||||
//! This method is thread safe.
|
||||
SL_API sl::Result slGetNewFrameToken(sl::FrameToken*& token, const uint32_t* frameIndex = nullptr);
|
||||
|
||||
//! Set D3D device to use
|
||||
//!
|
||||
//! Use this method to specify which D3D device should be used.
|
||||
//!
|
||||
//! @param d3dDevice D3D device to use
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is NOT thread safe and should be called IMMEDIATELY after main device is created.
|
||||
SL_API sl::Result slSetD3DDevice(void* d3dDevice);
|
||||
|
||||
#pragma endregion SL_API
|
||||
@@ -0,0 +1,751 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2024 NVIDIA CORPORATION. All rights reserved
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <limits.h>
|
||||
#include <vector>
|
||||
|
||||
#include "sl_struct.h"
|
||||
#include "sl_consts.h"
|
||||
#include "sl_version.h"
|
||||
#include "sl_result.h"
|
||||
#include "sl_appidentity.h"
|
||||
#include "sl_device_wrappers.h"
|
||||
|
||||
typedef struct ID3D11Resource ID3D11Resource;
|
||||
typedef struct ID3D11Buffer ID3D11Buffer;
|
||||
typedef struct ID3D11Texture2D ID3D11Texture2D;
|
||||
typedef struct ID3D12Resource ID3D12Resource;
|
||||
|
||||
// Forward declarations matching MS and VK specs
|
||||
#ifdef VK_VERSION_1_0
|
||||
using SL_VKResult = VkResult;
|
||||
#else
|
||||
using SL_VKResult = int;
|
||||
#endif
|
||||
using HRESULT = long;
|
||||
|
||||
namespace sl {
|
||||
|
||||
using CommandBuffer = void;
|
||||
using Device = void;
|
||||
|
||||
//! Buffer types used for tagging
|
||||
//!
|
||||
//! IMPORTANT: Each tag must use the unique id
|
||||
//!
|
||||
using BufferType = uint32_t;
|
||||
|
||||
// Friend function declaration to access private members for ABI validation static_asserts
|
||||
namespace test
|
||||
{
|
||||
constexpr void AbiValidation();
|
||||
}
|
||||
|
||||
//! Depth buffer - IMPORTANT - Must be suitable to use with clipToPrevClip transformation (see Constants below)
|
||||
constexpr BufferType kBufferTypeDepth = 0;
|
||||
//! Object and optional camera motion vectors (see Constants below)
|
||||
constexpr BufferType kBufferTypeMotionVectors = 1;
|
||||
//! Color buffer with all post-processing effects applied but without any UI/HUD elements
|
||||
constexpr BufferType kBufferTypeHUDLessColor = 2;
|
||||
//! Color buffer containing jittered input data for the image scaling pass
|
||||
constexpr BufferType kBufferTypeScalingInputColor = 3;
|
||||
//! Color buffer containing results from the image scaling pass
|
||||
constexpr BufferType kBufferTypeScalingOutputColor = 4;
|
||||
//! Normals
|
||||
constexpr BufferType kBufferTypeNormals = 5;
|
||||
//! Roughness
|
||||
constexpr BufferType kBufferTypeRoughness = 6;
|
||||
//! Albedo
|
||||
constexpr BufferType kBufferTypeAlbedo = 7;
|
||||
//! Specular Albedo
|
||||
constexpr BufferType kBufferTypeSpecularAlbedo = 8;
|
||||
//! Indirect Albedo
|
||||
constexpr BufferType kBufferTypeIndirectAlbedo = 9;
|
||||
//! Specular Motion Vectors
|
||||
constexpr BufferType kBufferTypeSpecularMotionVectors = 10;
|
||||
//! Disocclusion Mask
|
||||
constexpr BufferType kBufferTypeDisocclusionMask = 11;
|
||||
//! Emissive
|
||||
constexpr BufferType kBufferTypeEmissive = 12;
|
||||
//! Exposure
|
||||
constexpr BufferType kBufferTypeExposure = 13;
|
||||
//! Buffer with normal and roughness in alpha channel
|
||||
constexpr BufferType kBufferTypeNormalRoughness = 14;
|
||||
//! Diffuse and camera ray length
|
||||
constexpr BufferType kBufferTypeDiffuseHitNoisy = 15;
|
||||
//! Diffuse denoised
|
||||
constexpr BufferType kBufferTypeDiffuseHitDenoised = 16;
|
||||
//! Specular and reflected ray length
|
||||
constexpr BufferType kBufferTypeSpecularHitNoisy = 17;
|
||||
//! Specular denoised
|
||||
constexpr BufferType kBufferTypeSpecularHitDenoised = 18;
|
||||
//! Shadow noisy
|
||||
constexpr BufferType kBufferTypeShadowNoisy = 19;
|
||||
//! Shadow denoised
|
||||
constexpr BufferType kBufferTypeShadowDenoised = 20;
|
||||
//! AO noisy
|
||||
constexpr BufferType kBufferTypeAmbientOcclusionNoisy = 21;
|
||||
//! AO denoised
|
||||
constexpr BufferType kBufferTypeAmbientOcclusionDenoised = 22;
|
||||
//! Optional - UI/HUD color and alpha
|
||||
//! IMPORTANT: Please make sure that alpha channel has enough precision (for example do NOT use formats like R10G10B10A2)
|
||||
constexpr BufferType kBufferTypeUIColorAndAlpha = 23;
|
||||
//! Optional - Shadow pixels hint (set to 1 if a pixel belongs to the shadow area, 0 otherwise)
|
||||
constexpr BufferType kBufferTypeShadowHint = 24;
|
||||
//! Optional - Reflection pixels hint (set to 1 if a pixel belongs to the reflection area, 0 otherwise)
|
||||
constexpr BufferType kBufferTypeReflectionHint = 25;
|
||||
//! Optional - Particle pixels hint (set to 1 if a pixel represents a particle, 0 otherwise)
|
||||
constexpr BufferType kBufferTypeParticleHint = 26;
|
||||
//! Optional - Transparency pixels hint (set to 1 if a pixel belongs to the transparent area, 0 otherwise)
|
||||
constexpr BufferType kBufferTypeTransparencyHint = 27;
|
||||
//! Optional - Animated texture pixels hint (set to 1 if a pixel belongs to the animated texture area, 0 otherwise)
|
||||
constexpr BufferType kBufferTypeAnimatedTextureHint = 28;
|
||||
//! Optional - Bias for current color vs history hint - lerp(history, current, bias) (set to 1 to completely reject history)
|
||||
constexpr BufferType kBufferTypeBiasCurrentColorHint = 29;
|
||||
//! Optional - Ray-tracing distance (camera ray length)
|
||||
constexpr BufferType kBufferTypeRaytracingDistance = 30;
|
||||
//! Optional - Motion vectors for reflections
|
||||
constexpr BufferType kBufferTypeReflectionMotionVectors = 31;
|
||||
//! Optional - Position, in same space as eNormals
|
||||
constexpr BufferType kBufferTypePosition = 32;
|
||||
//! Optional - Indicates (via non-zero value) which pixels have motion/depth values that do not match the final color content at that pixel (e.g. overlaid, opaque Picture-in-Picture)
|
||||
constexpr BufferType kBufferTypeInvalidDepthMotionHint = 33;
|
||||
//! Alpha
|
||||
constexpr BufferType kBufferTypeAlpha = 34;
|
||||
//! Color buffer containing only opaque geometry
|
||||
constexpr BufferType kBufferTypeOpaqueColor = 35;
|
||||
//! Optional - Reduce reliance on history instead using current frame hint (0 if a pixel is not at all reactive and default composition should be used, 1 if fully reactive)
|
||||
constexpr BufferType kBufferTypeReactiveMaskHint = 36;
|
||||
//! Optional - Pixel lock adjustment hint (set to 1 if pixel lock should be completely removed, 0 otherwise)
|
||||
constexpr BufferType kBufferTypeTransparencyAndCompositionMaskHint = 37;
|
||||
//! Optional - Albedo of the reflection ray hit point. For multibounce reflections, this should be the albedo of the first non-specular bounce.
|
||||
constexpr BufferType kBufferTypeReflectedAlbedo = 38;
|
||||
//! Optional - Color buffer before particles are drawn.
|
||||
constexpr BufferType kBufferTypeColorBeforeParticles = 39;
|
||||
//! Optional - Color buffer before transparent objects are drawn.
|
||||
constexpr BufferType kBufferTypeColorBeforeTransparency = 40;
|
||||
//! Optional - Color buffer before fog is drawn.
|
||||
constexpr BufferType kBufferTypeColorBeforeFog = 41;
|
||||
//! Optional - Buffer containing the hit distance of a specular ray.
|
||||
constexpr BufferType kBufferTypeSpecularHitDistance = 42;
|
||||
//! Optional - Buffer that contains 3 components of a specular ray direction, and 1 component of specular hit distance.
|
||||
constexpr BufferType kBufferTypeSpecularRayDirectionHitDistance = 43;
|
||||
//! Optional - Buffer containing normalized direction of a specular ray.
|
||||
constexpr BufferType kBufferTypeSpecularRayDirection = 44;
|
||||
// !Optional - Buffer containing the hit distance of a diffuse ray.
|
||||
constexpr BufferType kBufferTypeDiffuseHitDistance = 45;
|
||||
//! Optional - Buffer that contains 3 components of a diffuse ray direction, and 1 component of diffuse hit distance.
|
||||
constexpr BufferType kBufferTypeDiffuseRayDirectionHitDistance = 46;
|
||||
//! Optional - Buffer containing normalized direction of a diffuse ray.
|
||||
constexpr BufferType kBufferTypeDiffuseRayDirection = 47;
|
||||
//! Optional - Buffer containing display resolution depth.
|
||||
constexpr BufferType kBufferTypeHiResDepth = 48;
|
||||
//! Required either this or kBufferTypeDepth - Buffer containing linear depth.
|
||||
constexpr BufferType kBufferTypeLinearDepth = 49;
|
||||
//! Optional - Bidirectional distortion field. 4 channels in normalized [0,1] pixel space. RG = distorted pixel to undistorted pixel displacement. BA = undistorted pixel to distorted pixel displacement.
|
||||
constexpr BufferType kBufferTypeBidirectionalDistortionField = 50;
|
||||
//!Optional - Buffer containing particles or other similar transparent effects rendered into it instead of passing it as part of the input color
|
||||
constexpr BufferType kBufferTypeTransparencyLayer = 51;
|
||||
//!Optional - Buffer to be used in addition to TransparencyLayer which allows 3-channels of Opacity versus 1-channel.
|
||||
// In this case, TransparencyLayer represents Color (RcGcBc), TransparencyLayerOpacity represents alpha (RaGaBa)'
|
||||
constexpr BufferType kBufferTypeTransparencyLayerOpacity = 52;
|
||||
//! Optional - Swapchain buffer to be presented
|
||||
constexpr BufferType kBufferTypeBackbuffer = 53;
|
||||
//! Optional - Mask for pixels to skip warping
|
||||
constexpr BufferType kBufferTypeNoWarpMask = 54;
|
||||
//! Optional - Color buffer after particles are drawn (for research purposes)
|
||||
constexpr BufferType kBufferTypeColorAfterParticles = 55;
|
||||
//! Optional - Color buffer after transparent objects are drawn (for research purposes)
|
||||
constexpr BufferType kBufferTypeColorAfterTransparency = 56;
|
||||
//! Optional - Color buffer after fog is drawn (for research purposes)
|
||||
constexpr BufferType kBufferTypeColorAfterFog = 57;
|
||||
//! Optional - Subsurface scattering guide buffer
|
||||
constexpr BufferType kBufferTypeScreenSpaceSubsurfaceScatteringGuide = 58;
|
||||
//! Optional - Color buffer before subsurface scattering (for research purposes)
|
||||
constexpr BufferType kBufferTypeColorBeforeScreenSpaceSubsurfaceScattering = 59;
|
||||
//! Optional - Color buffer after subsurface scattering (for research purposes)
|
||||
constexpr BufferType kBufferTypeColorAfterScreenSpaceSubsurfaceScattering = 60;
|
||||
//! Optional - Refraction guide buffer (for research purposes)
|
||||
constexpr BufferType kBufferTypeScreenSpaceRefractionGuide = 61;
|
||||
//! Optional - Color buffer before refraction (for research purposes)
|
||||
constexpr BufferType kBufferTypeColorBeforeScreenSpaceRefraction = 62;
|
||||
//! Optional - Color buffer after refraction (for research purposes)
|
||||
constexpr BufferType kBufferTypeColorAfterScreenSpaceRefraction = 63;
|
||||
//! Optional - Depth of Field Buffer (for research purposes)
|
||||
constexpr BufferType kBufferTypeDepthOfFieldGuide = 64;
|
||||
//! Optional - Color buffer before Depth of Field (for research purposes)
|
||||
constexpr BufferType kBufferTypeColorBeforeDepthOfField = 65;
|
||||
//! Optional - Color buffer after Depth of Field (for research purposes)
|
||||
constexpr BufferType kBufferTypeColorAfterDepthOfField = 66;
|
||||
//! Optional - Color buffer that overrides the alpha channel of kBufferTypeScalingOutputColor
|
||||
constexpr BufferType kBufferTypeScalingOutputAlpha = 67;
|
||||
//! Features supported with this SDK
|
||||
//!
|
||||
//! IMPORTANT: Each feature must use a unique id
|
||||
//!
|
||||
using Feature = uint32_t;
|
||||
|
||||
//! Deep Learning Super Sampling
|
||||
constexpr Feature kFeatureDLSS = 0;
|
||||
|
||||
//! Real-Time Denoiser (removed)
|
||||
constexpr Feature kFeatureNRD_INVALID = 1;
|
||||
|
||||
//! NVIDIA Image Scaling
|
||||
constexpr Feature kFeatureNIS = 2;
|
||||
|
||||
//! Reflex
|
||||
constexpr Feature kFeatureReflex = 3;
|
||||
|
||||
//! PC Latency
|
||||
constexpr Feature kFeaturePCL = 4;
|
||||
|
||||
//! DeepDVC
|
||||
constexpr Feature kFeatureDeepDVC = 5;
|
||||
|
||||
constexpr Feature kFeatureLatewarp = 6;
|
||||
|
||||
//! DLSS Frame Generation
|
||||
constexpr Feature kFeatureDLSS_G = 1000;
|
||||
|
||||
//! DLSS Ray Reconstruction
|
||||
constexpr Feature kFeatureDLSS_RR = 1001;
|
||||
|
||||
constexpr Feature kFeatureNvPerf = 1002;
|
||||
|
||||
constexpr Feature kFeatureDirectSR = 1003;
|
||||
|
||||
// ImGUI
|
||||
constexpr Feature kFeatureImGUI = 9999;
|
||||
|
||||
//! Common feature, NOT intended to be used directly
|
||||
constexpr Feature kFeatureCommon = UINT_MAX;
|
||||
|
||||
//! Different levels for logging
|
||||
enum class LogLevel : uint32_t
|
||||
{
|
||||
//! No logging
|
||||
eOff,
|
||||
//! Default logging
|
||||
eDefault,
|
||||
//! Verbose logging
|
||||
eVerbose,
|
||||
//! Total count
|
||||
eCount
|
||||
};
|
||||
|
||||
//! Resource types
|
||||
enum class ResourceType : char
|
||||
{
|
||||
eTex2d,
|
||||
eBuffer,
|
||||
eCommandQueue,
|
||||
eCommandBuffer,
|
||||
eCommandPool,
|
||||
eFence,
|
||||
eSwapchain,
|
||||
eHostFence,
|
||||
// this type means that the only thing we know for sure about this resource is that it's castable to IUnknown
|
||||
eUnknown,
|
||||
eCount
|
||||
};
|
||||
|
||||
//! Resource allocate information
|
||||
//!
|
||||
SL_STRUCT_BEGIN(ResourceAllocationDesc, StructType({ 0xbb57e5, 0x49a2, 0x4c23, { 0xa5, 0x19, 0xab, 0x92, 0x86, 0xe7, 0x40, 0x14 } }), kStructVersion1)
|
||||
ResourceAllocationDesc(ResourceType _type, void* _desc, uint32_t _state, void* _heap) : BaseStructure(ResourceAllocationDesc::s_structType, kStructVersion1), type(_type),desc(_desc),state(_state),heap(_heap){};
|
||||
//! Indicates the type of resource
|
||||
ResourceType type = ResourceType::eTex2d;
|
||||
//! D3D12_RESOURCE_DESC/VkImageCreateInfo/VkBufferCreateInfo
|
||||
void* desc{};
|
||||
//! Initial state as D3D12_RESOURCE_STATES or VkMemoryPropertyFlags
|
||||
uint32_t state = 0;
|
||||
//! CD3DX12_HEAP_PROPERTIES or nullptr
|
||||
void* heap{};
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
|
||||
//! Subresource range information, for Vulkan resources
|
||||
//!
|
||||
//! {8D4C316C-D402-4524-89A7-14E79E638E3A}
|
||||
SL_STRUCT_BEGIN(SubresourceRange, StructType({ 0x8d4c316c, 0xd402, 0x4524, { 0x89, 0xa7, 0x14, 0xe7, 0x9e, 0x63, 0x8e, 0x3a } }), kStructVersion1)
|
||||
//! Vulkan subresource aspectMask
|
||||
uint32_t aspectMask;
|
||||
//! Vulkan subresource baseMipLevel
|
||||
uint32_t baseMipLevel;
|
||||
//! Vulkan subresource levelCount
|
||||
uint32_t levelCount;
|
||||
//! Vulkan subresource baseArrayLayer
|
||||
uint32_t baseArrayLayer;
|
||||
//! Vulkan subresource layerCount
|
||||
uint32_t layerCount;
|
||||
SL_STRUCT_END()
|
||||
|
||||
//! Native resource
|
||||
//!
|
||||
//! {3A9D70CF-2418-4B72-8391-13F8721C7261}
|
||||
SL_STRUCT_BEGIN(Resource, StructType({ 0x3a9d70cf, 0x2418, 0x4b72, { 0x83, 0x91, 0x13, 0xf8, 0x72, 0x1c, 0x72, 0x61 } }), kStructVersion1)
|
||||
//! Constructors
|
||||
//!
|
||||
//! Resource type, native pointer are MANDATORY always
|
||||
//! Resource state is MANDATORY unless using D3D11
|
||||
//! Resource view, description etc. are MANDATORY only when using Vulkan
|
||||
//!
|
||||
Resource(ResourceType _type, void* _native, void* _mem, void* _view, uint32_t _state = UINT_MAX) : BaseStructure(Resource::s_structType, kStructVersion1), type(_type), native(_native), memory(_mem), view(_view), state(_state){};
|
||||
Resource(ResourceType _type, void* _native, uint32_t _state = UINT_MAX) : BaseStructure(Resource::s_structType, kStructVersion1), type(_type), native(_native), state(_state) {};
|
||||
|
||||
//! Conversion helpers for D3D
|
||||
inline operator ID3D12Resource* () { return reinterpret_cast<ID3D12Resource*>(native); }
|
||||
inline operator ID3D11Resource* () { return reinterpret_cast<ID3D11Resource*>(native); }
|
||||
inline operator ID3D11Buffer* () { return reinterpret_cast<ID3D11Buffer*>(native); }
|
||||
inline operator ID3D11Texture2D* () { return reinterpret_cast<ID3D11Texture2D*>(native); }
|
||||
|
||||
//! Indicates the type of resource
|
||||
ResourceType type = ResourceType::eTex2d;
|
||||
//! ID3D11Resource/ID3D12Resource/VkBuffer/VkImage
|
||||
void* native{};
|
||||
//! vkDeviceMemory or nullptr
|
||||
void* memory{};
|
||||
//! VkImageView/VkBufferView or nullptr
|
||||
void* view{};
|
||||
//! State as D3D12_RESOURCE_STATES or VkImageLayout
|
||||
//!
|
||||
//! IMPORTANT: State is MANDATORY and needs to be correct when tagged resources are actually used.
|
||||
//!
|
||||
uint32_t state = UINT_MAX;
|
||||
//! Width in pixels
|
||||
uint32_t width{};
|
||||
//! Height in pixels
|
||||
uint32_t height{};
|
||||
//! Native format
|
||||
uint32_t nativeFormat{};
|
||||
//! Number of mip-map levels
|
||||
uint32_t mipLevels{};
|
||||
//! Number of arrays
|
||||
uint32_t arrayLayers{};
|
||||
//! Virtual address on GPU (if applicable)
|
||||
uint64_t gpuVirtualAddress{};
|
||||
//! VkImageCreateFlags
|
||||
uint32_t flags;
|
||||
//! VkImageUsageFlags
|
||||
uint32_t usage{};
|
||||
//! Reserved for internal use
|
||||
uint32_t reserved{};
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
//! Specifies life-cycle for the tagged resource
|
||||
//!
|
||||
//! IMPORTANT: Use 'eOnlyValidNow' and 'eValidUntilEvaluate' ONLY when really needed since it can result in wasting VRAM if SL ends up making unnecessary copies.
|
||||
//!
|
||||
//! If integrating features, like for example DLSS-G, which require tags to be 'eValidUntilPresent' please try to tag everything as 'eValidUntilPresent' first
|
||||
//! and only make modifications if upon visual inspection you notice that tags are corrupted when used during the Present frame call.
|
||||
enum ResourceLifecycle
|
||||
{
|
||||
//! Resource can change, get destroyed or reused for other purposes after it is provided to SL
|
||||
eOnlyValidNow,
|
||||
//! Resource does NOT change, gets destroyed or reused for other purposes from the moment it is provided to SL until the frame is presented
|
||||
eValidUntilPresent,
|
||||
//! Resource does NOT change, gets destroyed or reused for other purposes from the moment it is provided to SL until after the slEvaluateFeature call has returned.
|
||||
eValidUntilEvaluate
|
||||
};
|
||||
|
||||
//! Tagged resource
|
||||
//!
|
||||
//! {4C6A5AAD-B445-496C-87FF-1AF3845BE653}
|
||||
//! Extensions as part of the `next` ptr:
|
||||
//! PrecisionInfo
|
||||
SL_STRUCT_BEGIN(ResourceTag, StructType({ 0x4c6a5aad, 0xb445, 0x496c, { 0x87, 0xff, 0x1a, 0xf3, 0x84, 0x5b, 0xe6, 0x53 } }), kStructVersion1)
|
||||
ResourceTag(Resource* r, BufferType t, ResourceLifecycle l, const Extent* e = nullptr)
|
||||
: BaseStructure(ResourceTag::s_structType, kStructVersion1), resource(r), type(t), lifecycle(l)
|
||||
{
|
||||
if (e) extent = *e;
|
||||
};
|
||||
|
||||
//! Resource description
|
||||
Resource* resource{};
|
||||
//! Type of the tagged buffer
|
||||
BufferType type{};
|
||||
//! The life-cycle for the tag, if resource is volatile a valid command buffer must be specified
|
||||
ResourceLifecycle lifecycle{};
|
||||
//! The area of the tagged resource to use (if using the entire resource leave as null)
|
||||
Extent extent{};
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
//
|
||||
//! Precision info, optional extension for ResourceTag.
|
||||
//!
|
||||
//! {98F6E9BA-8D16-4831-A802-4D3B52FF26BF}
|
||||
//! Extensions as part of the `next` ptr:
|
||||
//! ResourceTag
|
||||
SL_STRUCT_BEGIN(PrecisionInfo, StructType({ 0x98f6e9ba, 0x8d16, 0x4831, { 0xa8, 0x2, 0x4d, 0x3b, 0x52, 0xff, 0x26, 0xbf } }), kStructVersion1)
|
||||
// Formula used to convert the low-precision data to high-precision
|
||||
enum PrecisionFormula : uint32_t
|
||||
{
|
||||
eNoTransform = 0, // hi = lo, essentially no conversion is done
|
||||
eLinearTransform, // hi = lo * scale + bias
|
||||
};
|
||||
|
||||
PrecisionInfo(PrecisionInfo::PrecisionFormula formula, float bias, float scale)
|
||||
: BaseStructure(PrecisionInfo::s_structType, kStructVersion1), conversionFormula(formula), bias(bias), scale(scale) {};
|
||||
|
||||
static std::string getPrecisionFormulaAsStr(PrecisionFormula formula)
|
||||
{
|
||||
switch (formula)
|
||||
{
|
||||
case eNoTransform:
|
||||
return "eNoTransform";
|
||||
case eLinearTransform:
|
||||
return "eLinearTransform";
|
||||
default:
|
||||
assert("Invalid PrecisionFormula" && false);
|
||||
return "Unknown";
|
||||
}
|
||||
};
|
||||
|
||||
PrecisionFormula conversionFormula{ eNoTransform };
|
||||
float bias{ 0.0f };
|
||||
float scale{ 1.0f };
|
||||
|
||||
inline operator bool() const { return conversionFormula != eNoTransform; }
|
||||
inline bool operator==(const PrecisionInfo& rhs) const
|
||||
{
|
||||
return conversionFormula == rhs.conversionFormula && bias == rhs.bias && scale == rhs.scale;
|
||||
}
|
||||
inline bool operator!=(const PrecisionInfo& rhs) const
|
||||
{
|
||||
return !operator==(rhs);
|
||||
}
|
||||
SL_STRUCT_END()
|
||||
|
||||
//! Resource allocation/deallocation callbacks
|
||||
//!
|
||||
//! Use these callbacks to gain full control over
|
||||
//! resource life cycle and memory allocation tracking.
|
||||
//!
|
||||
//! @param device - Device to be used (vkDevice or ID3D11Device or ID3D12Device)
|
||||
//!
|
||||
//! IMPORTANT: Textures must have the pixel shader resource
|
||||
//! and the unordered access view flags set
|
||||
using PFun_ResourceAllocateCallback = Resource(const ResourceAllocationDesc* desc, void* device);
|
||||
using PFun_ResourceReleaseCallback = void(Resource* resource, void* device);
|
||||
|
||||
//! Log type
|
||||
enum class LogType : uint32_t
|
||||
{
|
||||
//! Controlled by LogLevel, SL can show more information in eLogLevelVerbose mode
|
||||
eInfo,
|
||||
//! Always shown regardless of LogLevel
|
||||
eWarn,
|
||||
eError,
|
||||
//! Total count
|
||||
eCount
|
||||
};
|
||||
|
||||
//! Logging callback
|
||||
//!
|
||||
//! Use these callbacks to track messages posted in the log.
|
||||
//! If any of the SL methods returns false use eLogTypeError
|
||||
//! type to track down what went wrong and why.
|
||||
using PFun_LogMessageCallback = void(LogType type, const char* msg);
|
||||
|
||||
struct APIError
|
||||
{
|
||||
union
|
||||
{
|
||||
HRESULT hres;
|
||||
SL_VKResult vkRes;
|
||||
};
|
||||
};
|
||||
//! Returns an error returned by DXGI or Vulkan API calls 'vkQueuePresentKHR' and 'vkAcquireNextImageKHR'
|
||||
using PFunOnAPIErrorCallback = void(const APIError& lastError);
|
||||
|
||||
//! Optional flags
|
||||
enum class PreferenceFlags : uint64_t
|
||||
{
|
||||
//! Set by default - Disables command list state tracking - Host application is responsible for restoring CL state correctly after each 'slEvaluateFeature' call
|
||||
eDisableCLStateTracking = 1 << 0,
|
||||
//! Optional - Disables debug text on screen in development builds
|
||||
eDisableDebugText = 1 << 1,
|
||||
//! Optional - IMPORTANT: Only to be used in the advanced integration mode, see the 'manual hooking' programming guide for more details
|
||||
eUseManualHooking = 1 << 2,
|
||||
//! Optional - Enables downloading of Over The Air (OTA) updates for SL and NGX
|
||||
//! This will invoke the OTA updater to look for new updates. A separate
|
||||
//! flag below is used to control whether or not OTA-downloaded SL Plugins are
|
||||
//! loaded.
|
||||
eAllowOTA = 1 << 3,
|
||||
//! Do not check OS version when deciding if feature is supported or not
|
||||
//!
|
||||
//! IMPORTANT: ONLY SET THIS FLAG IF YOU KNOW WHAT YOU ARE DOING.
|
||||
//!
|
||||
//! VARIOUS WIN APIs INCLUDING BUT NOT LIMITED TO `IsWindowsXXX`, `GetVersionX`, `rtlGetVersion` ARE KNOWN FOR RETURNING INCORRECT RESULTS.
|
||||
eBypassOSVersionCheck = 1 << 4,
|
||||
//! Optional - If specified SL will create DXGI factory proxy rather than modifying the v-table for the base interface.
|
||||
//!
|
||||
//! This can help with 3rd party overlays which are NOT integrated with the host application but rather operate via injection.
|
||||
eUseDXGIFactoryProxy = 1 << 5,
|
||||
//! Optional - Enables loading of plugins downloaded Over The Air (OTA), to
|
||||
//! be used in conjunction with the eAllowOTA flag.
|
||||
eLoadDownloadedPlugins = 1 << 6,
|
||||
|
||||
//! Optional - allow tagging of resources for frame. This helps distinguish whether slEvaluateFeature needs to do frame-based tagging
|
||||
//! of resources which wasn't the case earlier.
|
||||
eUseFrameBasedResourceTagging = 1 << 7,
|
||||
|
||||
//! All preference flags. This isn't expected to be used directly by integrations, but may be useful for e.g. writing helpers.
|
||||
eAll = eDisableCLStateTracking | eDisableDebugText | eUseManualHooking | eAllowOTA | eBypassOSVersionCheck | eUseDXGIFactoryProxy | eLoadDownloadedPlugins | eUseFrameBasedResourceTagging
|
||||
};
|
||||
|
||||
SL_ENUM_OPERATORS_64(PreferenceFlags)
|
||||
|
||||
//! Application preferences
|
||||
//!
|
||||
//! {1CA10965-BF8E-432B-8DA1-6716D879FB14}
|
||||
SL_STRUCT_BEGIN(Preferences, StructType({ 0x1ca10965, 0xbf8e, 0x432b, { 0x8d, 0xa1, 0x67, 0x16, 0xd8, 0x79, 0xfb, 0x14 } }), kStructVersion1)
|
||||
//! Optional - In non-production builds it is useful to enable debugging console window
|
||||
bool showConsole = false;
|
||||
//! Optional - Various logging levels
|
||||
LogLevel logLevel = LogLevel::eDefault;
|
||||
//! Optional - Absolute paths to locations where to look for plugins, first path in the list has the highest priority
|
||||
const wchar_t** pathsToPlugins{};
|
||||
//! Optional - Number of paths to search
|
||||
uint32_t numPathsToPlugins = 0;
|
||||
//! Optional - Absolute path to location where logs and other data should be stored
|
||||
//!
|
||||
//! NOTE: Set this to nullptr in order to disable logging to a file
|
||||
const wchar_t* pathToLogsAndData{};
|
||||
//! Optional - Allows resource allocation tracking on the host side
|
||||
PFun_ResourceAllocateCallback* allocateCallback{};
|
||||
//! Optional - Allows resource deallocation tracking on the host side
|
||||
PFun_ResourceReleaseCallback* releaseCallback{};
|
||||
//! Optional - Allows log message tracking including critical errors if they occur
|
||||
PFun_LogMessageCallback* logMessageCallback{};
|
||||
//! Optional - Flags used to enable or disable advanced options
|
||||
PreferenceFlags flags = PreferenceFlags::eDisableCLStateTracking | PreferenceFlags::eAllowOTA | PreferenceFlags::eLoadDownloadedPlugins;
|
||||
//! Required - Features to load (assuming appropriate plugins are found), if not specified NO features will be loaded by default
|
||||
const Feature* featuresToLoad{};
|
||||
//! Required - Number of features to load, only used when list is not a null pointer
|
||||
uint32_t numFeaturesToLoad{};
|
||||
//! Optional - Id provided by NVIDIA, if not specified then engine type and version are required
|
||||
uint32_t applicationId{};
|
||||
//! Optional - Type of the rendering engine used, if not specified then applicationId is required
|
||||
EngineType engine = EngineType::eCustom;
|
||||
//! Optional - Version of the rendering engine used
|
||||
const char* engineVersion{};
|
||||
//! Optional - GUID (like for example 'a0f57b54-1daf-4934-90ae-c4035c19df04')
|
||||
const char* projectId{};
|
||||
//! Optional - Which rendering API host is planning to use
|
||||
//!
|
||||
//! NOTE: To ensure correct `slGetFeatureRequirements` behavior please specify if planning to use Vulkan.
|
||||
RenderAPI renderAPI = RenderAPI::eD3D12;
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
//! Frame tracking handle
|
||||
//!
|
||||
//! IMPORTANT: Use slGetNewFrameToken to obtain unique instance
|
||||
//!
|
||||
//! {830A0F35-DB84-4171-A804-59B206499B18}
|
||||
SL_STRUCT_PROTECTED_BEGIN(FrameToken, StructType({ 0x830a0f35, 0xdb84, 0x4171, { 0xa8, 0x4, 0x59, 0xb2, 0x6, 0x49, 0x9b, 0x18 } }), kStructVersion1)
|
||||
//! Helper operator to obtain current frame index
|
||||
virtual operator uint32_t() const = 0;
|
||||
SL_STRUCT_END()
|
||||
|
||||
//! Handle for the unique viewport
|
||||
//!
|
||||
//! {171B6435-9B3C-4FC8-9994-FBE52569AAA4}
|
||||
SL_STRUCT_BEGIN(ViewportHandle, StructType({ 0x171b6435, 0x9b3c, 0x4fc8, { 0x99, 0x94, 0xfb, 0xe5, 0x25, 0x69, 0xaa, 0xa4 } }), kStructVersion1)
|
||||
ViewportHandle(uint32_t v) : BaseStructure(ViewportHandle::s_structType, kStructVersion1), value(v) {}
|
||||
ViewportHandle(int32_t v) : BaseStructure(ViewportHandle::s_structType, kStructVersion1), value(v) {}
|
||||
operator uint32_t() const { return value; }
|
||||
private:
|
||||
uint32_t value = UINT_MAX;
|
||||
friend constexpr void sl::test::AbiValidation();
|
||||
SL_STRUCT_END()
|
||||
|
||||
//! Specifies feature requirement flags
|
||||
//!
|
||||
enum class FeatureRequirementFlags : uint32_t
|
||||
{
|
||||
//! Rendering APIs
|
||||
eD3D11Supported = 1 << 0,
|
||||
eD3D12Supported = 1 << 1,
|
||||
eVulkanSupported = 1 << 2,
|
||||
//! If set V-Sync must be disabled when feature is active
|
||||
eVSyncOffRequired = 1 << 3,
|
||||
//! If set GPU hardware scheduling OS feature must be turned on
|
||||
eHardwareSchedulingRequired = 1 << 4,
|
||||
|
||||
//! All feature requirement flags. This isn't expected to be used directly by integrations, but may be useful for e.g. writing helpers.
|
||||
eAll = eD3D11Supported | eD3D12Supported | eVulkanSupported | eVSyncOffRequired | eHardwareSchedulingRequired
|
||||
};
|
||||
|
||||
SL_ENUM_OPERATORS_32(FeatureRequirementFlags);
|
||||
|
||||
//! Specifies feature requirements
|
||||
//!
|
||||
//! {66714097-AC6D-4BC6-8915-1E0F55A6B61F}
|
||||
SL_STRUCT_BEGIN(FeatureRequirements, StructType({ 0x66714097, 0xac6d, 0x4bc6, { 0x89, 0x15, 0x1e, 0xf, 0x55, 0xa6, 0xb6, 0x1f } }), kStructVersion2)
|
||||
//! Various Flags
|
||||
FeatureRequirementFlags flags {};
|
||||
|
||||
//! Feature will create this many CPU threads
|
||||
uint32_t maxNumCPUThreads{};
|
||||
|
||||
//! Feature supports only this many viewports
|
||||
uint32_t maxNumViewports{};
|
||||
|
||||
//! Required buffer tags
|
||||
uint32_t numRequiredTags{};
|
||||
const BufferType* requiredTags{};
|
||||
|
||||
//! OS and Driver versions
|
||||
Version osVersionDetected{};
|
||||
Version osVersionRequired{};
|
||||
Version driverVersionDetected{};
|
||||
Version driverVersionRequired{};
|
||||
|
||||
//! Vulkan specific bits
|
||||
|
||||
//! Command queues
|
||||
uint32_t vkNumComputeQueuesRequired{};
|
||||
uint32_t vkNumGraphicsQueuesRequired{};
|
||||
|
||||
//! Device extensions
|
||||
uint32_t vkNumDeviceExtensions{};
|
||||
const char** vkDeviceExtensions{};
|
||||
//! Instance extensions
|
||||
uint32_t vkNumInstanceExtensions{};
|
||||
const char** vkInstanceExtensions{};
|
||||
//! 1.2 features
|
||||
//!
|
||||
//! NOTE: Use getVkPhysicalDeviceVulkan12Features from sl_helpers_vk.h
|
||||
uint32_t vkNumFeatures12{};
|
||||
const char** vkFeatures12{};
|
||||
//! 1.3 features
|
||||
//!
|
||||
//! NOTE: Use getVkPhysicalDeviceVulkan13Features from sl_helpers_vk.h
|
||||
uint32_t vkNumFeatures13{};
|
||||
const char** vkFeatures13{};
|
||||
|
||||
//! Vulkan optical flow feature
|
||||
uint32_t vkNumOpticalFlowQueuesRequired{};
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
//! Specifies feature's version
|
||||
//!
|
||||
//! {6D5B51F0-076B-486D-9995-5A561043F5C1}
|
||||
SL_STRUCT_BEGIN(FeatureVersion, StructType({ 0x6d5b51f0, 0x76b, 0x486d, { 0x99, 0x95, 0x5a, 0x56, 0x10, 0x43, 0xf5, 0xc1 } }), kStructVersion1)
|
||||
//! SL version
|
||||
Version versionSL{};
|
||||
//! NGX version (if feature is using NGX, null otherwise)
|
||||
Version versionNGX{};
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
//! Specifies either DXGI adapter or VK physical device
|
||||
//!
|
||||
//! {0677315F-A746-4492-9F42-CB6142C9C3D4}
|
||||
SL_STRUCT_BEGIN(AdapterInfo, StructType({ 0x677315f, 0xa746, 0x4492, { 0x9f, 0x42, 0xcb, 0x61, 0x42, 0xc9, 0xc3, 0xd4 } }), kStructVersion1)
|
||||
//! Locally unique identifier
|
||||
uint8_t* deviceLUID {};
|
||||
//! Size in bytes
|
||||
uint32_t deviceLUIDSizeInBytes{};
|
||||
//! Vulkan Specific, if specified LUID will be ignored
|
||||
void* vkPhysicalDevice{};
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
//! A simple array wrapper designed for safe use across DLL boundaries.
|
||||
//! Since different DLLs may use different memory allocators, this class
|
||||
//! relies on an IAllocator pointer to ensure that memory is allocated
|
||||
//! and freed consistently within the same runtime.
|
||||
struct IAllocator
|
||||
{
|
||||
virtual ~IAllocator() = default;
|
||||
virtual void *allocate(uint32_t nBytes) = 0;
|
||||
virtual void free(void *p) = 0;
|
||||
};
|
||||
template <class T>
|
||||
struct Array
|
||||
{
|
||||
inline Array() {}
|
||||
inline ~Array() { destroy(); }
|
||||
inline uint32_t size() const { return m_size; }
|
||||
inline void copyFrom(IAllocator *pAllocator, const std::vector<T>& src)
|
||||
{
|
||||
// if they give us data - we need the allocator
|
||||
assert(pAllocator || src.size() == 0);
|
||||
destroy();
|
||||
if (src.size() == 0) return;
|
||||
m_pAllocator = pAllocator;
|
||||
m_size = static_cast<uint32_t>(src.size());
|
||||
m_pData = (T*)m_pAllocator->allocate(m_size * sizeof(T));
|
||||
for (uint32_t i = 0; i < m_size; ++i)
|
||||
m_pData[i] = src[i];
|
||||
}
|
||||
inline void copyTo(std::vector<T>& dst)
|
||||
{
|
||||
dst.resize(m_size);
|
||||
for (uint32_t i = 0; i < m_size; ++i)
|
||||
dst[i] = m_pData[i];
|
||||
}
|
||||
inline T& operator[](uint32_t index)
|
||||
{
|
||||
assert(index < m_size);
|
||||
return m_pData[index];
|
||||
}
|
||||
inline const T& operator[](uint32_t index) const
|
||||
{
|
||||
assert(index < m_size);
|
||||
return m_pData[index];
|
||||
}
|
||||
inline void destroy()
|
||||
{
|
||||
if (m_pData) m_pAllocator->free(m_pData);
|
||||
m_pAllocator = nullptr;
|
||||
m_pData = nullptr;
|
||||
m_size = 0;
|
||||
}
|
||||
// Prevent copying
|
||||
Array(const Array&) = delete;
|
||||
Array& operator=(const Array&) = delete;
|
||||
private:
|
||||
T* m_pData{};
|
||||
uint32_t m_size{};
|
||||
// the allocator that was used to allocate memory
|
||||
IAllocator *m_pAllocator{};
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sl.h"
|
||||
#include "sl_helpers.h"
|
||||
|
||||
namespace sl
|
||||
{
|
||||
|
||||
enum class DeepDVCMode : uint32_t
|
||||
{
|
||||
eOff,
|
||||
eOn,
|
||||
eCount
|
||||
};
|
||||
|
||||
// {23288AAD-7E7E-BE2A-916F-27DA30A3046B}
|
||||
SL_STRUCT_BEGIN(DeepDVCOptions, StructType({ 0x23288aad, 0x7e7e, 0xbe2a, { 0x91, 0x67, 0x27, 0xda, 0x30, 0xa3, 0x04, 0x6b } }), kStructVersion1)
|
||||
//! Specifies which mode should be used
|
||||
DeepDVCMode mode = DeepDVCMode::eOff;
|
||||
//! Specifies intensity level in range [0,1]. Default 0.5
|
||||
float intensity = 0.5f;
|
||||
//! Specifies saturation boost in range [0,1]. Default 0.25
|
||||
float saturationBoost = 0.25f;
|
||||
SL_STRUCT_END()
|
||||
|
||||
//! Returned by the DeepDVC plugin
|
||||
//!
|
||||
// {934FD3D3-B34C-70A7-A139-F19FE04D91D3}
|
||||
SL_STRUCT_BEGIN(DeepDVCState, StructType({ 0x934fd3d3, 0xb34c, 0x70a7, { 0xa1, 0x39, 0xf1, 0x9f, 0xe0, 0x4d, 0x91, 0xd3 } }), kStructVersion1)
|
||||
//! Specified the amount of memory expected to be used
|
||||
uint64_t estimatedVRAMUsageInBytes {};
|
||||
SL_STRUCT_END()
|
||||
|
||||
}
|
||||
|
||||
//! Sets DeepDVC options
|
||||
//!
|
||||
//! Call this method to turn DeepDVC on/off, change mode etc.
|
||||
//!
|
||||
//! @param viewport Specified viewport we are working with
|
||||
//! @param options Specifies DeepDVC options to use
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is NOT thread safe.
|
||||
using PFun_slDeepDVCSetOptions = sl::Result(const sl::ViewportHandle& viewport, const sl::DeepDVCOptions& options);
|
||||
|
||||
//! Provides DeepDVC state for the given viewport
|
||||
//!
|
||||
//! Call this method to obtain VRAM usage and other information.
|
||||
//!
|
||||
//! @param viewport Specified viewport we are working with
|
||||
//! @param state Reference to a structure where state is to be returned
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is NOT thread safe.
|
||||
using PFun_slDeepDVCGetState = sl::Result(const sl::ViewportHandle& viewport, sl::DeepDVCState& state);
|
||||
|
||||
//! HELPERS
|
||||
//!
|
||||
inline sl::Result slDeepDVCSetOptions(const sl::ViewportHandle& viewport, const sl::DeepDVCOptions& options)
|
||||
{
|
||||
SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureDeepDVC, slDeepDVCSetOptions);
|
||||
return s_slDeepDVCSetOptions(viewport, options);
|
||||
}
|
||||
|
||||
inline sl::Result slDeepDVCGetState(const sl::ViewportHandle& viewport, sl::DeepDVCState& state)
|
||||
{
|
||||
SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureDeepDVC, slDeepDVCGetState);
|
||||
return s_slDeepDVCGetState(viewport, state);
|
||||
}
|
||||
//#define SL_CASE_STR(a) case a : return #a;
|
||||
|
||||
inline const char* getDeepDVCModeAsStr(sl::DeepDVCMode v)
|
||||
{
|
||||
switch (v)
|
||||
{
|
||||
SL_CASE_STR(sl::DeepDVCMode::eOff);
|
||||
SL_CASE_STR(sl::DeepDVCMode::eOn);
|
||||
};
|
||||
return "Unknown";
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "sl_struct.h"
|
||||
|
||||
namespace sl
|
||||
{
|
||||
|
||||
//! Rendering API
|
||||
//!
|
||||
enum class RenderAPI : uint32_t
|
||||
{
|
||||
eD3D11,
|
||||
eD3D12,
|
||||
eVulkan,
|
||||
eCount
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (c) 2024 NVIDIA CORPORATION. All rights reserved
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sl_struct.h"
|
||||
#include <dxgi.h>
|
||||
|
||||
struct ID3D12CommandQueue;
|
||||
namespace sl
|
||||
{
|
||||
|
||||
enum class DirectSROptimizationType : uint32_t
|
||||
{
|
||||
eBalanced,
|
||||
eHighQuality,
|
||||
eMaxQuality,
|
||||
eHighPerformance,
|
||||
eMaxPerformance,
|
||||
ePowerSaving,
|
||||
eMaxPowerSaving,
|
||||
|
||||
eCount
|
||||
};
|
||||
|
||||
enum class DirectSRVariantFlags : uint32_t
|
||||
{
|
||||
eNone = 0x0,
|
||||
eSupportsExposureScaleTexture = 0x1,
|
||||
eSupportsIgnoreHistoryMask = 0x2,
|
||||
eNative = 0x4,
|
||||
eSupportsReactiveMask = 0x8,
|
||||
eSupportsSharpness = 0x10,
|
||||
eDisallowsRegionOffsets = 0x20,
|
||||
|
||||
eAll = eSupportsExposureScaleTexture | eSupportsIgnoreHistoryMask | eNative | eSupportsReactiveMask | eSupportsSharpness | eDisallowsRegionOffsets
|
||||
};
|
||||
|
||||
// {1AD87504-774E-4BF3-9633-A44D1F7F9CB8}
|
||||
SL_STRUCT_BEGIN(DirectSROptions, StructType({ 0x1ad87504, 0x774e, 0x4bf3, { 0x96, 0x33, 0xa4, 0x4d, 0x1f, 0x7f, 0x9c, 0xb8 } }), kStructVersion1)
|
||||
// DirectSR variant index as enumerated
|
||||
uint32_t variantIndex;
|
||||
|
||||
// D3D12 command queue to execute work on
|
||||
ID3D12CommandQueue *pCommandQueue;
|
||||
|
||||
//! Specifies which mode should be used
|
||||
DirectSROptimizationType optType;
|
||||
|
||||
//! Specifies output (final) target width
|
||||
uint32_t outputWidth = INVALID_UINT;
|
||||
|
||||
//! Specifies output (final) target height
|
||||
uint32_t outputHeight = INVALID_UINT;
|
||||
|
||||
//! Specifies sharpening level in range [0,1]
|
||||
float sharpness = 0.0f;
|
||||
|
||||
//! Specifies pre-exposure value
|
||||
float preExposure = 1.0f;
|
||||
|
||||
//! Specifies exposure scale value
|
||||
float exposureScale = 1.0f;
|
||||
|
||||
//! Specifies if tagged color buffers are full HDR or not (DLSS in HDR pipeline or not)
|
||||
Boolean colorBuffersHDR = Boolean::eTrue;
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
//! Returned by DirectSR plugin
|
||||
//!
|
||||
//! {1BD0C637-A28F-41F2-BC91-B421FAEE8E1E}
|
||||
SL_STRUCT_BEGIN(DirectSROptimalSettings, StructType({ 0x1bd0c637, 0xa28f, 0x41f2, { 0xbc, 0x91, 0xb4, 0x21, 0xfa, 0xee, 0x8e, 0x1e } }), kStructVersion1)
|
||||
//! Specifies render area width
|
||||
uint32_t optimalRenderWidth{};
|
||||
//! Specifies render area height
|
||||
uint32_t optimalRenderHeight{};
|
||||
//! Specifies minimal render area width
|
||||
uint32_t renderWidthMin{};
|
||||
//! Specifies minimal render area height
|
||||
uint32_t renderHeightMin{};
|
||||
//! Specifies maximal render area width
|
||||
uint32_t renderWidthMax{};
|
||||
//! Specifies maximal render area height
|
||||
uint32_t renderHeightMax{};
|
||||
|
||||
// optimal color format
|
||||
DXGI_FORMAT optimalColorFormat;
|
||||
|
||||
// optimal depth format
|
||||
DXGI_FORMAT optimalDepthFormat;
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
//! Returned by DirectSR plugin
|
||||
//!
|
||||
//! {38216184-79ba-48cb-93f5-7a8a59382fdf}
|
||||
SL_STRUCT_BEGIN(DirectSRVariantInfo, StructType({ 0x38216184, 0x79ba, 0x48cb, { 0x93, 0xf5, 0x7a, 0x8a, 0x59, 0x38, 0x2f, 0xdf } }), kStructVersion1)
|
||||
char name[128];
|
||||
sl::DirectSRVariantFlags flags;
|
||||
sl::DirectSROptimizationType optimizationRankings[7];
|
||||
DXGI_FORMAT optimalTargetFormat;
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
}
|
||||
|
||||
//! Provides optimal DirectSR settings
|
||||
//!
|
||||
//! Call this method to obtain optimal render target size and other DirectSR related settings.
|
||||
//!
|
||||
//! @param options Specifies DirectSR options to use
|
||||
//! @param settings Reference to a structure where settings are returned
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is NOT thread safe.
|
||||
using PFun_slDirectSRGetOptimalSettings = sl::Result(const sl::DirectSROptions & options, sl::DirectSROptimalSettings & settings);
|
||||
|
||||
//! Retrive information about the available DirectSR variants.
|
||||
using PFun_slDirectSRGetVariantInfo = sl::Result(uint32_t *numVariants, sl::DirectSRVariantInfo *variantInfo);
|
||||
|
||||
//! Sets DirectSR options
|
||||
//!
|
||||
//! Call this method to turn DirectSR on/off, change mode etc.
|
||||
//!
|
||||
//! @param viewport Specified viewport we are working with
|
||||
//! @param options Specifies DirectSR options to use
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is NOT thread safe.
|
||||
using PFun_slDirectSRSetOptions = sl::Result(const sl::ViewportHandle& viewport, const sl::DirectSROptions& options);
|
||||
|
||||
//! HELPERS
|
||||
//!
|
||||
inline sl::Result slDirectSRGetOptimalSettings(const sl::DirectSROptions& options, sl::DirectSROptimalSettings& settings)
|
||||
{
|
||||
SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureDirectSR, slDirectSRGetOptimalSettings);
|
||||
return s_slDirectSRGetOptimalSettings(options, settings);
|
||||
}
|
||||
|
||||
inline sl::Result slDirectSRGetVariantInfo(uint32_t *numVariants, sl::DirectSRVariantInfo *variantInfo)
|
||||
{
|
||||
SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureDirectSR, slDirectSRGetVariantInfo);
|
||||
return s_slDirectSRGetVariantInfo(numVariants, variantInfo);
|
||||
}
|
||||
|
||||
inline sl::Result slDirectSRSetOptions(const sl::ViewportHandle& viewport, const sl::DirectSROptions& options)
|
||||
{
|
||||
SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureDirectSR, slDirectSRSetOptions);
|
||||
return s_slDirectSRSetOptions(viewport, options);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus >= 201402L
|
||||
#define SR_DEPRECATED_SHARPENING [[deprecated("Sharpness is not supported")]]
|
||||
#else
|
||||
#define SR_DEPRECATED_SHARPENING
|
||||
#endif
|
||||
|
||||
namespace sl
|
||||
{
|
||||
|
||||
enum class DLSSMode : uint32_t
|
||||
{
|
||||
eOff,
|
||||
eMaxPerformance,
|
||||
eBalanced,
|
||||
eMaxQuality,
|
||||
eUltraPerformance,
|
||||
eUltraQuality,
|
||||
eDLAA,
|
||||
eCount,
|
||||
};
|
||||
|
||||
enum class DLSSPreset : uint32_t
|
||||
{
|
||||
//! Default behavior, may or may not change after an OTA
|
||||
eDefault,
|
||||
//! Fixed DL models
|
||||
// ePresetA removed, use presets J or K
|
||||
// ePresetB removed, use presets J or K
|
||||
// ePresetC removed, use presets J or K
|
||||
// ePresetD removed, use presets J or K
|
||||
// ePresetE removed, use presets J or K
|
||||
ePresetF = 6, // Intended for Ultra Perf/DLAA modes. The default preset for Ultra Perf
|
||||
ePresetG = 7, // Reverts to default, not recommended to use
|
||||
ePresetH = 8, // Reverts to default, not recommended to use
|
||||
ePresetI = 9, // Reverts to default, not recommended to use
|
||||
ePresetJ = 10, // Similar to preset K. Preset J might exhibit slightly less ghosting at the cost of extra flickering. Preset K is generally recommended over preset J
|
||||
ePresetK = 11, // Default preset for DLAA/Perf/Balanced/Quality modes that is transformer based. Best image quality preset at a higher performance cost
|
||||
ePresetL = 12, // Reverts to default, not recommended to use
|
||||
ePresetM = 13, // Reverts to default, not recommended to use
|
||||
ePresetN = 14, // Reverts to default, not recommended to use
|
||||
ePresetO = 15, // Reverts to default, not recommended to use
|
||||
|
||||
eCount
|
||||
};
|
||||
|
||||
// {6AC826E4-4C61-4101-A92D-638D421057B8}
|
||||
SL_STRUCT_BEGIN(DLSSOptions, StructType({ 0x6ac826e4, 0x4c61, 0x4101, { 0xa9, 0x2d, 0x63, 0x8d, 0x42, 0x10, 0x57, 0xb8 } }), kStructVersion3)
|
||||
//! Specifies which mode should be used
|
||||
DLSSMode mode = DLSSMode::eOff;
|
||||
//! Specifies output (final) target width
|
||||
uint32_t outputWidth = INVALID_UINT;
|
||||
//! Specifies output (final) target height
|
||||
uint32_t outputHeight = INVALID_UINT;
|
||||
//! Specifies sharpening level in range [0,1] this is a deprecated field
|
||||
float sharpness SR_DEPRECATED_SHARPENING = 0.0f;
|
||||
//! Specifies pre-exposure value
|
||||
float preExposure = 1.0f;
|
||||
//! Specifies exposure scale value
|
||||
float exposureScale = 1.0f;
|
||||
//! Specifies if tagged color buffers are full HDR or not (DLSS in HDR pipeline or not)
|
||||
Boolean colorBuffersHDR = Boolean::eTrue;
|
||||
//! Specifies if indicator on screen should invert axis
|
||||
Boolean indicatorInvertAxisX = Boolean::eFalse;
|
||||
//! Specifies if indicator on screen should invert axis
|
||||
Boolean indicatorInvertAxisY = Boolean::eFalse;
|
||||
//! Presets
|
||||
DLSSPreset dlaaPreset = DLSSPreset::eDefault;
|
||||
DLSSPreset qualityPreset = DLSSPreset::eDefault;
|
||||
DLSSPreset balancedPreset = DLSSPreset::eDefault;
|
||||
DLSSPreset performancePreset = DLSSPreset::eDefault;
|
||||
DLSSPreset ultraPerformancePreset = DLSSPreset::eDefault;
|
||||
DLSSPreset ultraQualityPreset = DLSSPreset::eDefault;
|
||||
|
||||
//! Specifies if the setting for AutoExposure is used
|
||||
Boolean useAutoExposure = Boolean::eFalse;
|
||||
|
||||
//! Whether or not the alpha channel should be upscaled (if false, only RGB is upscaled)
|
||||
//! Enabling alpha upscaling may impact performance
|
||||
Boolean alphaUpscalingEnabled = Boolean::eFalse;
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
//! Returned by DLSS plugin
|
||||
//!
|
||||
//! {EF1D0957-FD58-4DF7-B504-8B69D8AA6B76}
|
||||
SL_STRUCT_BEGIN(DLSSOptimalSettings, StructType({ 0xef1d0957, 0xfd58, 0x4df7, { 0xb5, 0x4, 0x8b, 0x69, 0xd8, 0xaa, 0x6b, 0x76 } }), kStructVersion1)
|
||||
//! Specifies render area width
|
||||
uint32_t optimalRenderWidth{};
|
||||
//! Specifies render area height
|
||||
uint32_t optimalRenderHeight{};
|
||||
//! Specifies the optimal sharpness value
|
||||
float optimalSharpness{};
|
||||
//! Specifies minimal render area width
|
||||
uint32_t renderWidthMin{};
|
||||
//! Specifies minimal render area height
|
||||
uint32_t renderHeightMin{};
|
||||
//! Specifies maximal render area width
|
||||
uint32_t renderWidthMax{};
|
||||
//! Specifies maximal render area height
|
||||
uint32_t renderHeightMax{};
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
//! Returned by DLSS plugin
|
||||
//!
|
||||
//! {9366B056-8C01-463C-BB91-E68782636CE9}
|
||||
SL_STRUCT_BEGIN(DLSSState, StructType({ 0x9366b056, 0x8c01, 0x463c, { 0xbb, 0x91, 0xe6, 0x87, 0x82, 0x63, 0x6c, 0xe9 } }), kStructVersion1)
|
||||
//! Specified the amount of memory expected to be used
|
||||
uint64_t estimatedVRAMUsageInBytes{};
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
}
|
||||
|
||||
//! Provides optimal DLSS settings
|
||||
//!
|
||||
//! Call this method to obtain optimal render target size and other DLSS related settings.
|
||||
//!
|
||||
//! @param options Specifies DLSS options to use
|
||||
//! @param settings Reference to a structure where settings are returned
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is NOT thread safe.
|
||||
using PFun_slDLSSGetOptimalSettings = sl::Result(const sl::DLSSOptions & options, sl::DLSSOptimalSettings & settings);
|
||||
|
||||
//! Provides DLSS state for the given viewport
|
||||
//!
|
||||
//! Call this method to obtain optimal render target size and other DLSS related settings.
|
||||
//!
|
||||
//! @param viewport Specified viewport we are working with
|
||||
//! @param state Reference to a structure where state is to be returned
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is NOT thread safe.
|
||||
using PFun_slDLSSGetState = sl::Result(const sl::ViewportHandle & viewport, sl::DLSSState & state);
|
||||
|
||||
//! Sets DLSS options
|
||||
//!
|
||||
//! Call this method to turn DLSS on/off, change mode etc.
|
||||
//!
|
||||
//! @param viewport Specified viewport we are working with
|
||||
//! @param options Specifies DLSS options to use
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is NOT thread safe.
|
||||
using PFun_slDLSSSetOptions = sl::Result(const sl::ViewportHandle& viewport, const sl::DLSSOptions& options);
|
||||
|
||||
//! HELPERS
|
||||
//!
|
||||
inline sl::Result slDLSSGetOptimalSettings(const sl::DLSSOptions& options, sl::DLSSOptimalSettings& settings)
|
||||
{
|
||||
SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureDLSS, slDLSSGetOptimalSettings);
|
||||
return s_slDLSSGetOptimalSettings(options, settings);
|
||||
}
|
||||
|
||||
inline sl::Result slDLSSGetState(const sl::ViewportHandle& viewport, sl::DLSSState& state)
|
||||
{
|
||||
SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureDLSS, slDLSSGetState);
|
||||
return s_slDLSSGetState(viewport, state);
|
||||
}
|
||||
|
||||
inline sl::Result slDLSSSetOptions(const sl::ViewportHandle& viewport, const sl::DLSSOptions& options)
|
||||
{
|
||||
SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureDLSS, slDLSSSetOptions);
|
||||
return s_slDLSSSetOptions(viewport, options);
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright (c) 2023 NVIDIA CORPORATION. All rights reserved
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sl_dlss.h"
|
||||
|
||||
namespace sl
|
||||
{
|
||||
|
||||
enum class DLSSDPreset : uint32_t
|
||||
{
|
||||
//! Default behavior, may or may not change after an OTA
|
||||
eDefault,
|
||||
// ePresetA removed, use preset D or E
|
||||
// ePresetB removed, use preset D or E
|
||||
// ePresetC removed, use preset D or E
|
||||
ePresetD = 4, // Default model (transformer)
|
||||
ePresetE = 5, // Latest transformer model (must use if DoF guide is needed)
|
||||
ePresetF = 6, // Reverts to default
|
||||
ePresetG = 7, // Reverts to default
|
||||
ePresetH = 8, // Reverts to default
|
||||
ePresetI = 9, // Reverts to default
|
||||
ePresetJ = 10, // Reverts to default
|
||||
ePresetK = 11, // Reverts to default
|
||||
ePresetL = 12, // Reverts to default
|
||||
ePresetM = 13, // Reverts to default. Not recommended to use
|
||||
ePresetN = 14, // Reverts to default. Not recommended to use
|
||||
ePresetO = 15, // Reverts to default. Not recommended to use
|
||||
|
||||
eCount
|
||||
};
|
||||
|
||||
enum class DLSSDNormalRoughnessMode : uint32_t
|
||||
{
|
||||
eUnpacked, // App needs to provide Normal resource and Roughness resource separately.
|
||||
ePacked, // App needs to write Roughness to w channel of Normal resource.
|
||||
|
||||
eCount
|
||||
};
|
||||
|
||||
// {0AD87504-774E-4BF3-9633-A44D1F7F9CB8}
|
||||
SL_STRUCT_BEGIN(DLSSDOptions, StructType({ 0x0ad87504, 0x774e, 0x4bf3, { 0x96, 0x33, 0xa4, 0x4d, 0x1f, 0x7f, 0x9c, 0xb8 } }), kStructVersion3)
|
||||
//! Specifies which mode should be used
|
||||
DLSSMode mode = DLSSMode::eOff;
|
||||
//! Specifies output (final) target width
|
||||
uint32_t outputWidth = INVALID_UINT;
|
||||
//! Specifies output (final) target height
|
||||
uint32_t outputHeight = INVALID_UINT;
|
||||
//! Specifies sharpening level in range [0,1]
|
||||
float sharpness = 0.0f;
|
||||
//! Specifies pre-exposure value
|
||||
float preExposure = 1.0f;
|
||||
//! Specifies exposure scale value
|
||||
float exposureScale = 1.0f;
|
||||
//! Specifies if tagged color buffers are full HDR or not (DLSS in HDR pipeline or not)
|
||||
Boolean colorBuffersHDR = Boolean::eTrue;
|
||||
//! Specifies if indicator on screen should invert axis
|
||||
Boolean indicatorInvertAxisX = Boolean::eFalse;
|
||||
//! Specifies if indicator on screen should invert axis
|
||||
Boolean indicatorInvertAxisY = Boolean::eFalse;
|
||||
//! Specifies which mode should be used for roughness resource
|
||||
DLSSDNormalRoughnessMode normalRoughnessMode = DLSSDNormalRoughnessMode::eUnpacked;
|
||||
//! Specifies matrix transformation from the world space to the camera view space.
|
||||
float4x4 worldToCameraView;
|
||||
//! Specifies matrix transformation from the camera view space to the world space.
|
||||
//! cameraViewToWorld = worldToCameraView.inverse()
|
||||
float4x4 cameraViewToWorld;
|
||||
//! Whether or not the alpha channel should be upscaled (if false, only RGB is upscaled)
|
||||
//! Enabling alpha upscaling may impact performance
|
||||
Boolean alphaUpscalingEnabled = Boolean::eFalse;
|
||||
|
||||
//! Presets
|
||||
DLSSDPreset dlaaPreset = DLSSDPreset::eDefault;
|
||||
DLSSDPreset qualityPreset = DLSSDPreset::eDefault;
|
||||
DLSSDPreset balancedPreset = DLSSDPreset::eDefault;
|
||||
DLSSDPreset performancePreset = DLSSDPreset::eDefault;
|
||||
DLSSDPreset ultraPerformancePreset = DLSSDPreset::eDefault;
|
||||
DLSSDPreset ultraQualityPreset = DLSSDPreset::eDefault;
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
//! Returned by DLSSD plugin
|
||||
//!
|
||||
//! {FBD0C637-A28F-41F2-BC91-B421FAEE8E1E}
|
||||
SL_STRUCT_BEGIN(DLSSDOptimalSettings, StructType({ 0xfbd0c637, 0xa28f, 0x41f2, { 0xbc, 0x91, 0xb4, 0x21, 0xfa, 0xee, 0x8e, 0x1e } }), kStructVersion1)
|
||||
//! Specifies render area width
|
||||
uint32_t optimalRenderWidth{};
|
||||
//! Specifies render area height
|
||||
uint32_t optimalRenderHeight{};
|
||||
//! Specifies the optimal sharpness value
|
||||
float optimalSharpness{};
|
||||
//! Specifies minimal render area width
|
||||
uint32_t renderWidthMin{};
|
||||
//! Specifies minimal render area height
|
||||
uint32_t renderHeightMin{};
|
||||
//! Specifies maximal render area width
|
||||
uint32_t renderWidthMax{};
|
||||
//! Specifies maximal render area height
|
||||
uint32_t renderHeightMax{};
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
//! Returned by DLSSD plugin
|
||||
//!
|
||||
//! {71873C14-F8CA-4767-9EAF-3B4393EA98FA}
|
||||
SL_STRUCT_BEGIN(DLSSDState, StructType({ 0x71873c14, 0xf8ca, 0x4767, { 0x9e, 0xaf, 0x3b, 0x43, 0x93, 0xea, 0x98, 0xfa } }), kStructVersion1)
|
||||
//! Specified the amount of memory expected to be used
|
||||
uint64_t estimatedVRAMUsageInBytes {};
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
}
|
||||
|
||||
//! Provides optimal DLSSD settings
|
||||
//!
|
||||
//! Call this method to obtain optimal render target size and other DLSSD related settings.
|
||||
//!
|
||||
//! @param options Specifies DLSSD options to use
|
||||
//! @param settings Reference to a structure where settings are returned
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is NOT thread safe.
|
||||
using PFun_slDLSSDGetOptimalSettings = sl::Result(const sl::DLSSDOptions & options, sl::DLSSDOptimalSettings & settings);
|
||||
|
||||
//! Provides DLSSD state for the given viewport
|
||||
//!
|
||||
//! Call this method to obtain optimal render target size and other DLSSD related settings.
|
||||
//!
|
||||
//! @param viewport Specified viewport we are working with
|
||||
//! @param state Reference to a structure where state is to be returned
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is NOT thread safe.
|
||||
using PFun_slDLSSDGetState = sl::Result(const sl::ViewportHandle & viewport, sl::DLSSDState & state);
|
||||
|
||||
//! Sets DLSSD options
|
||||
//!
|
||||
//! Call this method to turn DLSSD on/off, change mode etc.
|
||||
//!
|
||||
//! @param viewport Specified viewport we are working with
|
||||
//! @param options Specifies DLSSD options to use
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is NOT thread safe.
|
||||
using PFun_slDLSSDSetOptions = sl::Result(const sl::ViewportHandle& viewport, const sl::DLSSDOptions& options);
|
||||
|
||||
//! HELPERS
|
||||
//!
|
||||
inline sl::Result slDLSSDGetOptimalSettings(const sl::DLSSDOptions& options, sl::DLSSDOptimalSettings& settings)
|
||||
{
|
||||
SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureDLSS_RR, slDLSSDGetOptimalSettings);
|
||||
return s_slDLSSDGetOptimalSettings(options, settings);
|
||||
}
|
||||
|
||||
inline sl::Result slDLSSDGetState(const sl::ViewportHandle& viewport, sl::DLSSDState& state)
|
||||
{
|
||||
SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureDLSS_RR, slDLSSDGetState);
|
||||
return s_slDLSSDGetState(viewport, state);
|
||||
}
|
||||
|
||||
inline sl::Result slDLSSDSetOptions(const sl::ViewportHandle& viewport, const sl::DLSSDOptions& options)
|
||||
{
|
||||
SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureDLSS_RR, slDLSSDSetOptions);
|
||||
return s_slDLSSDSetOptions(viewport, options);
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sl.h"
|
||||
#include "sl_consts.h"
|
||||
#include "sl_core_types.h"
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace sl
|
||||
{
|
||||
|
||||
enum class DLSSGMode : uint32_t
|
||||
{
|
||||
eOff,
|
||||
eOn,
|
||||
eAuto,
|
||||
eCount
|
||||
};
|
||||
|
||||
enum class DLSSGFlags : uint32_t
|
||||
{
|
||||
eShowOnlyInterpolatedFrame = 1 << 0,
|
||||
eDynamicResolutionEnabled = 1 << 1,
|
||||
eRequestVRAMEstimate = 1 << 2,
|
||||
eRetainResourcesWhenOff = 1 << 3,
|
||||
eEnableFullscreenMenuDetection = 1 << 4,
|
||||
|
||||
//! All DLSS-FG flags. This isn't expected to be used directly by integrations, but may be useful for e.g. writing helpers.
|
||||
eAll = eShowOnlyInterpolatedFrame | eDynamicResolutionEnabled | eRequestVRAMEstimate | eRetainResourcesWhenOff | eEnableFullscreenMenuDetection
|
||||
};
|
||||
|
||||
enum class DLSSGQueueParallelismMode : uint32_t
|
||||
{
|
||||
//! Default mode in which client's presenting queue is blocked until DLSSG workload execution completes.
|
||||
eBlockPresentingClientQueue,
|
||||
//! This mode is only supported on Vulkan presently. Even if set by any D3D client, it would default to
|
||||
//! eBlockPresentingClientQueue as before. eBlockNoClientQueues mode helps achieve maximum performance benefit
|
||||
//! from queue-level paralleism in Vulkan during DLSS-G processing. In this mode, client must must wait on
|
||||
//! DLSSGState::inputsProcessingCompletionFence and associated value, before it can modify or destroy the tagged
|
||||
//! resources input to DLSS-G enabled for the corresponding previously presented frame on any client queue.
|
||||
eBlockNoClientQueues,
|
||||
eCount
|
||||
};
|
||||
|
||||
// Adds various useful operators for our enum
|
||||
SL_ENUM_OPERATORS_32(DLSSGFlags)
|
||||
|
||||
// {FAC5F1CB-2DFD-4F36-A1E6-3A9E865256C5}
|
||||
SL_STRUCT_BEGIN(DLSSGOptions, StructType({ 0xfac5f1cb, 0x2dfd, 0x4f36, { 0xa1, 0xe6, 0x3a, 0x9e, 0x86, 0x52, 0x56, 0xc5 } }), kStructVersion4)
|
||||
//! Specifies which mode should be used.
|
||||
DLSSGMode mode = DLSSGMode::eOff;
|
||||
//! Number of frames to generate inbetween fully rendered frames. Cannot exceed DLSSGState::numFramesToGenerateMax.
|
||||
//! For 2x frame multiplier, numFramesToGenerate is 1.
|
||||
//! For 3x frame multiplier, numFramesToGenerate is 2.
|
||||
//! For 4x frame multiplier, numFramesToGenerate is 3.
|
||||
uint32_t numFramesToGenerate = 1;
|
||||
//! Optional - Flags used to enable or disable certain functionality
|
||||
DLSSGFlags flags{};
|
||||
//! Optional - Dynamic resolution optimal width (used only if eDynamicResolutionEnabled is set)
|
||||
uint32_t dynamicResWidth{};
|
||||
//! Optional - Dynamic resolution optimal height (used only if eDynamicResolutionEnabled is set)
|
||||
uint32_t dynamicResHeight{};
|
||||
//! Optional - Expected number of buffers in the swap-chain
|
||||
uint32_t numBackBuffers{};
|
||||
//! Optional - Expected width of the input render targets (depth, motion-vector buffers etc)
|
||||
uint32_t mvecDepthWidth{};
|
||||
//! Optional - Expected height of the input render targets (depth, motion-vector buffers etc)
|
||||
uint32_t mvecDepthHeight{};
|
||||
//! Optional - Expected width of the back buffers in the swap-chain
|
||||
uint32_t colorWidth{};
|
||||
//! Optional - Expected height of the back buffers in the swap-chain
|
||||
uint32_t colorHeight{};
|
||||
//! Optional - Indicates native format used for the swap-chain back buffers
|
||||
uint32_t colorBufferFormat{};
|
||||
//! Optional - Indicates native format used for eMotionVectors
|
||||
uint32_t mvecBufferFormat{};
|
||||
//! Optional - Indicates native format used for eDepth
|
||||
uint32_t depthBufferFormat{};
|
||||
//! Optional - Indicates native format used for eHUDLessColor
|
||||
uint32_t hudLessBufferFormat{};
|
||||
//! Optional - Indicates native format used for eUIColorAndAlpha
|
||||
uint32_t uiBufferFormat{};
|
||||
//! Optional - if specified DLSSG will return any errors which occur when calling underlying API (DXGI or Vulkan)
|
||||
PFunOnAPIErrorCallback* onErrorCallback{};
|
||||
// kStructVersion2
|
||||
Boolean bReserved15 = eInvalid;
|
||||
// kStructVersion3
|
||||
//! Optional - determines the level of client and DLSSG queue parallelism to use for performance gain - must be same for all viewports.
|
||||
DLSSGQueueParallelismMode queueParallelismMode{};
|
||||
// kStructVersion4
|
||||
Boolean bReserved16 = eInvalid;
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
|
||||
enum class DLSSGStatus : uint32_t
|
||||
{
|
||||
//! Everything is working as expected
|
||||
eOk = 0,
|
||||
//! Output resolution (size of the back buffers in the swap-chain) is too low
|
||||
eFailResolutionTooLow = 1 << 0,
|
||||
//! Reflex is not active while DLSS-G is running, Reflex must be turned on when DLSS-G is on
|
||||
eFailReflexNotDetectedAtRuntime = 1 << 1,
|
||||
//! HDR format not supported, see DLSS-G programming guide for more details
|
||||
eFailHDRFormatNotSupported = 1 << 2,
|
||||
//! Some constants are invalid, see programming guide for more details
|
||||
eFailCommonConstantsInvalid = 1 << 3,
|
||||
//! D3D integrations must use SwapChain::GetCurrentBackBufferIndex API
|
||||
eFailGetCurrentBackBufferIndexNotCalled = 1 << 4,
|
||||
//! Reserved for future use, do not use
|
||||
eReserved5 = 1 << 5,
|
||||
|
||||
eAll = eFailResolutionTooLow | eFailReflexNotDetectedAtRuntime | eFailHDRFormatNotSupported | eFailCommonConstantsInvalid | eFailGetCurrentBackBufferIndexNotCalled | eReserved5
|
||||
};
|
||||
|
||||
// Adds various useful operators for our enum
|
||||
SL_ENUM_OPERATORS_32(DLSSGStatus)
|
||||
|
||||
// {CC8AC8E1-A179-44F5-97FA-E74112F9BC61}
|
||||
SL_STRUCT_BEGIN(DLSSGState, StructType({ 0xcc8ac8e1, 0xa179, 0x44f5, { 0x97, 0xfa, 0xe7, 0x41, 0x12, 0xf9, 0xbc, 0x61 } }), kStructVersion3)
|
||||
//! Specifies the amount of memory expected to be used
|
||||
uint64_t estimatedVRAMUsageInBytes{};
|
||||
//! Specifies current status of DLSS-G
|
||||
DLSSGStatus status{};
|
||||
//! Specifies minimum supported dimension
|
||||
uint32_t minWidthOrHeight{};
|
||||
//! Number of frames presented since the last 'slDLSSGGetState' call
|
||||
uint32_t numFramesActuallyPresented{};
|
||||
// kStructVersion2
|
||||
//! Maximum number of frames possible to generate on this gpu architecture.
|
||||
//! For 2x only supporting devices, numFramesToGenerateMax is 1.
|
||||
//! For 3x and 4x supporting devices, numFramesToGenerateMax is 3.
|
||||
uint32_t numFramesToGenerateMax{};
|
||||
//! Reserved for future use, do not use
|
||||
sl::Boolean bReserved4{};
|
||||
//! Hint to the application to display VSync support in the user interface
|
||||
sl::Boolean bIsVsyncSupportAvailable{};
|
||||
|
||||
//! SL client must wait on SL DLSS-G plugin-internal fence and associated value, before it can modify or destroy the tagged resources input
|
||||
//! to DLSS-G enabled for the corresponding previously presented frame on a non-presenting queue.
|
||||
//! If modified on client's presenting queue, then it's recommended but not required.
|
||||
//! However, if DLSSGQueueParallelismMode::eBlockNoClientQueues is set, then it's always required.
|
||||
//! It must call slDLSSGGetState on the present thread to retrieve the fence value for the inputs consumed by FG, on which client would
|
||||
//! wait in the frame it would modify those inputs.
|
||||
void* inputsProcessingCompletionFence{};
|
||||
uint64_t lastPresentInputsProcessingCompletionFenceValue{};
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
}
|
||||
|
||||
//! Provides DLSS-G state
|
||||
//!
|
||||
//! Call this method to obtain current state of DLSS-G
|
||||
//!
|
||||
//! @param viewport Specified viewport we are working with
|
||||
//! @param state Reference to a structure where state is returned
|
||||
//! @param options Specifies DLSS-G options to use (can be null if not needed)
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is NOT thread safe.
|
||||
using PFun_slDLSSGGetState = sl::Result(const sl::ViewportHandle& viewport, sl::DLSSGState& state, const sl::DLSSGOptions* options);
|
||||
|
||||
//! Sets DLSS-G options
|
||||
//!
|
||||
//! Call this method to turn DLSS-G on/off, change modes etc.
|
||||
//!
|
||||
//! @param viewport Specified viewport we are working with
|
||||
//! @param options Specifies DLSS-G options to use
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is NOT thread safe.
|
||||
using PFun_slDLSSGSetOptions = sl::Result(const sl::ViewportHandle& viewport, const sl::DLSSGOptions& options);
|
||||
|
||||
//! HELPERS
|
||||
//!
|
||||
inline sl::Result slDLSSGGetState(const sl::ViewportHandle& viewport, sl::DLSSGState& state, const sl::DLSSGOptions* options)
|
||||
{
|
||||
SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureDLSS_G, slDLSSGGetState);
|
||||
return s_slDLSSGGetState(viewport, state, options);
|
||||
}
|
||||
|
||||
inline sl::Result slDLSSGSetOptions(const sl::ViewportHandle& viewport, const sl::DLSSGOptions& options)
|
||||
{
|
||||
SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureDLSS_G, slDLSSGSetOptions);
|
||||
return s_slDLSSGSetOptions(viewport, options);
|
||||
}
|
||||
@@ -0,0 +1,475 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2025 NVIDIA CORPORATION. All rights reserved
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
|
||||
#define FEATURE_SPECIFIC_BUFFER_TYPE_ID(feature, number) feature << 16 | number
|
||||
|
||||
#include "sl.h"
|
||||
#include "sl_consts.h"
|
||||
#include "sl_reflex.h"
|
||||
#include "sl_pcl.h"
|
||||
#include "sl_dlss.h"
|
||||
#include "sl_nis.h"
|
||||
#include "sl_dlss_d.h"
|
||||
#include "sl_dlss_g.h"
|
||||
|
||||
#if defined(__clang__)
|
||||
#define SL_DISABLE_DEPRECATED_WARNINGS \
|
||||
_Pragma("clang diagnostic push") \
|
||||
_Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"")
|
||||
#define SL_RESTORE_DEPRECATED_WARNINGS \
|
||||
_Pragma("clang diagnostic pop")
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
#define SL_DISABLE_DEPRECATED_WARNINGS \
|
||||
__pragma(warning(push)) \
|
||||
__pragma(warning(disable: 4996))
|
||||
#define SL_RESTORE_DEPRECATED_WARNINGS \
|
||||
__pragma(warning(pop))
|
||||
|
||||
#else
|
||||
#define SL_DISABLE_DEPRECATED_WARNINGS
|
||||
#define SL_RESTORE_DEPRECATED_WARNINGS
|
||||
#endif
|
||||
|
||||
|
||||
namespace sl
|
||||
{
|
||||
|
||||
inline float4x4 transpose(const float4x4& m)
|
||||
{
|
||||
float4x4 r;
|
||||
r[0] = { m[0].x, m[1].x, m[2].x, m[3].x };
|
||||
r[1] = { m[0].y, m[1].y, m[2].y, m[3].y };
|
||||
r[2] = { m[0].z, m[1].z, m[2].z, m[3].z };
|
||||
r[3] = { m[0].w, m[1].w, m[2].w, m[3].w };
|
||||
return r;
|
||||
};
|
||||
|
||||
#define SL_CASE_STR(a) case a : return #a;
|
||||
|
||||
// Check for c++17 features
|
||||
#if __cplusplus >= 201703L
|
||||
#define SL_FALLTHROUGH [[fallthrough]];
|
||||
#else
|
||||
#define SL_FALLTHROUGH
|
||||
#endif
|
||||
|
||||
inline const char* getResultAsStr(Result v)
|
||||
{
|
||||
switch (v)
|
||||
{
|
||||
SL_CASE_STR(Result::eOk);
|
||||
SL_CASE_STR(Result::eErrorIO);
|
||||
SL_CASE_STR(Result::eErrorDriverOutOfDate);
|
||||
SL_CASE_STR(Result::eErrorOSOutOfDate);
|
||||
SL_CASE_STR(Result::eErrorOSDisabledHWS);
|
||||
SL_CASE_STR(Result::eErrorDeviceNotCreated);
|
||||
SL_CASE_STR(Result::eErrorNoSupportedAdapterFound);
|
||||
SL_CASE_STR(Result::eErrorAdapterNotSupported);
|
||||
SL_CASE_STR(Result::eErrorNoPlugins);
|
||||
SL_CASE_STR(Result::eErrorVulkanAPI);
|
||||
SL_CASE_STR(Result::eErrorDXGIAPI);
|
||||
SL_CASE_STR(Result::eErrorD3DAPI);
|
||||
SL_CASE_STR(Result::eErrorNRDAPI);
|
||||
SL_CASE_STR(Result::eErrorNVAPI);
|
||||
SL_CASE_STR(Result::eErrorReflexAPI);
|
||||
SL_CASE_STR(Result::eErrorNGXFailed);
|
||||
SL_CASE_STR(Result::eErrorJSONParsing);
|
||||
SL_CASE_STR(Result::eErrorMissingProxy);
|
||||
SL_CASE_STR(Result::eErrorMissingResourceState);
|
||||
SL_CASE_STR(Result::eErrorInvalidIntegration);
|
||||
SL_CASE_STR(Result::eErrorMissingInputParameter);
|
||||
SL_CASE_STR(Result::eErrorNotInitialized);
|
||||
SL_CASE_STR(Result::eErrorComputeFailed);
|
||||
SL_CASE_STR(Result::eErrorInitNotCalled);
|
||||
SL_CASE_STR(Result::eErrorExceptionHandler);
|
||||
SL_CASE_STR(Result::eErrorInvalidParameter);
|
||||
SL_CASE_STR(Result::eErrorMissingConstants);
|
||||
SL_CASE_STR(Result::eErrorDuplicatedConstants);
|
||||
SL_CASE_STR(Result::eErrorMissingOrInvalidAPI);
|
||||
SL_CASE_STR(Result::eErrorCommonConstantsMissing);
|
||||
SL_CASE_STR(Result::eErrorUnsupportedInterface);
|
||||
SL_CASE_STR(Result::eErrorFeatureMissing);
|
||||
SL_CASE_STR(Result::eErrorFeatureNotSupported);
|
||||
SL_CASE_STR(Result::eErrorFeatureMissingHooks);
|
||||
SL_CASE_STR(Result::eErrorFeatureFailedToLoad);
|
||||
SL_CASE_STR(Result::eErrorFeatureWrongPriority);
|
||||
SL_CASE_STR(Result::eErrorFeatureMissingDependency);
|
||||
SL_CASE_STR(Result::eErrorFeatureManagerInvalidState);
|
||||
SL_CASE_STR(Result::eErrorInvalidState);
|
||||
SL_CASE_STR(Result::eWarnOutOfVRAM);
|
||||
};
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
inline const char* getNISModeAsStr(NISMode v)
|
||||
{
|
||||
switch (v)
|
||||
{
|
||||
SL_CASE_STR(NISMode::eOff);
|
||||
SL_CASE_STR(NISMode::eScaler);
|
||||
SL_CASE_STR(NISMode::eSharpen);
|
||||
case NISMode::eCount: break;
|
||||
};
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
inline const char* getNISHDRAsStr(NISHDR v)
|
||||
{
|
||||
switch (v)
|
||||
{
|
||||
SL_CASE_STR(NISHDR::eNone);
|
||||
SL_CASE_STR(NISHDR::eLinear);
|
||||
SL_CASE_STR(NISHDR::ePQ);
|
||||
case NISHDR::eCount: break;
|
||||
};
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
inline const char* getReflexModeAsStr(ReflexMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
SL_CASE_STR(ReflexMode::eOff);
|
||||
SL_CASE_STR(ReflexMode::eLowLatency);
|
||||
SL_CASE_STR(ReflexMode::eLowLatencyWithBoost);
|
||||
case ReflexMode::ReflexMode_eCount: break;
|
||||
};
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
inline const char* getPCLMarkerAsStr(PCLMarker marker)
|
||||
{
|
||||
switch (marker)
|
||||
{
|
||||
SL_CASE_STR(PCLMarker::eSimulationStart);
|
||||
SL_CASE_STR(PCLMarker::eSimulationEnd);
|
||||
SL_CASE_STR(PCLMarker::eRenderSubmitStart);
|
||||
SL_CASE_STR(PCLMarker::eRenderSubmitEnd);
|
||||
SL_CASE_STR(PCLMarker::ePresentStart);
|
||||
SL_CASE_STR(PCLMarker::ePresentEnd);
|
||||
SL_CASE_STR(PCLMarker::eTriggerFlash);
|
||||
SL_CASE_STR(PCLMarker::ePCLatencyPing);
|
||||
SL_CASE_STR(PCLMarker::eOutOfBandRenderSubmitStart);
|
||||
SL_CASE_STR(PCLMarker::eOutOfBandRenderSubmitEnd);
|
||||
SL_CASE_STR(PCLMarker::eOutOfBandPresentStart);
|
||||
SL_CASE_STR(PCLMarker::eOutOfBandPresentEnd);
|
||||
SL_CASE_STR(PCLMarker::eControllerInputSample);
|
||||
SL_CASE_STR(PCLMarker::eDeltaTCalculation);
|
||||
SL_CASE_STR(PCLMarker::eLateWarpPresentStart);
|
||||
SL_CASE_STR(PCLMarker::eLateWarpPresentEnd);
|
||||
SL_CASE_STR(PCLMarker::eCameraConstructed);
|
||||
SL_CASE_STR(PCLMarker::eLateWarpRenderSubmitStart);
|
||||
SL_CASE_STR(PCLMarker::eLateWarpRenderSubmitEnd);
|
||||
case PCLMarker::eMaximum: break;
|
||||
};
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
inline const char* getDLSSModeAsStr(DLSSMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
SL_CASE_STR(DLSSMode::eOff);
|
||||
SL_CASE_STR(DLSSMode::eDLAA);
|
||||
SL_CASE_STR(DLSSMode::eMaxPerformance);
|
||||
SL_CASE_STR(DLSSMode::eBalanced);
|
||||
SL_CASE_STR(DLSSMode::eMaxQuality);
|
||||
SL_CASE_STR(DLSSMode::eUltraPerformance);
|
||||
SL_CASE_STR(DLSSMode::eUltraQuality);
|
||||
case DLSSMode::eCount: break;
|
||||
};
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
inline const char* getDLSSGModeAsStr(DLSSGMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
SL_CASE_STR(sl::DLSSGMode::eOff);
|
||||
SL_CASE_STR(sl::DLSSGMode::eOn);
|
||||
SL_CASE_STR(sl::DLSSGMode::eAuto);
|
||||
case DLSSGMode::eCount: break;
|
||||
};
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
inline const char* getBufferTypeAsStr(BufferType buf)
|
||||
{
|
||||
switch (buf)
|
||||
{
|
||||
SL_CASE_STR(kBufferTypeDepth);
|
||||
SL_CASE_STR(kBufferTypeMotionVectors);
|
||||
SL_CASE_STR(kBufferTypeHUDLessColor);
|
||||
SL_CASE_STR(kBufferTypeScalingInputColor);
|
||||
SL_CASE_STR(kBufferTypeScalingOutputColor);
|
||||
SL_CASE_STR(kBufferTypeNormals);
|
||||
SL_CASE_STR(kBufferTypeRoughness);
|
||||
SL_CASE_STR(kBufferTypeAlbedo);
|
||||
SL_CASE_STR(kBufferTypeSpecularAlbedo);
|
||||
SL_CASE_STR(kBufferTypeIndirectAlbedo);
|
||||
SL_CASE_STR(kBufferTypeSpecularMotionVectors);
|
||||
SL_CASE_STR(kBufferTypeDisocclusionMask);
|
||||
SL_CASE_STR(kBufferTypeEmissive);
|
||||
SL_CASE_STR(kBufferTypeExposure);
|
||||
SL_CASE_STR(kBufferTypeNormalRoughness);
|
||||
SL_CASE_STR(kBufferTypeDiffuseHitNoisy);
|
||||
SL_CASE_STR(kBufferTypeDiffuseHitDenoised);
|
||||
SL_CASE_STR(kBufferTypeSpecularHitNoisy);
|
||||
SL_CASE_STR(kBufferTypeSpecularHitDenoised);
|
||||
SL_CASE_STR(kBufferTypeShadowNoisy);
|
||||
SL_CASE_STR(kBufferTypeShadowDenoised);
|
||||
SL_CASE_STR(kBufferTypeAmbientOcclusionNoisy);
|
||||
SL_CASE_STR(kBufferTypeAmbientOcclusionDenoised);
|
||||
SL_CASE_STR(kBufferTypeUIColorAndAlpha);
|
||||
SL_CASE_STR(kBufferTypeShadowHint);
|
||||
SL_CASE_STR(kBufferTypeReflectionHint);
|
||||
SL_CASE_STR(kBufferTypeParticleHint);
|
||||
SL_CASE_STR(kBufferTypeTransparencyHint);
|
||||
SL_CASE_STR(kBufferTypeAnimatedTextureHint);
|
||||
SL_CASE_STR(kBufferTypeBiasCurrentColorHint);
|
||||
SL_CASE_STR(kBufferTypeRaytracingDistance);
|
||||
SL_CASE_STR(kBufferTypeReflectionMotionVectors);
|
||||
SL_CASE_STR(kBufferTypePosition);
|
||||
SL_CASE_STR(kBufferTypeInvalidDepthMotionHint);
|
||||
SL_CASE_STR(kBufferTypeAlpha);
|
||||
SL_CASE_STR(kBufferTypeOpaqueColor);
|
||||
SL_CASE_STR(kBufferTypeReactiveMaskHint);
|
||||
SL_CASE_STR(kBufferTypeTransparencyAndCompositionMaskHint);
|
||||
SL_CASE_STR(kBufferTypeReflectedAlbedo);
|
||||
SL_CASE_STR(kBufferTypeColorBeforeParticles);
|
||||
SL_CASE_STR(kBufferTypeColorBeforeTransparency);
|
||||
SL_CASE_STR(kBufferTypeColorBeforeFog);
|
||||
SL_CASE_STR(kBufferTypeSpecularHitDistance);
|
||||
SL_CASE_STR(kBufferTypeSpecularRayDirectionHitDistance);
|
||||
SL_CASE_STR(kBufferTypeSpecularRayDirection);
|
||||
SL_CASE_STR(kBufferTypeDiffuseHitDistance);
|
||||
SL_CASE_STR(kBufferTypeDiffuseRayDirectionHitDistance);
|
||||
SL_CASE_STR(kBufferTypeDiffuseRayDirection);
|
||||
SL_CASE_STR(kBufferTypeHiResDepth);
|
||||
SL_CASE_STR(kBufferTypeLinearDepth);
|
||||
SL_CASE_STR(kBufferTypeColorAfterParticles);
|
||||
SL_CASE_STR(kBufferTypeColorAfterTransparency);
|
||||
SL_CASE_STR(kBufferTypeColorAfterFog);
|
||||
SL_CASE_STR(kBufferTypeScreenSpaceSubsurfaceScatteringGuide);
|
||||
SL_CASE_STR(kBufferTypeColorBeforeScreenSpaceSubsurfaceScattering);
|
||||
SL_CASE_STR(kBufferTypeColorAfterScreenSpaceSubsurfaceScattering);
|
||||
SL_CASE_STR(kBufferTypeScreenSpaceRefractionGuide);
|
||||
SL_CASE_STR(kBufferTypeColorBeforeScreenSpaceRefraction);
|
||||
SL_CASE_STR(kBufferTypeColorAfterScreenSpaceRefraction);
|
||||
SL_CASE_STR(kBufferTypeDepthOfFieldGuide);
|
||||
SL_CASE_STR(kBufferTypeColorBeforeDepthOfField);
|
||||
SL_CASE_STR(kBufferTypeColorAfterDepthOfField);
|
||||
SL_CASE_STR(kBufferTypeScalingOutputAlpha);
|
||||
SL_CASE_STR(kBufferTypeBidirectionalDistortionField);
|
||||
SL_CASE_STR(kBufferTypeTransparencyLayer);
|
||||
SL_CASE_STR(kBufferTypeTransparencyLayerOpacity);
|
||||
SL_CASE_STR(kBufferTypeBackbuffer);
|
||||
SL_CASE_STR(kBufferTypeNoWarpMask);
|
||||
};
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
inline const char* getFeatureAsStr(Feature f)
|
||||
{
|
||||
switch (f)
|
||||
{
|
||||
SL_CASE_STR(kFeatureDLSS);
|
||||
SL_CASE_STR(kFeatureNIS);
|
||||
SL_CASE_STR(kFeatureReflex);
|
||||
SL_CASE_STR(kFeaturePCL);
|
||||
SL_CASE_STR(kFeatureDLSS_G);
|
||||
SL_CASE_STR(kFeatureNvPerf);
|
||||
SL_CASE_STR(kFeatureImGUI);
|
||||
SL_CASE_STR(kFeatureCommon);
|
||||
SL_CASE_STR(kFeatureDLSS_RR);
|
||||
SL_CASE_STR(kFeatureDeepDVC);
|
||||
SL_CASE_STR(kFeatureDirectSR);
|
||||
SL_CASE_STR(kFeatureLatewarp);
|
||||
// Removed features
|
||||
case kFeatureNRD_INVALID: break;
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
// Get the feature file name as a string. For a given feature kFeatureDLSS with
|
||||
// a plugin name sl.dlss.dll the value "dlss" will be returned
|
||||
inline const char* getFeatureFilenameAsStrNoSL(Feature f)
|
||||
{
|
||||
switch (f)
|
||||
{
|
||||
case kFeatureDLSS: return "dlss";
|
||||
case kFeatureNIS: return "nis";
|
||||
case kFeatureReflex: return "reflex";
|
||||
case kFeaturePCL: return "pcl";
|
||||
case kFeatureDLSS_G: return "dlss_g";
|
||||
case kFeatureNvPerf: return "nvperf";
|
||||
case kFeatureDeepDVC: return "deepdvc";
|
||||
case kFeatureImGUI: return "imgui";
|
||||
case kFeatureCommon: return "common";
|
||||
case kFeatureDLSS_RR: return "dlss_d";
|
||||
case kFeatureDirectSR: return "directsr";
|
||||
case kFeatureLatewarp: return "latewarp";
|
||||
case kFeatureNRD_INVALID: break;
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
inline const char* getLogLevelAsStr(LogLevel v)
|
||||
{
|
||||
switch (v)
|
||||
{
|
||||
SL_CASE_STR(LogLevel::eOff);
|
||||
SL_CASE_STR(LogLevel::eDefault);
|
||||
SL_CASE_STR(LogLevel::eVerbose);
|
||||
case LogLevel::eCount: break;
|
||||
};
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
inline const char* getResourceTypeAsStr(ResourceType v)
|
||||
{
|
||||
switch (v)
|
||||
{
|
||||
SL_CASE_STR(ResourceType::eTex2d);
|
||||
SL_CASE_STR(ResourceType::eBuffer);
|
||||
SL_CASE_STR(ResourceType::eCommandQueue);
|
||||
SL_CASE_STR(ResourceType::eCommandBuffer);
|
||||
SL_CASE_STR(ResourceType::eCommandPool);
|
||||
SL_CASE_STR(ResourceType::eFence);
|
||||
SL_CASE_STR(ResourceType::eSwapchain);
|
||||
SL_CASE_STR(ResourceType::eHostFence);
|
||||
case ResourceType::eUnknown: break;
|
||||
case ResourceType::eCount: break;
|
||||
};
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
inline const char* getResourceLifecycleAsStr(ResourceLifecycle v)
|
||||
{
|
||||
switch (v)
|
||||
{
|
||||
SL_CASE_STR(ResourceLifecycle::eOnlyValidNow);
|
||||
SL_CASE_STR(ResourceLifecycle::eValidUntilPresent);
|
||||
SL_CASE_STR(ResourceLifecycle::eValidUntilEvaluate);
|
||||
};
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
SL_DISABLE_DEPRECATED_WARNINGS
|
||||
inline DLSSPreset resolveDLSSPreset(DLSSPreset preset)
|
||||
{
|
||||
switch (preset)
|
||||
{
|
||||
case DLSSPreset::ePresetF:
|
||||
case DLSSPreset::ePresetJ:
|
||||
case DLSSPreset::ePresetK:
|
||||
return preset;
|
||||
default:
|
||||
return DLSSPreset::eDefault;
|
||||
}
|
||||
}
|
||||
SL_RESTORE_DEPRECATED_WARNINGS
|
||||
|
||||
inline DLSSDPreset resolveDLSSDPreset(DLSSDPreset preset)
|
||||
{
|
||||
return static_cast<DLSSDPreset>(resolveDLSSPreset(static_cast<DLSSPreset>(preset)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Advanced/internal functions that are not useful or necessary in the vast majority of integrations
|
||||
// and would just pollute the namespace and/or cause distractions.
|
||||
// But, may be useful in e.g. intermediary game engine integrations, etc.
|
||||
#ifndef __INTELLISENSE__
|
||||
|
||||
//! Find a struct of type T
|
||||
template<typename T>
|
||||
T* findStruct(const void* ptr)
|
||||
{
|
||||
auto base = static_cast<const BaseStructure*>(ptr);
|
||||
while (base && base->structType != T::s_structType)
|
||||
{
|
||||
base = base->next;
|
||||
}
|
||||
return (T*)base;
|
||||
}
|
||||
|
||||
//! Find a struct of type T, but stop the search if we find a struct of type S
|
||||
template<typename T, typename S>
|
||||
T* findStruct(const void* ptr)
|
||||
{
|
||||
auto base = static_cast<const BaseStructure*>(ptr);
|
||||
while (base && base->structType != T::s_structType)
|
||||
{
|
||||
base = base->next;
|
||||
|
||||
// If we find a struct of type S, we know should stop the search
|
||||
if (base->structType == S::s_structType)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return (T*)base;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* findStruct(const void** ptr, uint32_t count)
|
||||
{
|
||||
const BaseStructure* base{};
|
||||
for (uint32_t i = 0; base == nullptr && i < count; i++)
|
||||
{
|
||||
base = static_cast<const BaseStructure*>(ptr[i]);
|
||||
while (base && base->structType != T::s_structType)
|
||||
{
|
||||
base = base->next;
|
||||
}
|
||||
}
|
||||
return (T*)base;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool findStructs(const void** ptr, uint32_t count, std::vector<T*>& structs)
|
||||
{
|
||||
for (uint32_t i = 0; i < count; i++)
|
||||
{
|
||||
auto base = static_cast<const BaseStructure*>(ptr[i]);
|
||||
while (base)
|
||||
{
|
||||
if (base->structType == T::s_structType)
|
||||
{
|
||||
structs.push_back((T*)base);
|
||||
}
|
||||
base = base->next;
|
||||
}
|
||||
}
|
||||
return structs.size() > 0;
|
||||
}
|
||||
|
||||
#endif // __INTELLISENSE__
|
||||
|
||||
} // namespace sl
|
||||
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sl.h"
|
||||
#include <string.h>
|
||||
|
||||
namespace sl
|
||||
{
|
||||
|
||||
#define SL_VK_FEATURE(n) if(strcmp(featureNames[i], #n) == 0) features.n = VK_TRUE;
|
||||
|
||||
inline VkPhysicalDeviceVulkan12Features getVkPhysicalDeviceVulkan12Features(uint32_t featureCount, const char** featureNames)
|
||||
{
|
||||
VkPhysicalDeviceVulkan12Features features{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES };
|
||||
for (uint32_t i = 0; i < featureCount; i++)
|
||||
{
|
||||
SL_VK_FEATURE(samplerMirrorClampToEdge);
|
||||
SL_VK_FEATURE(drawIndirectCount);
|
||||
SL_VK_FEATURE(storageBuffer8BitAccess);
|
||||
SL_VK_FEATURE(uniformAndStorageBuffer8BitAccess);
|
||||
SL_VK_FEATURE(storagePushConstant8);
|
||||
SL_VK_FEATURE(shaderBufferInt64Atomics);
|
||||
SL_VK_FEATURE(shaderSharedInt64Atomics);
|
||||
SL_VK_FEATURE(shaderFloat16);
|
||||
SL_VK_FEATURE(shaderInt8);
|
||||
SL_VK_FEATURE(descriptorIndexing);
|
||||
SL_VK_FEATURE(shaderInputAttachmentArrayDynamicIndexing);
|
||||
SL_VK_FEATURE(shaderUniformTexelBufferArrayDynamicIndexing);
|
||||
SL_VK_FEATURE(shaderStorageTexelBufferArrayDynamicIndexing);
|
||||
SL_VK_FEATURE(shaderUniformBufferArrayNonUniformIndexing);
|
||||
SL_VK_FEATURE(shaderSampledImageArrayNonUniformIndexing);
|
||||
SL_VK_FEATURE(shaderStorageBufferArrayNonUniformIndexing);
|
||||
SL_VK_FEATURE(shaderStorageImageArrayNonUniformIndexing);
|
||||
SL_VK_FEATURE(shaderInputAttachmentArrayNonUniformIndexing);
|
||||
SL_VK_FEATURE(shaderUniformTexelBufferArrayNonUniformIndexing);
|
||||
SL_VK_FEATURE(shaderStorageTexelBufferArrayNonUniformIndexing);
|
||||
SL_VK_FEATURE(descriptorBindingUniformBufferUpdateAfterBind);
|
||||
SL_VK_FEATURE(descriptorBindingSampledImageUpdateAfterBind);
|
||||
SL_VK_FEATURE(descriptorBindingStorageImageUpdateAfterBind);
|
||||
SL_VK_FEATURE(descriptorBindingStorageBufferUpdateAfterBind);
|
||||
SL_VK_FEATURE(descriptorBindingUniformTexelBufferUpdateAfterBind);
|
||||
SL_VK_FEATURE(descriptorBindingStorageTexelBufferUpdateAfterBind);
|
||||
SL_VK_FEATURE(descriptorBindingUpdateUnusedWhilePending);
|
||||
SL_VK_FEATURE(descriptorBindingPartiallyBound);
|
||||
SL_VK_FEATURE(descriptorBindingVariableDescriptorCount);
|
||||
SL_VK_FEATURE(runtimeDescriptorArray);
|
||||
SL_VK_FEATURE(samplerFilterMinmax);
|
||||
SL_VK_FEATURE(scalarBlockLayout);
|
||||
SL_VK_FEATURE(imagelessFramebuffer);
|
||||
SL_VK_FEATURE(uniformBufferStandardLayout);
|
||||
SL_VK_FEATURE(shaderSubgroupExtendedTypes);
|
||||
SL_VK_FEATURE(separateDepthStencilLayouts);
|
||||
SL_VK_FEATURE(hostQueryReset);
|
||||
SL_VK_FEATURE(timelineSemaphore);
|
||||
SL_VK_FEATURE(bufferDeviceAddress);
|
||||
SL_VK_FEATURE(bufferDeviceAddressCaptureReplay);
|
||||
SL_VK_FEATURE(bufferDeviceAddressMultiDevice);
|
||||
SL_VK_FEATURE(vulkanMemoryModel);
|
||||
SL_VK_FEATURE(vulkanMemoryModelDeviceScope);
|
||||
SL_VK_FEATURE(vulkanMemoryModelAvailabilityVisibilityChains);
|
||||
SL_VK_FEATURE(shaderOutputViewportIndex);
|
||||
SL_VK_FEATURE(shaderOutputLayer);
|
||||
SL_VK_FEATURE(subgroupBroadcastDynamicId);
|
||||
}
|
||||
return features;
|
||||
}
|
||||
|
||||
inline VkPhysicalDeviceVulkan13Features getVkPhysicalDeviceVulkan13Features(uint32_t featureCount, const char** featureNames)
|
||||
{
|
||||
VkPhysicalDeviceVulkan13Features features{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES };
|
||||
for (uint32_t i = 0; i < featureCount; i++)
|
||||
{
|
||||
SL_VK_FEATURE(robustImageAccess);
|
||||
SL_VK_FEATURE(robustImageAccess);
|
||||
SL_VK_FEATURE(inlineUniformBlock);
|
||||
SL_VK_FEATURE(descriptorBindingInlineUniformBlockUpdateAfterBind);
|
||||
SL_VK_FEATURE(pipelineCreationCacheControl);
|
||||
SL_VK_FEATURE(privateData);
|
||||
SL_VK_FEATURE(shaderDemoteToHelperInvocation);
|
||||
SL_VK_FEATURE(shaderTerminateInvocation);
|
||||
SL_VK_FEATURE(subgroupSizeControl);
|
||||
SL_VK_FEATURE(computeFullSubgroups);
|
||||
SL_VK_FEATURE(synchronization2);
|
||||
SL_VK_FEATURE(textureCompressionASTC_HDR);
|
||||
SL_VK_FEATURE(shaderZeroInitializeWorkgroupMemory);
|
||||
SL_VK_FEATURE(dynamicRendering);
|
||||
SL_VK_FEATURE(shaderIntegerDotProduct);
|
||||
SL_VK_FEATURE(maintenance4);
|
||||
}
|
||||
return features;
|
||||
}
|
||||
|
||||
inline VkPhysicalDeviceOpticalFlowFeaturesNV getVkPhysicalDeviceOpticalFlowNVFeatures(uint32_t featureCount, const char** featureNames)
|
||||
{
|
||||
VkPhysicalDeviceOpticalFlowFeaturesNV features{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_FEATURES_NV };
|
||||
for (uint32_t i = 0; i < featureCount; i++)
|
||||
{
|
||||
SL_VK_FEATURE(opticalFlow);
|
||||
}
|
||||
return features;
|
||||
}
|
||||
|
||||
#define SL_VK_FEATURE_SUPPORT(T, feature, n) ((T*)pPhysicalDeviceFeatures)->n = ((feature) && (((T*)pSupportedFeatures)->n))
|
||||
#define SL_VK_FEATURE_MERGE_SUPPORT(T, n) (pFeaturesToMerge == NULL) ? \
|
||||
SL_VK_FEATURE_SUPPORT(T, ((T*)pPhysicalDeviceFeatures)->n, n) : SL_VK_FEATURE_SUPPORT(T, ((((T*)pPhysicalDeviceFeatures)->n) || (((T*)pFeaturesToMerge)->n)), n)
|
||||
|
||||
inline void getMergedSupportedVkPhysicalDeviceVulkanFeatures(VkBaseOutStructure* pPhysicalDeviceFeatures, const VkBaseOutStructure* pFeaturesToMerge, const VkBaseOutStructure* pSupportedFeatures)
|
||||
{
|
||||
if (pPhysicalDeviceFeatures == NULL || pSupportedFeatures == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (pFeaturesToMerge != NULL)
|
||||
{
|
||||
assert(pFeaturesToMerge->sType == pPhysicalDeviceFeatures->sType);
|
||||
}
|
||||
assert(pSupportedFeatures->sType == pPhysicalDeviceFeatures->sType);
|
||||
|
||||
switch (pPhysicalDeviceFeatures->sType)
|
||||
{
|
||||
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES:
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, samplerMirrorClampToEdge);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, samplerMirrorClampToEdge);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, drawIndirectCount);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, storageBuffer8BitAccess);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, uniformAndStorageBuffer8BitAccess);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, storagePushConstant8);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderBufferInt64Atomics);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderSharedInt64Atomics);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderFloat16);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderInt8);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, descriptorIndexing);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderInputAttachmentArrayDynamicIndexing);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderUniformTexelBufferArrayDynamicIndexing);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderStorageTexelBufferArrayDynamicIndexing);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderUniformBufferArrayNonUniformIndexing);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderSampledImageArrayNonUniformIndexing);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderStorageBufferArrayNonUniformIndexing);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderStorageImageArrayNonUniformIndexing);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderInputAttachmentArrayNonUniformIndexing);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderUniformTexelBufferArrayNonUniformIndexing);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderStorageTexelBufferArrayNonUniformIndexing);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, descriptorBindingUniformBufferUpdateAfterBind);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, descriptorBindingSampledImageUpdateAfterBind);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, descriptorBindingStorageImageUpdateAfterBind);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, descriptorBindingStorageBufferUpdateAfterBind);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, descriptorBindingUniformTexelBufferUpdateAfterBind);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, descriptorBindingStorageTexelBufferUpdateAfterBind);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, descriptorBindingUpdateUnusedWhilePending);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, descriptorBindingPartiallyBound);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, descriptorBindingVariableDescriptorCount);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, runtimeDescriptorArray);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, samplerFilterMinmax);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, scalarBlockLayout);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, imagelessFramebuffer);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, uniformBufferStandardLayout);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderSubgroupExtendedTypes);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, separateDepthStencilLayouts);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, hostQueryReset);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, timelineSemaphore);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, bufferDeviceAddress);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, bufferDeviceAddressCaptureReplay);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, bufferDeviceAddressMultiDevice);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, vulkanMemoryModel);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, vulkanMemoryModelDeviceScope);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, vulkanMemoryModelAvailabilityVisibilityChains);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderOutputViewportIndex);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderOutputLayer);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, subgroupBroadcastDynamicId);
|
||||
break;
|
||||
|
||||
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES:
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, robustImageAccess);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, robustImageAccess);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, inlineUniformBlock);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, descriptorBindingInlineUniformBlockUpdateAfterBind);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, pipelineCreationCacheControl);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, privateData);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, shaderDemoteToHelperInvocation);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, shaderTerminateInvocation);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, subgroupSizeControl);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, computeFullSubgroups);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, synchronization2);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, textureCompressionASTC_HDR);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, shaderZeroInitializeWorkgroupMemory);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, dynamicRendering);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, shaderIntegerDotProduct);
|
||||
SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, maintenance4);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//! Interface to provide to slSetVulkanInfo when manually hooking Vulkan API and NOT
|
||||
//! leveraging vkCreateDevice and vkCreateInstance proxies provided by SL.
|
||||
//!
|
||||
//! {0EED6FD5-82CD-43A9-BDB5-47A5BA2F45D6}
|
||||
SL_STRUCT_BEGIN(VulkanInfo, StructType({ 0xeed6fd5, 0x82cd, 0x43a9, { 0xbd, 0xb5, 0x47, 0xa5, 0xba, 0x2f, 0x45, 0xd6 } }), kStructVersion3)
|
||||
VkDevice device {};
|
||||
VkInstance instance{};
|
||||
VkPhysicalDevice physicalDevice{};
|
||||
//! IMPORTANT:
|
||||
//!
|
||||
//! SL features can request additional graphics or compute queues.
|
||||
//! The below values provide information about the queue families and
|
||||
//! starting index at which SL queues are created.
|
||||
uint32_t computeQueueIndex{};
|
||||
uint32_t computeQueueFamily{};
|
||||
uint32_t graphicsQueueIndex{};
|
||||
uint32_t graphicsQueueFamily{};
|
||||
uint32_t opticalFlowQueueIndex{};
|
||||
uint32_t opticalFlowQueueFamily{};
|
||||
bool useNativeOpticalFlowMode = false;
|
||||
uint32_t computeQueueCreateFlags{};
|
||||
uint32_t graphicsQueueCreateFlags{};
|
||||
uint32_t opticalFlowQueueCreateFlags{};
|
||||
SL_STRUCT_END()
|
||||
|
||||
}
|
||||
|
||||
using PFun_slSetVulkanInfo = sl::Result(const sl::VulkanInfo& info);
|
||||
|
||||
//! Specify Vulkan specific information
|
||||
//!
|
||||
//! Use this method to provide Vulkan device, instance information to SL.
|
||||
//!
|
||||
//! IMPORTANT: Only call this API if NOT using vkCreateDevice and vkCreateInstance proxies provided by SL.
|
||||
//
|
||||
//! @param info Reference to the structure providing the information
|
||||
//!
|
||||
//! This method is NOT thread safe and should be called IMMEDIATELY after base interface is created.
|
||||
SL_API sl::Result slSetVulkanInfo(const sl::VulkanInfo& info);
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sl.h"
|
||||
|
||||
struct VkPhysicalDevice_T;
|
||||
struct VkDevice_T;
|
||||
struct VkInstance_T;
|
||||
|
||||
using VkPhysicalDevice = VkPhysicalDevice_T*;
|
||||
using VkDevice = VkDevice_T*;
|
||||
using VkInstance = VkInstance_T*;
|
||||
|
||||
|
||||
namespace sl
|
||||
{
|
||||
|
||||
//! NOTE: Adding new hooks require sl.interposer to be recompiled
|
||||
//!
|
||||
//! IMPORTANT: Since SL interposer proxies supports many different versions of various D3D/DXGI interfaces
|
||||
//! we use only base interface names for our hooks.
|
||||
//!
|
||||
//! For example if API was added in IDXGISwapChain5::FUNCTION it is still named eIDXGISwapChain_FUNCTION (there is no 5 in the name)
|
||||
//!
|
||||
enum class FunctionHookID : uint32_t
|
||||
{
|
||||
//! Mandatory - IDXGIFactory*
|
||||
eIDXGIFactory_CreateSwapChain,
|
||||
eIDXGIFactory_CreateSwapChainForHwnd,
|
||||
eIDXGIFactory_CreateSwapChainForCoreWindow,
|
||||
|
||||
//! Mandatory - IDXGISwapChain*
|
||||
eIDXGISwapChain_Present,
|
||||
eIDXGISwapChain_Present1,
|
||||
eIDXGISwapChain_GetBuffer,
|
||||
eIDXGISwapChain_GetDesc,
|
||||
eIDXGISwapChain_ResizeBuffers,
|
||||
eIDXGISwapChain_ResizeBuffers1,
|
||||
eIDXGISwapChain_GetCurrentBackBufferIndex,
|
||||
eIDXGISwapChain_SetFullscreenState,
|
||||
//! Internal - please ignore when doing manual hooking
|
||||
eIDXGISwapChain_Destroyed,
|
||||
|
||||
//! Mandatory - ID3D12Device*
|
||||
eID3D12Device_CreateCommandQueue,
|
||||
|
||||
//! Mandatory - Vulkan
|
||||
eVulkan_Present,
|
||||
eVulkan_CreateSwapchainKHR,
|
||||
eVulkan_DestroySwapchainKHR,
|
||||
eVulkan_GetSwapchainImagesKHR,
|
||||
eVulkan_AcquireNextImageKHR,
|
||||
eVulkan_DeviceWaitIdle,
|
||||
eVulkan_CreateWin32SurfaceKHR,
|
||||
eVulkan_DestroySurfaceKHR,
|
||||
|
||||
eMaxNum
|
||||
};
|
||||
|
||||
#ifndef SL_CASE_STR
|
||||
#define SL_CASE_STR(a) case a : return #a;
|
||||
#endif
|
||||
|
||||
inline const char* getFunctionHookIDAsStr(FunctionHookID v)
|
||||
{
|
||||
switch (v)
|
||||
{
|
||||
SL_CASE_STR(FunctionHookID::eIDXGIFactory_CreateSwapChain);
|
||||
SL_CASE_STR(FunctionHookID::eIDXGIFactory_CreateSwapChainForHwnd);
|
||||
SL_CASE_STR(FunctionHookID::eIDXGIFactory_CreateSwapChainForCoreWindow);
|
||||
SL_CASE_STR(FunctionHookID::eIDXGISwapChain_Present);
|
||||
SL_CASE_STR(FunctionHookID::eIDXGISwapChain_Present1);
|
||||
SL_CASE_STR(FunctionHookID::eIDXGISwapChain_GetBuffer);
|
||||
SL_CASE_STR(FunctionHookID::eIDXGISwapChain_GetDesc);
|
||||
SL_CASE_STR(FunctionHookID::eIDXGISwapChain_ResizeBuffers);
|
||||
SL_CASE_STR(FunctionHookID::eIDXGISwapChain_ResizeBuffers1);
|
||||
SL_CASE_STR(FunctionHookID::eIDXGISwapChain_GetCurrentBackBufferIndex);
|
||||
SL_CASE_STR(FunctionHookID::eIDXGISwapChain_SetFullscreenState);
|
||||
SL_CASE_STR(FunctionHookID::eIDXGISwapChain_Destroyed);
|
||||
SL_CASE_STR(FunctionHookID::eID3D12Device_CreateCommandQueue);
|
||||
SL_CASE_STR(FunctionHookID::eVulkan_Present);
|
||||
SL_CASE_STR(FunctionHookID::eVulkan_CreateSwapchainKHR);
|
||||
SL_CASE_STR(FunctionHookID::eVulkan_DestroySwapchainKHR);
|
||||
SL_CASE_STR(FunctionHookID::eVulkan_GetSwapchainImagesKHR);
|
||||
SL_CASE_STR(FunctionHookID::eVulkan_AcquireNextImageKHR);
|
||||
SL_CASE_STR(FunctionHookID::eVulkan_DeviceWaitIdle);
|
||||
SL_CASE_STR(FunctionHookID::eVulkan_CreateWin32SurfaceKHR);
|
||||
SL_CASE_STR(FunctionHookID::eVulkan_DestroySurfaceKHR);
|
||||
case FunctionHookID::eMaxNum: break;
|
||||
};
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
} // namespace sl
|
||||
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sl.h"
|
||||
#include "sl_consts.h"
|
||||
|
||||
namespace sl
|
||||
{
|
||||
|
||||
inline void matrixMul(float4x4& result, const float4x4& a, const float4x4& b)
|
||||
{
|
||||
// Alias raw pointers over the input matrices
|
||||
const float* pA = &a[0].x;
|
||||
const float* pB = &b[0].x;
|
||||
|
||||
result[0].x = (float)((pA[0] * pB[0]) + (pA[1] * pB[4]) + (pA[2] * pB[8]) + (pA[3] * pB[12]));
|
||||
result[0].y = (float)((pA[0] * pB[1]) + (pA[1] * pB[5]) + (pA[2] * pB[9]) + (pA[3] * pB[13]));
|
||||
result[0].z = (float)((pA[0] * pB[2]) + (pA[1] * pB[6]) + (pA[2] * pB[10]) + (pA[3] * pB[14]));
|
||||
result[0].w = (float)((pA[0] * pB[3]) + (pA[1] * pB[7]) + (pA[2] * pB[11]) + (pA[3] * pB[15]));
|
||||
|
||||
result[1].x = (float)((pA[4] * pB[0]) + (pA[5] * pB[4]) + (pA[6] * pB[8]) + (pA[7] * pB[12]));
|
||||
result[1].y = (float)((pA[4] * pB[1]) + (pA[5] * pB[5]) + (pA[6] * pB[9]) + (pA[7] * pB[13]));
|
||||
result[1].z = (float)((pA[4] * pB[2]) + (pA[5] * pB[6]) + (pA[6] * pB[10]) + (pA[7] * pB[14]));
|
||||
result[1].w = (float)((pA[4] * pB[3]) + (pA[5] * pB[7]) + (pA[6] * pB[11]) + (pA[7] * pB[15]));
|
||||
|
||||
result[2].x = (float)((pA[8] * pB[0]) + (pA[9] * pB[4]) + (pA[10] * pB[8]) + (pA[11] * pB[12]));
|
||||
result[2].y = (float)((pA[8] * pB[1]) + (pA[9] * pB[5]) + (pA[10] * pB[9]) + (pA[11] * pB[13]));
|
||||
result[2].z = (float)((pA[8] * pB[2]) + (pA[9] * pB[6]) + (pA[10] * pB[10]) + (pA[11] * pB[14]));
|
||||
result[2].w = (float)((pA[8] * pB[3]) + (pA[9] * pB[7]) + (pA[10] * pB[11]) + (pA[11] * pB[15]));
|
||||
|
||||
result[3].x = (float)((pA[12] * pB[0]) + (pA[13] * pB[4]) + (pA[14] * pB[8]) + (pA[15] * pB[12]));
|
||||
result[3].y = (float)((pA[12] * pB[1]) + (pA[13] * pB[5]) + (pA[14] * pB[9]) + (pA[15] * pB[13]));
|
||||
result[3].z = (float)((pA[12] * pB[2]) + (pA[13] * pB[6]) + (pA[14] * pB[10]) + (pA[15] * pB[14]));
|
||||
result[3].w = (float)((pA[12] * pB[3]) + (pA[13] * pB[7]) + (pA[14] * pB[11]) + (pA[15] * pB[15]));
|
||||
}
|
||||
|
||||
inline void matrixFullInvert(float4x4& result, const float4x4& mat)
|
||||
{
|
||||
// Matrix inversion code from https://stackoverflow.com/questions/1148309/inverting-a-4x4-matrix
|
||||
// Alias raw pointers over the input matrix and the result
|
||||
const float* pMat = &mat[0].x;
|
||||
float* pResult = &result[0].x;
|
||||
|
||||
pResult[0] = pMat[5] * pMat[10] * pMat[15] - pMat[5] * pMat[11] * pMat[14] - pMat[9] * pMat[6] * pMat[15] + pMat[9] * pMat[7] * pMat[14] + pMat[13] * pMat[6] * pMat[11] - pMat[13] * pMat[7] * pMat[10];
|
||||
pResult[4] = -pMat[4] * pMat[10] * pMat[15] + pMat[4] * pMat[11] * pMat[14] + pMat[8] * pMat[6] * pMat[15] - pMat[8] * pMat[7] * pMat[14] - pMat[12] * pMat[6] * pMat[11] + pMat[12] * pMat[7] * pMat[10];
|
||||
pResult[8] = pMat[4] * pMat[9] * pMat[15] - pMat[4] * pMat[11] * pMat[13] - pMat[8] * pMat[5] * pMat[15] + pMat[8] * pMat[7] * pMat[13] + pMat[12] * pMat[5] * pMat[11] - pMat[12] * pMat[7] * pMat[9];
|
||||
pResult[12] = -pMat[4] * pMat[9] * pMat[14] + pMat[4] * pMat[10] * pMat[13] + pMat[8] * pMat[5] * pMat[14] - pMat[8] * pMat[6] * pMat[13] - pMat[12] * pMat[5] * pMat[10] + pMat[12] * pMat[6] * pMat[9];
|
||||
pResult[1] = -pMat[1] * pMat[10] * pMat[15] + pMat[1] * pMat[11] * pMat[14] + pMat[9] * pMat[2] * pMat[15] - pMat[9] * pMat[3] * pMat[14] - pMat[13] * pMat[2] * pMat[11] + pMat[13] * pMat[3] * pMat[10];
|
||||
pResult[5] = pMat[0] * pMat[10] * pMat[15] - pMat[0] * pMat[11] * pMat[14] - pMat[8] * pMat[2] * pMat[15] + pMat[8] * pMat[3] * pMat[14] + pMat[12] * pMat[2] * pMat[11] - pMat[12] * pMat[3] * pMat[10];
|
||||
pResult[9] = -pMat[0] * pMat[9] * pMat[15] + pMat[0] * pMat[11] * pMat[13] + pMat[8] * pMat[1] * pMat[15] - pMat[8] * pMat[3] * pMat[13] - pMat[12] * pMat[1] * pMat[11] + pMat[12] * pMat[3] * pMat[9];
|
||||
pResult[13] = pMat[0] * pMat[9] * pMat[14] - pMat[0] * pMat[10] * pMat[13] - pMat[8] * pMat[1] * pMat[14] + pMat[8] * pMat[2] * pMat[13] + pMat[12] * pMat[1] * pMat[10] - pMat[12] * pMat[2] * pMat[9];
|
||||
pResult[2] = pMat[1] * pMat[6] * pMat[15] - pMat[1] * pMat[7] * pMat[14] - pMat[5] * pMat[2] * pMat[15] + pMat[5] * pMat[3] * pMat[14] + pMat[13] * pMat[2] * pMat[7] - pMat[13] * pMat[3] * pMat[6];
|
||||
pResult[6] = -pMat[0] * pMat[6] * pMat[15] + pMat[0] * pMat[7] * pMat[14] + pMat[4] * pMat[2] * pMat[15] - pMat[4] * pMat[3] * pMat[14] - pMat[12] * pMat[2] * pMat[7] + pMat[12] * pMat[3] * pMat[6];
|
||||
pResult[10] = pMat[0] * pMat[5] * pMat[15] - pMat[0] * pMat[7] * pMat[13] - pMat[4] * pMat[1] * pMat[15] + pMat[4] * pMat[3] * pMat[13] + pMat[12] * pMat[1] * pMat[7] - pMat[12] * pMat[3] * pMat[5];
|
||||
pResult[14] = -pMat[0] * pMat[5] * pMat[14] + pMat[0] * pMat[6] * pMat[13] + pMat[4] * pMat[1] * pMat[14] - pMat[4] * pMat[2] * pMat[13] - pMat[12] * pMat[1] * pMat[6] + pMat[12] * pMat[2] * pMat[5];
|
||||
pResult[3] = -pMat[1] * pMat[6] * pMat[11] + pMat[1] * pMat[7] * pMat[10] + pMat[5] * pMat[2] * pMat[11] - pMat[5] * pMat[3] * pMat[10] - pMat[9] * pMat[2] * pMat[7] + pMat[9] * pMat[3] * pMat[6];
|
||||
pResult[7] = pMat[0] * pMat[6] * pMat[11] - pMat[0] * pMat[7] * pMat[10] - pMat[4] * pMat[2] * pMat[11] + pMat[4] * pMat[3] * pMat[10] + pMat[8] * pMat[2] * pMat[7] - pMat[8] * pMat[3] * pMat[6];
|
||||
pResult[11] = -pMat[0] * pMat[5] * pMat[11] + pMat[0] * pMat[7] * pMat[9] + pMat[4] * pMat[1] * pMat[11] - pMat[4] * pMat[3] * pMat[9] - pMat[8] * pMat[1] * pMat[7] + pMat[8] * pMat[3] * pMat[5];
|
||||
pResult[15] = pMat[0] * pMat[5] * pMat[10] - pMat[0] * pMat[6] * pMat[9] - pMat[4] * pMat[1] * pMat[10] + pMat[4] * pMat[2] * pMat[9] + pMat[8] * pMat[1] * pMat[6] - pMat[8] * pMat[2] * pMat[5];
|
||||
|
||||
float det = pMat[0] * pResult[0] + pMat[1] * pResult[4] + pMat[2] * pResult[8] + pMat[3] * pResult[12];
|
||||
if (det != 0.f)
|
||||
{
|
||||
det = 1.0f / det;
|
||||
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
pResult[i] *= det;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Specialised lightweight matrix invert when the matrix is known to be orthonormal
|
||||
inline void matrixOrthoNormalInvert(float4x4& result, const float4x4& mat)
|
||||
{
|
||||
// Transpose the first 3x3
|
||||
result[0].x = mat[0].x;
|
||||
result[0].y = mat[1].x;
|
||||
result[0].z = mat[2].x;
|
||||
result[1].x = mat[0].y;
|
||||
result[1].y = mat[1].y;
|
||||
result[1].z = mat[2].y;
|
||||
result[2].x = mat[0].z;
|
||||
result[2].y = mat[1].z;
|
||||
result[2].z = mat[2].z;
|
||||
|
||||
// Invert the translation
|
||||
result[3].x = -((mat[3].x * mat[0].x) + (mat[3].y * mat[0].y) + (mat[3].z * mat[0].z));
|
||||
result[3].y = -((mat[3].x * mat[1].x) + (mat[3].y * mat[1].y) + (mat[3].z * mat[1].z));
|
||||
result[3].z = -((mat[3].x * mat[2].x) + (mat[3].y * mat[2].y) + (mat[3].z * mat[2].z));
|
||||
|
||||
// Fill in the remaining constants
|
||||
result[0].w = 0.0f;
|
||||
result[1].w = 0.0f;
|
||||
result[2].w = 0.0f;
|
||||
result[3].w = 1.0f;
|
||||
}
|
||||
|
||||
inline void vectorNormalize(float3& v)
|
||||
{
|
||||
float k = 1.f / sqrtf((v.x * v.x) + (v.y * v.y) + (v.z * v.z));
|
||||
v.x *= k;
|
||||
v.y *= k;
|
||||
v.z *= k;
|
||||
}
|
||||
|
||||
inline void vectorCrossProduct(float3& result, const float3& a, const float3& b)
|
||||
{
|
||||
result.x = a.y * b.z - a.z * b.y;
|
||||
result.y = a.z * b.x - a.x * b.z;
|
||||
result.z = a.x * b.y - a.y * b.x;
|
||||
}
|
||||
|
||||
// Calculate a cameraToPrevCamera matrix from cameraToWorld and cameraToWorldPrev matrices
|
||||
// but do so in such a way as to avoid precision issues.
|
||||
//
|
||||
// Traditionally, you might go something like this...
|
||||
//
|
||||
// worldToCameraPrev = invert(cameraToWorldPrev)
|
||||
// cameraToPrevCamera = cameraToWorld * worldToCameraPrev
|
||||
//
|
||||
// But if you do that, you will subject yourself to fp32 precision issues if the camera is
|
||||
// any kind of reasonable distance from the origin, because you'll end up adding small
|
||||
// numbers to large numbers due to the large translations.
|
||||
//
|
||||
// But the camera's absolute position in the world doesn't matter at all to the result.
|
||||
// What we're interested in is the camera's motion.
|
||||
// So if we add the same thing to the translations of cameraToWorld and cameraToWorldPrev
|
||||
// then we should get the same result.
|
||||
// If we choose to subtract the current camera's translation in world space, then we will
|
||||
// change a potentially very large translation value into a very small one - thereby
|
||||
// sidestepping the precision issues.
|
||||
inline void calcCameraToPrevCamera(float4x4& outCameraToPrevCamera, const float4x4& cameraToWorld, const float4x4& cameraToWorldPrev)
|
||||
{
|
||||
// Create translated versions of cameraToWorld and cameraToWorldPrev, translated to
|
||||
// so that the current camera is effectively at the world origin.
|
||||
// CC == 'Camera-Centred'
|
||||
float4x4 cameraToCcWorld = cameraToWorld;
|
||||
cameraToCcWorld[3] = float4(0, 0, 0, 1);
|
||||
float4x4 cameraToCcWorldPrev = cameraToWorldPrev;
|
||||
cameraToCcWorldPrev[3].x -= cameraToWorld[3].x;
|
||||
cameraToCcWorldPrev[3].y -= cameraToWorld[3].y;
|
||||
cameraToCcWorldPrev[3].z -= cameraToWorld[3].z;
|
||||
|
||||
// We can use an optimised invert if we assume that the camera matrix is orthonormal
|
||||
float4x4 ccWorldToCameraPrev;
|
||||
matrixOrthoNormalInvert(ccWorldToCameraPrev, cameraToCcWorldPrev);
|
||||
matrixMul(outCameraToPrevCamera, cameraToCcWorld, ccWorldToCameraPrev);
|
||||
}
|
||||
|
||||
// Calculate some of the matrix fields in Constants
|
||||
// This can be used to validate what the app is providing, or tease out precision issues
|
||||
// The matrices that are recalculated are...
|
||||
// - clipToCameraView
|
||||
// - clipToPrevClip
|
||||
// - prevClipToClip
|
||||
inline void recalculateCameraMatrices(Constants& values)
|
||||
{
|
||||
// Form a camera-to-world matrix from the camera fields
|
||||
vectorNormalize(values.cameraRight);
|
||||
vectorNormalize(values.cameraFwd);
|
||||
vectorCrossProduct(values.cameraUp, values.cameraFwd, values.cameraRight);
|
||||
vectorNormalize(values.cameraUp);
|
||||
float4x4 cameraViewToWorld = {
|
||||
float4(values.cameraRight.x, values.cameraRight.y, values.cameraRight.z, 0.f),
|
||||
float4(values.cameraUp.x, values.cameraUp.y, values.cameraUp.z, 0.f),
|
||||
float4(values.cameraFwd.x, values.cameraFwd.y, values.cameraFwd.z, 0.f),
|
||||
float4(values.cameraPos.x, values.cameraPos.y, values.cameraPos.z, 1.f)
|
||||
};
|
||||
// ********* DO NOT USE THIS IN ANYTHING PROPER *********
|
||||
// Crap storage of cameraViewToWorldPrev and cameraViewToClipPrev
|
||||
// These should be provided by the app, or stored by association with the view index.
|
||||
static float4x4 cameraViewToWorldPrev = {
|
||||
float4(1, 0, 0, 0),
|
||||
float4(0, 1, 0, 0),
|
||||
float4(0, 0, 1, 0),
|
||||
float4(0, 0, 0, 1),
|
||||
};
|
||||
static float4x4 cameraViewToClipPrev = {
|
||||
float4(1, 0, 0, 0),
|
||||
float4(0, 1, 0, 0),
|
||||
float4(0, 0, 1, 0),
|
||||
float4(0, 0, 0, 1),
|
||||
};
|
||||
matrixFullInvert(values.clipToCameraView, values.cameraViewToClip);
|
||||
|
||||
float4x4 cameraViewToPrevCameraView;
|
||||
calcCameraToPrevCamera(cameraViewToPrevCameraView, cameraViewToWorld, cameraViewToWorldPrev);
|
||||
|
||||
float4x4 clipToPrevCameraView;
|
||||
matrixMul(clipToPrevCameraView, values.clipToCameraView, cameraViewToPrevCameraView);
|
||||
matrixMul(values.clipToPrevClip, clipToPrevCameraView, cameraViewToClipPrev);
|
||||
matrixFullInvert(values.prevClipToClip, values.clipToPrevClip);
|
||||
|
||||
// ********* DO NOT USE THIS IN ANYTHING PROPER *********
|
||||
cameraViewToWorldPrev = cameraViewToWorld;
|
||||
cameraViewToClipPrev = values.cameraViewToClip;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace sl
|
||||
{
|
||||
|
||||
enum class NISMode : uint32_t
|
||||
{
|
||||
eOff,
|
||||
eScaler,
|
||||
eSharpen,
|
||||
eCount
|
||||
};
|
||||
|
||||
enum class NISHDR : uint32_t
|
||||
{
|
||||
eNone,
|
||||
eLinear,
|
||||
ePQ,
|
||||
eCount
|
||||
};
|
||||
|
||||
// {676610E5-9674-4D3A-9C8A-F495D01B36F3}
|
||||
SL_STRUCT_BEGIN(NISOptions, StructType({ 0x676610e5, 0x9674, 0x4d3a, { 0x9c, 0x8a, 0xf4, 0x95, 0xd0, 0x1b, 0x36, 0xf3 } }), kStructVersion1)
|
||||
//! Specifies which mode should be used
|
||||
NISMode mode = NISMode::eScaler;
|
||||
//! Specifies which hdr mode should be used
|
||||
NISHDR hdrMode = NISHDR::eNone;
|
||||
//! Specifies sharpening level in range [0,1]
|
||||
float sharpness = 0.0f;
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
//! Returned by the NIS plugin
|
||||
//!
|
||||
// {71AB4FD0-D959-4C2A-AF69-ED4850BD4E3D}
|
||||
SL_STRUCT_BEGIN(NISState, StructType({ 0x71ab4fd0, 0xd959, 0x4c2a, { 0xaf, 0x69, 0xed, 0x48, 0x50, 0xbd, 0x4e, 0x3d } }), kStructVersion1)
|
||||
//! Specified the amount of memory expected to be used
|
||||
uint64_t estimatedVRAMUsageInBytes {};
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
}
|
||||
|
||||
//! Sets NIS options
|
||||
//!
|
||||
//! Call this method to turn DLSS on/off, change mode etc.
|
||||
//!
|
||||
//! @param viewport Specified viewport we are working with
|
||||
//! @param options Specifies NIS options to use
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is NOT thread safe.
|
||||
using PFun_slNISSetOptions = sl::Result(const sl::ViewportHandle& viewport, const sl::NISOptions& options);
|
||||
|
||||
//! Provides NIS state for the given viewport
|
||||
//!
|
||||
//! Call this method to obtain VRAM usage and other information.
|
||||
//!
|
||||
//! @param viewport Specified viewport we are working with
|
||||
//! @param state Reference to a structure where state is to be returned
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is NOT thread safe.
|
||||
using PFun_slNISGetState = sl::Result(const sl::ViewportHandle& viewport, sl::NISState& state);
|
||||
|
||||
//! HELPERS
|
||||
//!
|
||||
inline sl::Result slNISSetOptions(const sl::ViewportHandle& viewport, const sl::NISOptions& options)
|
||||
{
|
||||
SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureNIS, slNISSetOptions);
|
||||
return s_slNISSetOptions(viewport, options);
|
||||
}
|
||||
|
||||
inline sl::Result slNISGetState(const sl::ViewportHandle& viewport, sl::NISState& state)
|
||||
{
|
||||
SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureNIS, slNISGetState);
|
||||
return s_slNISGetState(viewport, state);
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2014-2023 NVIDIA Corporation. All rights reserved.
|
||||
*
|
||||
* NOTICE TO USER:
|
||||
*
|
||||
* This source code is subject to NVIDIA ownership rights under U.S. and
|
||||
* international Copyright laws.
|
||||
*
|
||||
* This software and the information contained herein is PROPRIETARY and
|
||||
* CONFIDENTIAL to NVIDIA and is being provided under the terms and conditions
|
||||
* of a form of NVIDIA software license agreement.
|
||||
*
|
||||
* NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE
|
||||
* CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR
|
||||
* IMPLIED WARRANTY OF ANY KIND. NVIDIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL,
|
||||
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
|
||||
* OR PERFORMANCE OF THIS SOURCE CODE.
|
||||
*
|
||||
* U.S. Government End Users. This source code is a "commercial item" as
|
||||
* that term is defined at 48 C.F.R. 2.101 (OCT 1995), consisting of
|
||||
* "commercial computer software" and "commercial computer software
|
||||
* documentation" as such terms are used in 48 C.F.R. 12.212 (SEPT 1995)
|
||||
* and is provided to the U.S. Government only as a commercial end item.
|
||||
* Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through
|
||||
* 227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the
|
||||
* source code with only those rights set forth herein.
|
||||
*
|
||||
* Any use of this source code in individual and commercial software must
|
||||
* include, in the user documentation and internal comments to the code,
|
||||
* the above Disclaimer and U.S. Government End Users Notice.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace sl
|
||||
{
|
||||
|
||||
//! If your plugin does not have any constants then the code below can be removed
|
||||
//!
|
||||
enum class NvPerfMode : uint32_t
|
||||
{
|
||||
eOff,
|
||||
eOn,
|
||||
|
||||
eCount
|
||||
};
|
||||
|
||||
//! IMPORTANT: Each structure must have a unique GUID assigned, change this as needed
|
||||
//!
|
||||
// {29DF7FE0-273A-4D72-B481-2DC823D5B1AD}
|
||||
SL_STRUCT_BEGIN(NvPerfConstants, StructType({ 0x29df7fe0, 0x273a, 0x4d72, { 0xb4, 0x81, 0x2d, 0xc8, 0x23, 0xd5, 0xb1, 0xad } }), kStructVersion1)
|
||||
NvPerfMode mode = NvPerfMode::eOff;
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
//! IMPORTANT: Each structure must have a unique GUID assigned, change this as needed
|
||||
//!
|
||||
// {39DF7FE0-283A-4D72-B481-2DC823D5B1AD}
|
||||
SL_STRUCT_BEGIN(NvPerfSettings, StructType({ 0x39df7fe0, 0x283a, 0x4d72, { 0xb4, 0x81, 0x2d, 0xc8, 0x23, 0xd5, 0xb1, 0xad } }), kStructVersion1)
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 2023 NVIDIA CORPORATION. All rights reserved
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace sl
|
||||
{
|
||||
|
||||
//! Hot-key which should be used instead of custom message for PC latency marker
|
||||
enum class PCLHotKey: int16_t
|
||||
{
|
||||
eUsePingMessage = 0,
|
||||
eVK_F13 = 0x7C,
|
||||
eVK_F14 = 0x7D,
|
||||
eVK_F15 = 0x7E,
|
||||
};
|
||||
|
||||
// {cfa32f9b-023c-420e-9056-6832b74f89b4}
|
||||
SL_STRUCT_BEGIN(PCLOptions, StructType({ 0xcfa32f9b, 0x023c, 0x420e, { 0x90, 0x56, 0x68, 0x32, 0xb7, 0x4f, 0x89, 0xb4 } }), kStructVersion1)
|
||||
//! Specifies the hot-key which should be used instead of custom message for PC latency marker
|
||||
//! Possible values: VK_F13, VK_F14, VK_F15
|
||||
PCLHotKey virtualKey = PCLHotKey::eUsePingMessage;
|
||||
//! ThreadID for PCL messages
|
||||
uint32_t idThread = 0;
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
// {cfa32f9b-023c-420e-9056-6832b74f89b5}
|
||||
SL_STRUCT_BEGIN(PCLState, StructType({ 0xcfa32f9b, 0x023c, 0x420e, { 0x90, 0x56, 0x68, 0x32, 0xb7, 0x4f, 0x89, 0xb5 } }), kStructVersion1)
|
||||
//! Specifies PCL Windows message id (if PCLOptions::virtualKey is 0)
|
||||
uint32_t statsWindowMessage;
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
enum class PCLMarker: uint32_t
|
||||
{
|
||||
eSimulationStart = 0,
|
||||
eSimulationEnd = 1,
|
||||
eRenderSubmitStart = 2,
|
||||
eRenderSubmitEnd = 3,
|
||||
ePresentStart = 4,
|
||||
ePresentEnd = 5,
|
||||
//eInputSample = 6, // Deprecated
|
||||
eTriggerFlash = 7,
|
||||
ePCLatencyPing = 8,
|
||||
eOutOfBandRenderSubmitStart = 9,
|
||||
eOutOfBandRenderSubmitEnd = 10,
|
||||
eOutOfBandPresentStart = 11,
|
||||
eOutOfBandPresentEnd = 12,
|
||||
eControllerInputSample = 13,
|
||||
eDeltaTCalculation = 14,
|
||||
eLateWarpPresentStart = 15,
|
||||
eLateWarpPresentEnd = 16,
|
||||
eCameraConstructed = 17,
|
||||
eLateWarpRenderSubmitStart = 18,
|
||||
eLateWarpRenderSubmitEnd = 19,
|
||||
|
||||
eMaximum
|
||||
};
|
||||
|
||||
// c++23 has to_underlying implementation
|
||||
#if __cplusplus == 202302L
|
||||
using to_underlying = std::to_underlying;
|
||||
#else
|
||||
// Return `enum class` member as value of underlying type (i.e. an int). Basically same as:
|
||||
// static_cast<std::underlying_type_t<decltype(value)>>(value);
|
||||
// See c++23s std::to_underlying()
|
||||
template<class T>
|
||||
constexpr auto to_underlying(T value)
|
||||
{
|
||||
return std::underlying_type_t<T>(value);
|
||||
}
|
||||
#endif
|
||||
|
||||
// {cfa32f9b-023c-420e-9056-6832b74f89b6}
|
||||
SL_STRUCT_BEGIN(PCLHelper, StructType({ 0xcfa32f9b, 0x023c, 0x420e, { 0x90, 0x56, 0x68, 0x32, 0xb7, 0x4f, 0x89, 0xb6 } }), kStructVersion1)
|
||||
PCLHelper(PCLMarker m) : BaseStructure(PCLHelper::s_structType, kStructVersion1), marker(m) {};
|
||||
PCLMarker get() const { return marker; };
|
||||
private:
|
||||
PCLMarker marker;
|
||||
SL_STRUCT_END()
|
||||
|
||||
|
||||
}
|
||||
|
||||
//! Provides PCL settings
|
||||
//!
|
||||
//! Call this method to get stats etc.
|
||||
//!
|
||||
//! @param state Reference to a structure where states are returned
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is NOT thread safe.
|
||||
using PFun_slPCLGetState = sl::Result(sl::PCLState& state);
|
||||
|
||||
//! Sets PCL marker
|
||||
//!
|
||||
//! Call this method to set specific PCL marker
|
||||
//!
|
||||
//! @param marker Specifies which marker to use
|
||||
//! @param frame Specifies current frame
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is thread safe.
|
||||
using PFun_slPCLSetMarker = sl::Result(sl::PCLMarker marker, const sl::FrameToken& frame);
|
||||
|
||||
//! Sets PCL options
|
||||
//!
|
||||
//! Call this method to set PCL options.
|
||||
//!
|
||||
//! @param options Specifies options to use
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is NOT thread safe.
|
||||
using PFun_slPCLSetOptions = sl::Result(const sl::PCLOptions& options);
|
||||
|
||||
//! HELPERS
|
||||
//!
|
||||
inline sl::Result slPCLGetState(sl::PCLState& state)
|
||||
{
|
||||
SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeaturePCL, slPCLGetState);
|
||||
return s_slPCLGetState(state);
|
||||
}
|
||||
|
||||
inline sl::Result slPCLSetMarker(sl::PCLMarker marker, const sl::FrameToken& frame)
|
||||
{
|
||||
SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeaturePCL, slPCLSetMarker);
|
||||
return s_slPCLSetMarker(marker, frame);
|
||||
}
|
||||
|
||||
inline sl::Result slPCLSetOptions(const sl::PCLOptions& options)
|
||||
{
|
||||
SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeaturePCL, slPCLSetOptions);
|
||||
return s_slPCLSetOptions(options);
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sl_pcl.h"
|
||||
|
||||
namespace sl
|
||||
{
|
||||
|
||||
enum ReflexMode
|
||||
{
|
||||
eOff,
|
||||
eLowLatency,
|
||||
eLowLatencyWithBoost,
|
||||
|
||||
// ReflexMode is a C-enum (rather than enum class) so we can't add an eCount value
|
||||
// without polluting the global namespace (and conflicts with SMSCGMode::eCount in sl.dlss_g/defines.h)
|
||||
ReflexMode_eCount
|
||||
};
|
||||
|
||||
// {F03AF81A-6D0B-4902-A651-C4965E215434}
|
||||
SL_STRUCT_BEGIN(ReflexOptions, StructType({ 0xf03af81a, 0x6d0b, 0x4902, { 0xa6, 0x51, 0xc4, 0x96, 0x5e, 0x21, 0x54, 0x34 } }), kStructVersion1)
|
||||
//! Specifies which mode should be used
|
||||
ReflexMode mode = ReflexMode::eOff;
|
||||
//! Specifies if frame limiting (FPS cap) is enabled (0 to disable, microseconds otherwise).
|
||||
//! One benefit of using Reflex's FPS cap over other implementations is the driver would be aware and can provide better optimizations.
|
||||
//! This setting is independent of ReflexOptions::mode; it can even be used with mode == ReflexMode::eOff.
|
||||
//! The value is used each time you call slReflexSetOptions/slSetData, make sure to initialize when changing one of the other Reflex options during frame limiting.
|
||||
//! It is overridden (ignored) by frameLimitUs if set in sl.reflex.json in non-production builds.
|
||||
uint32_t frameLimitUs = 0;
|
||||
//! This should only be enabled in specific scenarios with subtle caveats.
|
||||
//! Most integrations should leave unset unless advised otherwise by the Reflex team
|
||||
bool useMarkersToOptimize = false;
|
||||
//! Specifies the hot-key which should be used instead of custom message for PC latency marker
|
||||
//! Possible values: VK_F13, VK_F14, VK_F15
|
||||
uint16_t virtualKey = 0;
|
||||
//! ThreadID for PCL Stats messages
|
||||
//! Most integrations should leave unset unless advised otherwise by the Reflex team
|
||||
uint32_t idThread = 0;
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
// {0D569B37-A1C8-4453-BE4D-40F4DE57952B}
|
||||
SL_STRUCT_BEGIN(ReflexReport, StructType({ 0xd569b37, 0xa1c8, 0x4453, { 0xbe, 0x4d, 0x40, 0xf4, 0xde, 0x57, 0x95, 0x2b } }), kStructVersion1)
|
||||
//! Various latency related stats
|
||||
uint64_t frameID{};
|
||||
uint64_t inputSampleTime{};
|
||||
uint64_t simStartTime{};
|
||||
uint64_t simEndTime{};
|
||||
uint64_t renderSubmitStartTime{};
|
||||
uint64_t renderSubmitEndTime{};
|
||||
uint64_t presentStartTime{};
|
||||
uint64_t presentEndTime{};
|
||||
uint64_t driverStartTime{};
|
||||
uint64_t driverEndTime{};
|
||||
uint64_t osRenderQueueStartTime{};
|
||||
uint64_t osRenderQueueEndTime{};
|
||||
uint64_t gpuRenderStartTime{};
|
||||
uint64_t gpuRenderEndTime{};
|
||||
uint32_t gpuActiveRenderTimeUs{};
|
||||
uint32_t gpuFrameTimeUs{};
|
||||
//! IMPORTANT: This struct cannot have new members because it is arrayed by ReflexState.
|
||||
SL_STRUCT_END()
|
||||
|
||||
// {68bb0632-5e1c-402b-899d-b49f633c56c2}
|
||||
SL_STRUCT_BEGIN(ReflexReport2, StructType({ 0x68bb0632, 0x5e1c, 0x402b, { 0x89, 0x9d, 0xb4, 0x9f, 0x63, 0x3c, 0x56, 0xc2 } }), kStructVersion1)
|
||||
//! Various latency related stats
|
||||
uint64_t cameraConstructedTime{};
|
||||
uint32_t crossAdapterCopyTimeUs{};
|
||||
//! IMPORTANT: This struct cannot have new members because it is arrayed by ReflexState.
|
||||
SL_STRUCT_END()
|
||||
|
||||
constexpr int kReflexFrameReportCount = 64;
|
||||
|
||||
// {F0BB5985-DAF9-4728-B2FD-AE80A2BD7989}
|
||||
SL_STRUCT_BEGIN(ReflexState, StructType({ 0xf0bb5985, 0xdaf9, 0x4728, { 0xb2, 0xfd, 0xae, 0x80, 0xa2, 0xbd, 0x79, 0x89 } }), kStructVersion2)
|
||||
//! Specifies if low-latency mode is available or not
|
||||
bool lowLatencyAvailable = false;
|
||||
//! Specifies if the frameReport below contains valid data or not
|
||||
bool latencyReportAvailable = false;
|
||||
//! Specifies low latency Windows message id (if ReflexOptions::virtualKey is 0)
|
||||
uint32_t statsWindowMessage;
|
||||
//! Reflex report per frame
|
||||
ReflexReport frameReport[kReflexFrameReportCount];
|
||||
//! Specifies ownership of flash indicator toggle (true = driver, false = application)
|
||||
bool flashIndicatorDriverControlled = false;
|
||||
// kStructVersion2
|
||||
//! Reflex report per frame
|
||||
ReflexReport2 frameReport2[kReflexFrameReportCount];
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
// {c83cbb02-b4e2-4260-9ca2-d0c3de3a9684}
|
||||
SL_STRUCT_BEGIN(ReflexCameraData, StructType({ 0xc83cbb02, 0xb4e2, 0x4260, { 0x9c, 0xa2, 0xd0, 0xc3, 0xde, 0x3a, 0x96, 0x84 } }), kStructVersion1)
|
||||
float4x4 worldToViewMatrix;
|
||||
float4x4 viewToClipMatrix;
|
||||
float4x4 prevRenderedWorldToViewMatrix;
|
||||
float4x4 prevRenderedViewToClipMatrix;
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
// {8b960090-a807-4c85-b02f-1069950d066c}
|
||||
SL_STRUCT_BEGIN(ReflexPredictedCameraData, StructType({ 0x8b960090, 0xa807, 0x4c85, { 0xb0, 0x2f, 0x10, 0x69, 0x95, 0x0d, 0x06, 0x6c } }), kStructVersion1)
|
||||
float4x4 predictedWorldToViewMatrix;
|
||||
float4x4 predictedViewToClipMatrix;
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
using MarkerUnderlying = std::underlying_type_t<PCLMarker>;
|
||||
|
||||
// {E268B3DC-F963-4C37-9776-AF048E132621}
|
||||
SL_STRUCT_BEGIN(ReflexHelper, StructType({ 0xe268b3dc, 0xf963, 0x4c37, { 0x97, 0x76, 0xaf, 0x4, 0x8e, 0x13, 0x26, 0x21 } }), kStructVersion1)
|
||||
ReflexHelper(MarkerUnderlying m) : BaseStructure(ReflexHelper::s_structType, kStructVersion1), marker(m) {};
|
||||
ReflexHelper(PCLMarker m) : BaseStructure(ReflexHelper::s_structType, kStructVersion1), marker(to_underlying(m)) {};
|
||||
operator MarkerUnderlying () const { return marker; };
|
||||
private:
|
||||
// May be kReflexMarkerSleep which is not a valid PCLMarker value
|
||||
MarkerUnderlying marker;
|
||||
SL_STRUCT_END()
|
||||
|
||||
|
||||
}
|
||||
|
||||
//! Provides Reflex settings
|
||||
//!
|
||||
//! Call this method to check if Reflex is on, get stats etc.
|
||||
//!
|
||||
//! @param state Reference to a structure where states are returned
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is NOT thread safe.
|
||||
using PFun_slReflexGetState = sl::Result(sl::ReflexState& state);
|
||||
|
||||
//! Tells reflex to sleep the app
|
||||
//!
|
||||
//! Call this method to invoke Reflex sleep in your application.
|
||||
//!
|
||||
//! @param frame Specifies current frame
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is thread safe.
|
||||
using PFun_slReflexSleep = sl::Result(const sl::FrameToken& frame);
|
||||
|
||||
//! Sets Reflex options
|
||||
//!
|
||||
//! Call this method to turn Reflex on/off, change mode etc.
|
||||
//!
|
||||
//! @param options Specifies options to use
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is NOT thread safe.
|
||||
using PFun_slReflexSetOptions = sl::Result(const sl::ReflexOptions& options);
|
||||
|
||||
//! Sets Reflex camera data
|
||||
//!
|
||||
//! Call this method to inform Reflex of upcoming camera data
|
||||
//!
|
||||
//! @param viewport The viewport the camera corresponds to
|
||||
//! @param frame The frame to set camera data for
|
||||
//! @param inCameraData Camera data for an upcoming render frame
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is thread safe.
|
||||
using PFun_slReflexSetCameraData = sl::Result(const sl::ViewportHandle& viewport, const sl::FrameToken& frame, const sl::ReflexCameraData& inCameraData);
|
||||
|
||||
//! Gets predicted Reflex camera data
|
||||
//!
|
||||
//! Call this method to get a prediction of upcoming camera data
|
||||
//!
|
||||
//! @param viewport The viewport the camera corresponds to
|
||||
//! @param frame The frame to get camera data for (if available)
|
||||
//! @param outCameraData Predicted Camera data for an upcoming render frame
|
||||
//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details)
|
||||
//!
|
||||
//! This method is thread safe.
|
||||
using PFun_slReflexGetPredictedCameraData = sl::Result(const sl::ViewportHandle& viewport, const sl::FrameToken& frame, sl::ReflexPredictedCameraData& outCameraData);
|
||||
|
||||
//! HELPERS
|
||||
//!
|
||||
inline sl::Result slReflexGetState(sl::ReflexState& state)
|
||||
{
|
||||
SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureReflex, slReflexGetState);
|
||||
return s_slReflexGetState(state);
|
||||
}
|
||||
|
||||
inline sl::Result slReflexSleep(const sl::FrameToken& frame)
|
||||
{
|
||||
SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureReflex, slReflexSleep);
|
||||
return s_slReflexSleep(frame);
|
||||
}
|
||||
|
||||
inline sl::Result slReflexSetOptions(const sl::ReflexOptions& options)
|
||||
{
|
||||
SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureReflex, slReflexSetOptions);
|
||||
return s_slReflexSetOptions(options);
|
||||
}
|
||||
|
||||
inline sl::Result slReflexSetCameraData(const sl::ViewportHandle& viewport, const sl::FrameToken& frame, const sl::ReflexCameraData& inCameraData)
|
||||
{
|
||||
SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureReflex, slReflexSetCameraData);
|
||||
return s_slReflexSetCameraData(viewport, frame, inCameraData);
|
||||
}
|
||||
|
||||
inline sl::Result slReflexGetPredictedCameraData(const sl::ViewportHandle& viewport, const sl::FrameToken& frame, sl::ReflexPredictedCameraData& outCameraData)
|
||||
{
|
||||
SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureReflex, slReflexGetPredictedCameraData);
|
||||
return s_slReflexGetPredictedCameraData(viewport, frame, outCameraData);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2024 NVIDIA CORPORATION. All rights reserved
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define SL_CHECK(f) {auto _r = f; if(_r != sl::Result::eOk) return _r;}
|
||||
#define SL_FAILED(r, f) sl::Result r = f; r != sl::Result::eOk
|
||||
#define SL_SUCCEEDED(r, f) sl::Result r = f; r == sl::Result::eOk
|
||||
|
||||
namespace sl
|
||||
{
|
||||
|
||||
enum class Result
|
||||
{
|
||||
eOk,
|
||||
eErrorIO,
|
||||
eErrorDriverOutOfDate,
|
||||
eErrorOSOutOfDate,
|
||||
eErrorOSDisabledHWS,
|
||||
eErrorDeviceNotCreated,
|
||||
eErrorNoSupportedAdapterFound,
|
||||
eErrorAdapterNotSupported,
|
||||
eErrorNoPlugins,
|
||||
eErrorVulkanAPI,
|
||||
eErrorDXGIAPI,
|
||||
eErrorD3DAPI,
|
||||
// NRD was removed
|
||||
eErrorNRDAPI,
|
||||
eErrorNVAPI,
|
||||
eErrorReflexAPI,
|
||||
eErrorNGXFailed,
|
||||
eErrorJSONParsing,
|
||||
eErrorMissingProxy,
|
||||
eErrorMissingResourceState,
|
||||
eErrorInvalidIntegration,
|
||||
eErrorMissingInputParameter,
|
||||
eErrorNotInitialized,
|
||||
eErrorComputeFailed,
|
||||
eErrorInitNotCalled,
|
||||
eErrorExceptionHandler,
|
||||
eErrorInvalidParameter,
|
||||
eErrorMissingConstants,
|
||||
eErrorDuplicatedConstants,
|
||||
eErrorMissingOrInvalidAPI,
|
||||
eErrorCommonConstantsMissing,
|
||||
eErrorUnsupportedInterface,
|
||||
eErrorFeatureMissing,
|
||||
eErrorFeatureNotSupported,
|
||||
eErrorFeatureMissingHooks,
|
||||
eErrorFeatureFailedToLoad,
|
||||
eErrorFeatureWrongPriority,
|
||||
eErrorFeatureMissingDependency,
|
||||
eErrorFeatureManagerInvalidState,
|
||||
eErrorInvalidState,
|
||||
eWarnOutOfVRAM
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,463 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define _UNICODE 1
|
||||
#define UNICODE 1
|
||||
|
||||
#include <tchar.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
#include <Softpub.h>
|
||||
#include <wincrypt.h>
|
||||
#include <wintrust.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define GetProc(hModule, procName, proc) (((NULL == proc) && (NULL == (*((FARPROC*)&proc) = GetProcAddress(hModule, procName)))) ? FALSE : TRUE)
|
||||
|
||||
typedef BOOL(WINAPI* PfnCryptMsgClose)(IN HCRYPTMSG hCryptMsg);
|
||||
static PfnCryptMsgClose pfnCryptMsgClose = NULL;
|
||||
|
||||
typedef BOOL(WINAPI* PfnCertCloseStore)(IN HCERTSTORE hCertStore, DWORD dwFlags);
|
||||
static PfnCertCloseStore pfnCertCloseStore = NULL;
|
||||
|
||||
typedef HCERTSTORE (WINAPI* PfnCertOpenStore)(
|
||||
_In_ LPCSTR lpszStoreProvider,
|
||||
_In_ DWORD dwEncodingType,
|
||||
_In_opt_ HCRYPTPROV_LEGACY hCryptProv,
|
||||
_In_ DWORD dwFlags,
|
||||
_In_opt_ const void* pvPara
|
||||
);
|
||||
static PfnCertOpenStore pfnCertOpenStore = NULL;
|
||||
|
||||
typedef BOOL(WINAPI* PfnCertFreeCertificateContext)(IN PCCERT_CONTEXT pCertContext);
|
||||
static PfnCertFreeCertificateContext pfnCertFreeCertificateContext = NULL;
|
||||
|
||||
typedef PCCERT_CONTEXT(WINAPI* PfnCertFindCertificateInStore)(
|
||||
IN HCERTSTORE hCertStore,
|
||||
IN DWORD dwCertEncodingType,
|
||||
IN DWORD dwFindFlags,
|
||||
IN DWORD dwFindType,
|
||||
IN const void* pvFindPara,
|
||||
IN PCCERT_CONTEXT pPrevCertContext
|
||||
);
|
||||
static PfnCertFindCertificateInStore pfnCertFindCertificateInStore = NULL;
|
||||
|
||||
typedef BOOL(WINAPI* PfnCryptMsgGetParam)(
|
||||
IN HCRYPTMSG hCryptMsg,
|
||||
IN DWORD dwParamType,
|
||||
IN DWORD dwIndex,
|
||||
OUT void* pvData,
|
||||
IN OUT DWORD* pcbData
|
||||
);
|
||||
static PfnCryptMsgGetParam pfnCryptMsgGetParam = NULL;
|
||||
|
||||
typedef HCRYPTMSG (WINAPI* PfnCryptMsgOpenToDecode)(
|
||||
_In_ DWORD dwMsgEncodingType,
|
||||
_In_ DWORD dwFlags,
|
||||
_In_ DWORD dwMsgType,
|
||||
_In_opt_ HCRYPTPROV_LEGACY hCryptProv,
|
||||
_Reserved_ PCERT_INFO pRecipientInfo,
|
||||
_In_opt_ PCMSG_STREAM_INFO pStreamInfo
|
||||
);
|
||||
PfnCryptMsgOpenToDecode pfnCryptMsgOpenToDecode = {};
|
||||
|
||||
typedef BOOL (WINAPI* PfnCryptMsgUpdate)(
|
||||
_In_ HCRYPTMSG hCryptMsg,
|
||||
_In_reads_bytes_opt_(cbData) const BYTE* pbData,
|
||||
_In_ DWORD cbData,
|
||||
_In_ BOOL fFinal
|
||||
);
|
||||
PfnCryptMsgUpdate pfnCryptMsgUpdate = {};
|
||||
|
||||
typedef BOOL(WINAPI* PfnCryptQueryObject)(
|
||||
DWORD dwObjectType,
|
||||
const void* pvObject,
|
||||
DWORD dwExpectedContentTypeFlags,
|
||||
DWORD dwExpectedFormatTypeFlags,
|
||||
DWORD dwFlags,
|
||||
DWORD* pdwMsgAndCertEncodingType,
|
||||
DWORD* pdwContentType,
|
||||
DWORD* pdwFormatType,
|
||||
HCERTSTORE* phCertStore,
|
||||
HCRYPTMSG* phMsg,
|
||||
const void** ppvContext
|
||||
);
|
||||
static PfnCryptQueryObject pfnCryptQueryObject = NULL;
|
||||
|
||||
typedef BOOL(WINAPI* PfnCryptDecodeObjectEx)(
|
||||
IN DWORD dwCertEncodingType,
|
||||
IN LPCSTR lpszStructType,
|
||||
IN const BYTE* pbEncoded,
|
||||
IN DWORD cbEncoded,
|
||||
IN DWORD dwFlags,
|
||||
IN PCRYPT_DECODE_PARA pDecodePara,
|
||||
OUT void* pvStructInfo,
|
||||
IN OUT DWORD* pcbStructInfo
|
||||
);
|
||||
static PfnCryptDecodeObjectEx pfnCryptDecodeObjectEx = NULL;
|
||||
|
||||
typedef LONG(WINAPI* PfnWinVerifyTrust)(
|
||||
IN HWND hwnd,
|
||||
IN GUID* pgActionID,
|
||||
IN LPVOID pWVTData
|
||||
);
|
||||
static PfnWinVerifyTrust pfnWinVerifyTrust = NULL;
|
||||
|
||||
namespace sl
|
||||
{
|
||||
|
||||
namespace security
|
||||
{
|
||||
|
||||
bool isSignedByNVIDIA(const wchar_t* pathToFile)
|
||||
{
|
||||
bool valid = false;
|
||||
|
||||
// Now let's make sure this is actually signed by NVIDIA
|
||||
|
||||
DWORD dwEncoding, dwContentType, dwFormatType;
|
||||
HCERTSTORE hStore = NULL;
|
||||
HCRYPTMSG hMsg = NULL;
|
||||
PCMSG_SIGNER_INFO pSignerInfo = NULL;
|
||||
DWORD dwSignerInfo;
|
||||
|
||||
if (!pfnCertOpenStore)
|
||||
{
|
||||
// We only support Win10+ so we can search for module in system32 directly
|
||||
auto hModCrypt32 = LoadLibraryExW(L"crypt32.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||
if (!hModCrypt32 ||
|
||||
!GetProc(hModCrypt32, "CryptMsgClose", pfnCryptMsgClose) ||
|
||||
!GetProc(hModCrypt32, "CertOpenStore", pfnCertOpenStore) ||
|
||||
!GetProc(hModCrypt32, "CertCloseStore", pfnCertCloseStore) ||
|
||||
!GetProc(hModCrypt32, "CertFreeCertificateContext", pfnCertFreeCertificateContext) ||
|
||||
!GetProc(hModCrypt32, "CertFindCertificateInStore", pfnCertFindCertificateInStore) ||
|
||||
!GetProc(hModCrypt32, "CryptMsgGetParam", pfnCryptMsgGetParam) ||
|
||||
!GetProc(hModCrypt32, "CryptMsgUpdate", pfnCryptMsgUpdate) ||
|
||||
!GetProc(hModCrypt32, "CryptMsgOpenToDecode", pfnCryptMsgOpenToDecode) ||
|
||||
!GetProc(hModCrypt32, "CryptQueryObject", pfnCryptQueryObject) ||
|
||||
!GetProc(hModCrypt32, "CryptDecodeObjectEx", pfnCryptDecodeObjectEx))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Get message handle and store handle from the signed file.
|
||||
auto bResult = pfnCryptQueryObject(CERT_QUERY_OBJECT_FILE,
|
||||
pathToFile,
|
||||
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
|
||||
CERT_QUERY_FORMAT_FLAG_BINARY,
|
||||
0,
|
||||
&dwEncoding,
|
||||
&dwContentType,
|
||||
&dwFormatType,
|
||||
&hStore,
|
||||
&hMsg,
|
||||
NULL);
|
||||
if (!bResult)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get signer information size.
|
||||
bResult = pfnCryptMsgGetParam(hMsg,
|
||||
CMSG_SIGNER_INFO_PARAM,
|
||||
0,
|
||||
NULL,
|
||||
&dwSignerInfo);
|
||||
if (!bResult)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allocate memory for signer information.
|
||||
pSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSignerInfo);
|
||||
if (!pSignerInfo)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get Signer Information.
|
||||
bResult = pfnCryptMsgGetParam(hMsg,
|
||||
CMSG_SIGNER_INFO_PARAM,
|
||||
0,
|
||||
(PVOID)pSignerInfo,
|
||||
&dwSignerInfo);
|
||||
if (!bResult)
|
||||
{
|
||||
LocalFree(pSignerInfo);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Look for nested signature
|
||||
constexpr const char* kOID_NESTED_SIGNATURE = "1.3.6.1.4.1.311.2.4.1";
|
||||
for (DWORD i = 0; i < pSignerInfo->UnauthAttrs.cAttr; i++)
|
||||
{
|
||||
if (strcmp(kOID_NESTED_SIGNATURE, pSignerInfo->UnauthAttrs.rgAttr[i].pszObjId) == 0)
|
||||
{
|
||||
HCRYPTMSG hMsg2 = pfnCryptMsgOpenToDecode(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, 0, NULL, NULL, NULL);
|
||||
if (hMsg2)
|
||||
{
|
||||
if (pfnCryptMsgUpdate(hMsg2,pSignerInfo->UnauthAttrs.rgAttr[i].rgValue->pbData,pSignerInfo->UnauthAttrs.rgAttr[i].rgValue->cbData,TRUE))
|
||||
{
|
||||
dwSignerInfo = 0;
|
||||
pfnCryptMsgGetParam(hMsg2, CMSG_SIGNER_INFO_PARAM, 0, NULL, &dwSignerInfo);
|
||||
if (dwSignerInfo != 0)
|
||||
{
|
||||
PCMSG_SIGNER_INFO pSignerInfo2 = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSignerInfo);
|
||||
if (pSignerInfo2)
|
||||
{
|
||||
if (pfnCryptMsgGetParam(hMsg2, CMSG_SIGNER_INFO_PARAM, 0, (PVOID)pSignerInfo2, &dwSignerInfo))
|
||||
{
|
||||
CRYPT_DATA_BLOB c7Data;
|
||||
c7Data.pbData = pSignerInfo->UnauthAttrs.rgAttr[i].rgValue->pbData;
|
||||
c7Data.cbData = pSignerInfo->UnauthAttrs.rgAttr[i].rgValue->cbData;
|
||||
|
||||
auto hStore2 = pfnCertOpenStore(CERT_STORE_PROV_PKCS7, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, NULL, 0, &c7Data);
|
||||
if (!hStore2)
|
||||
{
|
||||
LocalFree(pSignerInfo2);
|
||||
return false;
|
||||
}
|
||||
|
||||
CERT_INFO CertInfo{};
|
||||
PCCERT_CONTEXT pCertContext = NULL;
|
||||
|
||||
// Search for the signer certificate in the temporary certificate store.
|
||||
CertInfo.Issuer = pSignerInfo2->Issuer;
|
||||
CertInfo.SerialNumber = pSignerInfo2->SerialNumber;
|
||||
pCertContext = pfnCertFindCertificateInStore(hStore2,
|
||||
(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING),
|
||||
0,
|
||||
CERT_FIND_SUBJECT_CERT,
|
||||
(PVOID)&CertInfo,
|
||||
NULL);
|
||||
if (!pCertContext)
|
||||
{
|
||||
LocalFree(pSignerInfo2);
|
||||
pfnCertCloseStore(hStore2, CERT_CLOSE_STORE_FORCE_FLAG);
|
||||
return false;
|
||||
}
|
||||
|
||||
void* decodedPublicKey{};
|
||||
DWORD decodedPublicLength{};
|
||||
if (pfnCryptDecodeObjectEx((PKCS_7_ASN_ENCODING | X509_ASN_ENCODING),
|
||||
CNG_RSA_PUBLIC_KEY_BLOB,
|
||||
pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
|
||||
pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
|
||||
CRYPT_ENCODE_ALLOC_FLAG,
|
||||
NULL,
|
||||
&decodedPublicKey,
|
||||
&decodedPublicLength))
|
||||
{
|
||||
static uint8_t s_rsaStreamlinePublicKey[] =
|
||||
{
|
||||
0x52, 0x53, 0x41, 0x31, 0x00, 0x0c, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc1, 0x8e, 0x40, 0xc3, 0xf5,
|
||||
0xa7, 0x01, 0x9a, 0x37, 0x6b, 0x47, 0xa8, 0x58, 0xe8, 0xbe, 0xe3, 0x55, 0x0a, 0xee, 0x0f, 0x0d,
|
||||
0x32, 0xaa, 0x12, 0xf9, 0x56, 0x7f, 0x5d, 0xfd, 0x82, 0x09, 0x33, 0x21, 0x42, 0xf2, 0xe8, 0x74,
|
||||
0x98, 0x51, 0xb3, 0x88, 0x74, 0xcd, 0x00, 0x6e, 0xb1, 0x08, 0x10, 0x4b, 0xf1, 0xda, 0xd6, 0x97,
|
||||
0x87, 0xd4, 0x9c, 0xb1, 0x13, 0xa8, 0xa2, 0x86, 0x15, 0x0e, 0xc1, 0xa5, 0x9c, 0xe5, 0x90, 0x9b,
|
||||
0xbe, 0x69, 0xdc, 0x6a, 0x82, 0xbe, 0xb4, 0x4b, 0x4b, 0xfa, 0x95, 0x8e, 0xc1, 0xfc, 0x2b, 0x61,
|
||||
0x95, 0xd1, 0x91, 0xed, 0xeb, 0x87, 0xe7, 0x09, 0x84, 0x05, 0x41, 0x03, 0xb0, 0x2d, 0xd4, 0x39,
|
||||
0x7f, 0x62, 0x06, 0x56, 0x33, 0x93, 0x7e, 0x77, 0x54, 0x06, 0x77, 0x2b, 0x75, 0x05, 0xbc, 0xeb,
|
||||
0x98, 0xea, 0xc0, 0xa2, 0xca, 0x98, 0x86, 0x0f, 0x10, 0x65, 0xde, 0x19, 0x2c, 0xa6, 0x1e, 0x93,
|
||||
0xb0, 0x92, 0x5d, 0x5f, 0x5b, 0x6f, 0x79, 0x6d, 0x2c, 0x76, 0xa6, 0x67, 0x50, 0xaa, 0x8f, 0xc2,
|
||||
0x4c, 0xf1, 0x08, 0xf7, 0xc0, 0x27, 0x29, 0xf0, 0x68, 0xf4, 0x64, 0x00, 0x1c, 0xb6, 0x28, 0x1e,
|
||||
0x25, 0xb8, 0xf3, 0x8a, 0xd1, 0x6e, 0x65, 0xa3, 0x61, 0x9d, 0xf8, 0xca, 0x4a, 0x41, 0x60, 0x80,
|
||||
0x62, 0xdf, 0x41, 0xa4, 0x8b, 0xdc, 0x97, 0xee, 0xeb, 0x64, 0x6f, 0xe4, 0x8f, 0x4b, 0xdf, 0x24,
|
||||
0x01, 0x80, 0xd9, 0xb4, 0x0a, 0xec, 0x0d, 0x3e, 0xb7, 0x76, 0xba, 0xe9, 0xe7, 0xde, 0x07, 0xdd,
|
||||
0x30, 0xc8, 0x4a, 0x14, 0x79, 0xec, 0x15, 0xed, 0x5c, 0xc6, 0xcc, 0xd4, 0xe6, 0x06, 0x3c, 0x42,
|
||||
0x92, 0x10, 0xf7, 0x7c, 0x80, 0x1e, 0x78, 0xd3, 0xb4, 0x9f, 0xc2, 0x3b, 0xa8, 0x7b, 0xa0, 0xe3,
|
||||
0x0c, 0xd9, 0xad, 0x2e, 0x09, 0x72, 0xe2, 0x8f, 0x54, 0x28, 0x87, 0x3c, 0xba, 0x7c, 0x97, 0x80,
|
||||
0xdc, 0x09, 0xb5, 0x12, 0x34, 0x78, 0x9a, 0x26, 0xd0, 0xa3, 0xa7, 0xa7, 0x1b, 0x25, 0x19, 0xe5,
|
||||
0x6e, 0xbe, 0xd7, 0x5a, 0x91, 0x32, 0xc4, 0xa9, 0x2f, 0xcc, 0xd5, 0x82, 0x4b, 0x5b, 0x9f, 0xad,
|
||||
0xf3, 0x2f, 0xed, 0x4f, 0x33, 0xe1, 0x50, 0x33, 0xd6, 0x90, 0x79, 0x22, 0xe5, 0x1c, 0xc7, 0x35,
|
||||
0xe7, 0x58, 0xe6, 0xb4, 0x8b, 0xc4, 0x28, 0x20, 0xec, 0xca, 0x70, 0xbb, 0x02, 0x1b, 0x48, 0xd8,
|
||||
0x84, 0x51, 0x24, 0x33, 0x2a, 0x08, 0xb1, 0x15, 0x4e, 0xbc, 0x88, 0xa5, 0xe1, 0x37, 0x76, 0x70,
|
||||
0xe6, 0xdf, 0x3f, 0x73, 0xfd, 0x0d, 0x8a, 0xd9, 0x0d, 0xa5, 0x35, 0xb2, 0xb4, 0x01, 0x42, 0x96,
|
||||
0xc4, 0xaa, 0x1c, 0xeb, 0x68, 0x62, 0x36, 0xbf, 0xef, 0x5e, 0x2a, 0x3d, 0x18, 0x91, 0x8b, 0x92,
|
||||
0x0a, 0x1e, 0xce, 0x98, 0x5b, 0x7b, 0x64, 0x42, 0x09, 0xb0, 0x1d
|
||||
};
|
||||
|
||||
valid = decodedPublicLength == sizeof(s_rsaStreamlinePublicKey) && memcmp(s_rsaStreamlinePublicKey, decodedPublicKey, decodedPublicLength) == 0;
|
||||
LocalFree(decodedPublicKey);
|
||||
}
|
||||
|
||||
pfnCertFreeCertificateContext(pCertContext);
|
||||
pfnCertCloseStore(hStore2, CERT_CLOSE_STORE_FORCE_FLAG);
|
||||
}
|
||||
LocalFree(pSignerInfo2);
|
||||
}
|
||||
}
|
||||
}
|
||||
pfnCryptMsgClose(hMsg2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LocalFree(pSignerInfo);
|
||||
pfnCryptMsgClose(hMsg);
|
||||
pfnCertCloseStore(hStore, CERT_CLOSE_STORE_FORCE_FLAG);
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
//! See https://docs.microsoft.com/en-us/windows/win32/seccrypto/example-c-program--verifying-the-signature-of-a-pe-file
|
||||
//!
|
||||
//! IMPORTANT: Always pass in the FULL PATH to the file, relative paths are NOT allowed!
|
||||
bool verifyEmbeddedSignature(const wchar_t* pathToFile)
|
||||
{
|
||||
bool valid = true;
|
||||
|
||||
LONG lStatus = {};
|
||||
|
||||
// Initialize the WINTRUST_FILE_INFO structure.
|
||||
|
||||
WINTRUST_FILE_INFO FileData;
|
||||
memset(&FileData, 0, sizeof(FileData));
|
||||
FileData.cbStruct = sizeof(WINTRUST_FILE_INFO);
|
||||
FileData.pcwszFilePath = pathToFile;
|
||||
FileData.hFile = NULL;
|
||||
FileData.pgKnownSubject = NULL;
|
||||
|
||||
if (!pfnWinVerifyTrust)
|
||||
{
|
||||
// We only support Win10+ so we can search for module in system32 directly
|
||||
auto hModWintrust = LoadLibraryExW(L"wintrust.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||
if (!hModWintrust || !GetProc(hModWintrust, "WinVerifyTrust", pfnWinVerifyTrust))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
WVTPolicyGUID specifies the policy to apply on the file
|
||||
WINTRUST_ACTION_GENERIC_VERIFY_V2 policy checks:
|
||||
|
||||
1) The certificate used to sign the file chains up to a root
|
||||
certificate located in the trusted root certificate store. This
|
||||
implies that the identity of the publisher has been verified by
|
||||
a certification authority.
|
||||
|
||||
2) In cases where user interface is displayed (which this example
|
||||
does not do), WinVerifyTrust will check for whether the
|
||||
end entity certificate is stored in the trusted publisher store,
|
||||
implying that the user trusts content from this publisher.
|
||||
|
||||
3) The end entity certificate has sufficient permission to sign
|
||||
code, as indicated by the presence of a code signing EKU or no
|
||||
EKU.
|
||||
*/
|
||||
|
||||
GUID WVTPolicyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2;
|
||||
WINTRUST_DATA WinTrustData;
|
||||
|
||||
// Initialize the WinVerifyTrust input data structure.
|
||||
|
||||
// Default all fields to 0.
|
||||
memset(&WinTrustData, 0, sizeof(WinTrustData));
|
||||
|
||||
WinTrustData.cbStruct = sizeof(WinTrustData);
|
||||
// Use default code signing EKU.
|
||||
WinTrustData.pPolicyCallbackData = NULL;
|
||||
// No data to pass to SIP.
|
||||
WinTrustData.pSIPClientData = NULL;
|
||||
// Disable WVT UI.
|
||||
WinTrustData.dwUIChoice = WTD_UI_NONE;
|
||||
// No revocation checking.
|
||||
WinTrustData.fdwRevocationChecks = WTD_REVOKE_NONE;
|
||||
// Verify an embedded signature on a file.
|
||||
WinTrustData.dwUnionChoice = WTD_CHOICE_FILE;
|
||||
// Verify action.
|
||||
WinTrustData.dwStateAction = WTD_STATEACTION_VERIFY;
|
||||
// Verification sets this value.
|
||||
WinTrustData.hWVTStateData = NULL;
|
||||
// Not used.
|
||||
WinTrustData.pwszURLReference = NULL;
|
||||
// This is not applicable if there is no UI because it changes
|
||||
// the UI to accommodate running applications instead of
|
||||
// installing applications.
|
||||
WinTrustData.dwUIContext = 0;
|
||||
// Set pFile.
|
||||
WinTrustData.pFile = &FileData;
|
||||
|
||||
// First verify the primary signature (index 0) to determine how many secondary signatures
|
||||
// are present. We use WSS_VERIFY_SPECIFIC and dwIndex to do this, also setting
|
||||
// WSS_GET_SECONDARY_SIG_COUNT to have the number of secondary signatures returned.
|
||||
WINTRUST_SIGNATURE_SETTINGS SignatureSettings = {};
|
||||
CERT_STRONG_SIGN_PARA StrongSigPolicy = {};
|
||||
SignatureSettings.cbStruct = sizeof(WINTRUST_SIGNATURE_SETTINGS);
|
||||
SignatureSettings.dwFlags = WSS_GET_SECONDARY_SIG_COUNT | WSS_VERIFY_SPECIFIC;
|
||||
SignatureSettings.dwIndex = 0;
|
||||
WinTrustData.pSignatureSettings = &SignatureSettings;
|
||||
|
||||
StrongSigPolicy.cbSize = sizeof(CERT_STRONG_SIGN_PARA);
|
||||
StrongSigPolicy.dwInfoChoice = CERT_STRONG_SIGN_OID_INFO_CHOICE;
|
||||
StrongSigPolicy.pszOID = (LPSTR)szOID_CERT_STRONG_SIGN_OS_CURRENT;
|
||||
WinTrustData.pSignatureSettings->pCryptoPolicy = &StrongSigPolicy;
|
||||
|
||||
// WinVerifyTrust verifies signatures as specified by the GUID and Wintrust_Data.
|
||||
lStatus = pfnWinVerifyTrust(NULL, &WVTPolicyGUID, &WinTrustData);
|
||||
|
||||
// First signature must be validated by the OS
|
||||
valid = lStatus == ERROR_SUCCESS;
|
||||
if (!valid)
|
||||
{
|
||||
printf("File '%S' is NOT correctly signed - Streamline will not load unsecured modules\n", pathToFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Now there has to be a secondary one
|
||||
valid &= WinTrustData.pSignatureSettings->cSecondarySigs == 1;
|
||||
if (!valid)
|
||||
{
|
||||
printf("File '%S' does not have the secondary NVIDIA signature - Streamline will not load unsecured modules\n", pathToFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The secondary signature must be from NVIDIA
|
||||
valid &= isSignedByNVIDIA(pathToFile);
|
||||
if (valid)
|
||||
{
|
||||
printf("File '%S' is signed by NVIDIA and the signature was verified.\n", pathToFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("File '%S' is NOT correctly signed - Streamline will not load unsecured modules\n", pathToFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Any hWVTStateData must be released by a call with close.
|
||||
WinTrustData.dwStateAction = WTD_STATEACTION_CLOSE;
|
||||
lStatus = pfnWinVerifyTrust(NULL, &WVTPolicyGUID, &WinTrustData);
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace sl
|
||||
{
|
||||
|
||||
//! GUID
|
||||
struct StructType
|
||||
{
|
||||
uint32_t data1;
|
||||
uint16_t data2;
|
||||
uint16_t data3;
|
||||
uint8_t data4[8];
|
||||
|
||||
inline bool operator==(const StructType& rhs) const { return memcmp(this, &rhs, sizeof(*this)) == 0; }
|
||||
inline bool operator!=(const StructType& rhs) const { return memcmp(this, &rhs, sizeof(*this)) != 0; }
|
||||
};
|
||||
|
||||
//! SL is using typed and versioned structures which can be chained or not.
|
||||
//!
|
||||
//! --- OPTION 1 ---
|
||||
//!
|
||||
//! New members must be added at the end and version needs to be increased:
|
||||
//!
|
||||
//! SL_STRUCT_BEGIN(S1, GUID1, kStructVersion1)
|
||||
//! A
|
||||
//! B
|
||||
//! C
|
||||
//! SL_STRUCT_END()
|
||||
//!
|
||||
//! SL_STRUCT_BEGIN(S1, GUID1, kStructVersion2) // Note that version is bumped
|
||||
//! // V1
|
||||
//! A
|
||||
//! B
|
||||
//! C
|
||||
//!
|
||||
//! //! V2 - new members always go at the end!
|
||||
//! D
|
||||
//! E
|
||||
//! SL_STRUCT_END()
|
||||
//!
|
||||
//! Here is one example on how to check for version and handle backwards compatibility:
|
||||
//!
|
||||
//! void func(const S1* input)
|
||||
//! {
|
||||
//! // Access A, B, C as needed
|
||||
//! ...
|
||||
//! if (input->structVersion >= kStructVersion2)
|
||||
//! {
|
||||
//! // Safe to access D, E
|
||||
//! }
|
||||
//! }
|
||||
|
||||
|
||||
//! --- OPTION 2 ---
|
||||
//!
|
||||
//! New members are optional and added to a new struct which is then chained as needed:
|
||||
//!
|
||||
//! SL_STRUCT_BEGIN(S1, GUID1, kStructVersion1)
|
||||
//! A
|
||||
//! B
|
||||
//! C
|
||||
//! SL_STRUCT_END()
|
||||
//!
|
||||
//! SL_STRUCT_BEGIN(S2, GUID2, kStructVersion1) // Note that this is a different struct with new GUID
|
||||
//! D
|
||||
//! E
|
||||
//! SL_STRUCT_END()
|
||||
//!
|
||||
//! S1 s1;
|
||||
//! S2 s2
|
||||
//! s1.next = &s2; // optional parameters in S2
|
||||
|
||||
//! IMPORTANT: New members in the structure always go at the end!
|
||||
//!
|
||||
constexpr uint32_t kStructVersion1 = 1;
|
||||
constexpr uint32_t kStructVersion2 = 2;
|
||||
constexpr uint32_t kStructVersion3 = 3;
|
||||
constexpr uint32_t kStructVersion4 = 4;
|
||||
|
||||
struct BaseStructure
|
||||
{
|
||||
BaseStructure() = delete;
|
||||
BaseStructure(StructType t, uint32_t v) : structType(t), structVersion(v) {};
|
||||
BaseStructure* next{};
|
||||
StructType structType{};
|
||||
size_t structVersion;
|
||||
};
|
||||
|
||||
#define SL_STRUCT_BEGIN(name, guid, version) \
|
||||
struct name : public sl::BaseStructure \
|
||||
{ \
|
||||
name() : sl::BaseStructure(guid, version){} \
|
||||
constexpr static sl::StructType s_structType = guid;
|
||||
|
||||
#define SL_STRUCT_END() };
|
||||
|
||||
#define SL_STRUCT_PROTECTED_BEGIN(name, guid, version) \
|
||||
struct name : public sl::BaseStructure \
|
||||
{ \
|
||||
protected: \
|
||||
name() : sl::BaseStructure(guid, version){} \
|
||||
public: \
|
||||
constexpr static sl::StructType s_structType = guid; \
|
||||
|
||||
|
||||
// Deprecated: please use SL_STRUCT_BEGIN/SL_STRUCT_END instead
|
||||
#define SL_STRUCT(name, guid, version) \
|
||||
SL_STRUCT_BEGIN(name, guid, version)
|
||||
|
||||
// Deprecated: please use SL_STRUCT_PROTECTED_BEGIN/SL_STRUCT_END instead
|
||||
#define SL_STRUCT_PROTECTED(name, guid, version) \
|
||||
SL_STRUCT_PROTECTED_BEGIN(name, guid, version)
|
||||
|
||||
} // namespace sl
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace sl
|
||||
{
|
||||
|
||||
//! Each feature must have a unique id, please see sl.h Feature
|
||||
//!
|
||||
constexpr uint32_t kFeatureTemplate = 0xffff;
|
||||
|
||||
//! If your plugin does not have any constants then the code below can be removed
|
||||
//!
|
||||
enum class TemplateMode : uint32_t
|
||||
{
|
||||
eOff,
|
||||
eOn
|
||||
};
|
||||
|
||||
//! IMPORTANT: Each structure must have a unique GUID assigned, change this as needed
|
||||
//!
|
||||
// {29DF7FE0-273A-4D72-B481-2DC823D5B1AD}
|
||||
SL_STRUCT_BEGIN(TemplateConstants, StructType({ 0x29df7fe0, 0x273a, 0x4d72, { 0xb4, 0x81, 0x2d, 0xc8, 0x23, 0xd5, 0xb1, 0xad } }), kStructVersion1)
|
||||
TemplateMode mode = TemplateMode::eOff;
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
//! IMPORTANT: Each structure must have a unique GUID assigned, change this as needed
|
||||
//!
|
||||
// {39DF7FE0-283A-4D72-B481-2DC823D5B1AD}
|
||||
SL_STRUCT_BEGIN(TemplateSettings, StructType({ 0x39df7fe0, 0x283a, 0x4d72, { 0xb4, 0x81, 0x2d, 0xc8, 0x23, 0xd5, 0xb1, 0xad } }), kStructVersion1)
|
||||
|
||||
//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details
|
||||
SL_STRUCT_END()
|
||||
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#define SL_VERSION_MAJOR 2
|
||||
#define SL_VERSION_MINOR 10
|
||||
#define SL_VERSION_PATCH 3
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace sl
|
||||
{
|
||||
constexpr uint64_t kSDKVersionMagic = 0xfedc;
|
||||
constexpr uint64_t kSDKVersion = (uint64_t(SL_VERSION_MAJOR) << 48) | (uint64_t(SL_VERSION_MINOR) << 32) | (uint64_t(SL_VERSION_PATCH) << 16) | kSDKVersionMagic;
|
||||
|
||||
struct Version
|
||||
{
|
||||
Version() : major(0), minor(0), build(0) {};
|
||||
Version(uint32_t v1, uint32_t v2, uint32_t v3) : major(v1), minor(v2), build(v3) {};
|
||||
|
||||
inline operator bool() const { return major != 0 || minor != 0 || build != 0; }
|
||||
|
||||
inline std::string toStr() const
|
||||
{
|
||||
return std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(build);
|
||||
}
|
||||
inline std::wstring toWStr() const
|
||||
{
|
||||
return std::to_wstring(major) + L"." + std::to_wstring(minor) + L"." + std::to_wstring(build);
|
||||
}
|
||||
inline std::wstring toWStrOTAId() const
|
||||
{
|
||||
return std::to_wstring((major << 16) | (minor << 8) | build);
|
||||
}
|
||||
inline bool operator==(const Version& rhs) const
|
||||
{
|
||||
return major == rhs.major && minor == rhs.minor && build == rhs.build;
|
||||
}
|
||||
inline bool operator>(const Version& rhs) const
|
||||
{
|
||||
if (major < rhs.major) return false;
|
||||
else if (major > rhs.major) return true;
|
||||
// major version the same
|
||||
if (minor < rhs.minor) return false;
|
||||
else if (minor > rhs.minor) return true;
|
||||
// minor version the same
|
||||
if (build < rhs.build) return false;
|
||||
else if (build > rhs.build) return true;
|
||||
// build version the same
|
||||
return false;
|
||||
};
|
||||
inline bool operator>=(const Version& rhs) const
|
||||
{
|
||||
return operator>(rhs) || operator==(rhs);
|
||||
};
|
||||
inline bool operator<(const Version& rhs) const
|
||||
{
|
||||
if (major > rhs.major) return false;
|
||||
else if (major < rhs.major) return true;
|
||||
// major version the same
|
||||
if (minor > rhs.minor) return false;
|
||||
else if (minor < rhs.minor) return true;
|
||||
// minor version the same
|
||||
if (build > rhs.build) return false;
|
||||
else if (build < rhs.build) return true;
|
||||
// build version the same
|
||||
return false;
|
||||
};
|
||||
inline bool operator<=(const Version& rhs) const
|
||||
{
|
||||
return operator<(rhs) || operator==(rhs);
|
||||
};
|
||||
|
||||
uint32_t major;
|
||||
uint32_t minor;
|
||||
uint32_t build;
|
||||
};
|
||||
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __dict_list_h_
|
||||
#define __dict_list_h_
|
||||
|
||||
/* Use #define's so that another heap implementation can use this one */
|
||||
|
||||
#define DictKey DictListKey
|
||||
#define Dict DictList
|
||||
#define DictNode DictListNode
|
||||
|
||||
#define dictNewDict(frame,leq) __gl_dictListNewDict(frame,leq)
|
||||
#define dictDeleteDict(dict) __gl_dictListDeleteDict(dict)
|
||||
|
||||
#define dictSearch(dict,key) __gl_dictListSearch(dict,key)
|
||||
#define dictInsert(dict,key) __gl_dictListInsert(dict,key)
|
||||
#define dictInsertBefore(dict,node,key) __gl_dictListInsertBefore(dict,node,key)
|
||||
#define dictDelete(dict,node) __gl_dictListDelete(dict,node)
|
||||
|
||||
#define dictKey(n) __gl_dictListKey(n)
|
||||
#define dictSucc(n) __gl_dictListSucc(n)
|
||||
#define dictPred(n) __gl_dictListPred(n)
|
||||
#define dictMin(d) __gl_dictListMin(d)
|
||||
#define dictMax(d) __gl_dictListMax(d)
|
||||
|
||||
|
||||
|
||||
typedef void *DictKey;
|
||||
typedef struct Dict Dict;
|
||||
typedef struct DictNode DictNode;
|
||||
|
||||
Dict *dictNewDict(
|
||||
void *frame,
|
||||
int (*leq)(void *frame, DictKey key1, DictKey key2) );
|
||||
|
||||
void dictDeleteDict( Dict *dict );
|
||||
|
||||
/* Search returns the node with the smallest key greater than or equal
|
||||
* to the given key. If there is no such key, returns a node whose
|
||||
* key is NULL. Similarly, Succ(Max(d)) has a NULL key, etc.
|
||||
*/
|
||||
DictNode *dictSearch( Dict *dict, DictKey key );
|
||||
DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key );
|
||||
void dictDelete( Dict *dict, DictNode *node );
|
||||
|
||||
#define __gl_dictListKey(n) ((n)->key)
|
||||
#define __gl_dictListSucc(n) ((n)->next)
|
||||
#define __gl_dictListPred(n) ((n)->prev)
|
||||
#define __gl_dictListMin(d) ((d)->head.next)
|
||||
#define __gl_dictListMax(d) ((d)->head.prev)
|
||||
#define __gl_dictListInsert(d,k) (dictInsertBefore((d),&(d)->head,(k)))
|
||||
|
||||
|
||||
/*** Private data structures ***/
|
||||
|
||||
struct DictNode {
|
||||
DictKey key;
|
||||
DictNode *next;
|
||||
DictNode *prev;
|
||||
};
|
||||
|
||||
struct Dict {
|
||||
DictNode head;
|
||||
void *frame;
|
||||
int (*leq)(void *frame, DictKey key1, DictKey key2);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include "dict-list.h"
|
||||
#include "memalloc.h"
|
||||
|
||||
/* really __gl_dictListNewDict */
|
||||
Dict *dictNewDict( void *frame,
|
||||
int (*leq)(void *frame, DictKey key1, DictKey key2) )
|
||||
{
|
||||
Dict *dict = (Dict *) memAlloc( sizeof( Dict ));
|
||||
DictNode *head;
|
||||
|
||||
if (dict == NULL) return NULL;
|
||||
|
||||
head = &dict->head;
|
||||
|
||||
head->key = NULL;
|
||||
head->next = head;
|
||||
head->prev = head;
|
||||
|
||||
dict->frame = frame;
|
||||
dict->leq = leq;
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
/* really __gl_dictListDeleteDict */
|
||||
void dictDeleteDict( Dict *dict )
|
||||
{
|
||||
DictNode *node, *next;
|
||||
|
||||
for( node = dict->head.next; node != &dict->head; node = next ) {
|
||||
next = node->next;
|
||||
memFree( node );
|
||||
}
|
||||
memFree( dict );
|
||||
}
|
||||
|
||||
/* really __gl_dictListInsertBefore */
|
||||
DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key )
|
||||
{
|
||||
DictNode *newNode;
|
||||
|
||||
do {
|
||||
node = node->prev;
|
||||
} while( node->key != NULL && ! (*dict->leq)(dict->frame, node->key, key));
|
||||
|
||||
newNode = (DictNode *) memAlloc( sizeof( DictNode ));
|
||||
if (newNode == NULL) return NULL;
|
||||
|
||||
newNode->key = key;
|
||||
newNode->next = node->next;
|
||||
node->next->prev = newNode;
|
||||
newNode->prev = node;
|
||||
node->next = newNode;
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
||||
/* really __gl_dictListDelete */
|
||||
void dictDelete( Dict *dict, DictNode *node ) /*ARGSUSED*/
|
||||
{
|
||||
node->next->prev = node->prev;
|
||||
node->prev->next = node->next;
|
||||
memFree( node );
|
||||
}
|
||||
|
||||
/* really __gl_dictListSearch */
|
||||
DictNode *dictSearch( Dict *dict, DictKey key )
|
||||
{
|
||||
DictNode *node = &dict->head;
|
||||
|
||||
do {
|
||||
node = node->next;
|
||||
} while( node->key != NULL && ! (*dict->leq)(dict->frame, key, node->key));
|
||||
|
||||
return node;
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __dict_list_h_
|
||||
#define __dict_list_h_
|
||||
|
||||
/* Use #define's so that another heap implementation can use this one */
|
||||
|
||||
#define DictKey DictListKey
|
||||
#define Dict DictList
|
||||
#define DictNode DictListNode
|
||||
|
||||
#define dictNewDict(frame,leq) __gl_dictListNewDict(frame,leq)
|
||||
#define dictDeleteDict(dict) __gl_dictListDeleteDict(dict)
|
||||
|
||||
#define dictSearch(dict,key) __gl_dictListSearch(dict,key)
|
||||
#define dictInsert(dict,key) __gl_dictListInsert(dict,key)
|
||||
#define dictInsertBefore(dict,node,key) __gl_dictListInsertBefore(dict,node,key)
|
||||
#define dictDelete(dict,node) __gl_dictListDelete(dict,node)
|
||||
|
||||
#define dictKey(n) __gl_dictListKey(n)
|
||||
#define dictSucc(n) __gl_dictListSucc(n)
|
||||
#define dictPred(n) __gl_dictListPred(n)
|
||||
#define dictMin(d) __gl_dictListMin(d)
|
||||
#define dictMax(d) __gl_dictListMax(d)
|
||||
|
||||
|
||||
|
||||
typedef void *DictKey;
|
||||
typedef struct Dict Dict;
|
||||
typedef struct DictNode DictNode;
|
||||
|
||||
Dict *dictNewDict(
|
||||
void *frame,
|
||||
int (*leq)(void *frame, DictKey key1, DictKey key2) );
|
||||
|
||||
void dictDeleteDict( Dict *dict );
|
||||
|
||||
/* Search returns the node with the smallest key greater than or equal
|
||||
* to the given key. If there is no such key, returns a node whose
|
||||
* key is NULL. Similarly, Succ(Max(d)) has a NULL key, etc.
|
||||
*/
|
||||
DictNode *dictSearch( Dict *dict, DictKey key );
|
||||
DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key );
|
||||
void dictDelete( Dict *dict, DictNode *node );
|
||||
|
||||
#define __gl_dictListKey(n) ((n)->key)
|
||||
#define __gl_dictListSucc(n) ((n)->next)
|
||||
#define __gl_dictListPred(n) ((n)->prev)
|
||||
#define __gl_dictListMin(d) ((d)->head.next)
|
||||
#define __gl_dictListMax(d) ((d)->head.prev)
|
||||
#define __gl_dictListInsert(d,k) (dictInsertBefore((d),&(d)->head,(k)))
|
||||
|
||||
|
||||
/*** Private data structures ***/
|
||||
|
||||
struct DictNode {
|
||||
DictKey key;
|
||||
DictNode *next;
|
||||
DictNode *prev;
|
||||
};
|
||||
|
||||
struct Dict {
|
||||
DictNode head;
|
||||
void *frame;
|
||||
int (*leq)(void *frame, DictKey key1, DictKey key2);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gluos.h"
|
||||
#include <assert.h>
|
||||
#include "mesh.h"
|
||||
#include "geom.h"
|
||||
|
||||
int __gl_vertLeq( GLUvertex *u, GLUvertex *v )
|
||||
{
|
||||
/* Returns TRUE if u is lexicographically <= v. */
|
||||
|
||||
return VertLeq( u, v );
|
||||
}
|
||||
|
||||
GLdouble __gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w )
|
||||
{
|
||||
/* Given three vertices u,v,w such that VertLeq(u,v) && VertLeq(v,w),
|
||||
* evaluates the t-coord of the edge uw at the s-coord of the vertex v.
|
||||
* Returns v->t - (uw)(v->s), ie. the signed distance from uw to v.
|
||||
* If uw is vertical (and thus passes thru v), the result is zero.
|
||||
*
|
||||
* The calculation is extremely accurate and stable, even when v
|
||||
* is very close to u or w. In particular if we set v->t = 0 and
|
||||
* let r be the negated result (this evaluates (uw)(v->s)), then
|
||||
* r is guaranteed to satisfy MIN(u->t,w->t) <= r <= MAX(u->t,w->t).
|
||||
*/
|
||||
GLdouble gapL, gapR;
|
||||
|
||||
assert( VertLeq( u, v ) && VertLeq( v, w ));
|
||||
|
||||
gapL = v->s - u->s;
|
||||
gapR = w->s - v->s;
|
||||
|
||||
if( gapL + gapR > 0 ) {
|
||||
if( gapL < gapR ) {
|
||||
return (v->t - u->t) + (u->t - w->t) * (gapL / (gapL + gapR));
|
||||
} else {
|
||||
return (v->t - w->t) + (w->t - u->t) * (gapR / (gapL + gapR));
|
||||
}
|
||||
}
|
||||
/* vertical line */
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLdouble __gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w )
|
||||
{
|
||||
/* Returns a number whose sign matches EdgeEval(u,v,w) but which
|
||||
* is cheaper to evaluate. Returns > 0, == 0 , or < 0
|
||||
* as v is above, on, or below the edge uw.
|
||||
*/
|
||||
GLdouble gapL, gapR;
|
||||
|
||||
assert( VertLeq( u, v ) && VertLeq( v, w ));
|
||||
|
||||
gapL = v->s - u->s;
|
||||
gapR = w->s - v->s;
|
||||
|
||||
if( gapL + gapR > 0 ) {
|
||||
return (v->t - w->t) * gapL + (v->t - u->t) * gapR;
|
||||
}
|
||||
/* vertical line */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* Define versions of EdgeSign, EdgeEval with s and t transposed.
|
||||
*/
|
||||
|
||||
GLdouble __gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w )
|
||||
{
|
||||
/* Given three vertices u,v,w such that TransLeq(u,v) && TransLeq(v,w),
|
||||
* evaluates the t-coord of the edge uw at the s-coord of the vertex v.
|
||||
* Returns v->s - (uw)(v->t), ie. the signed distance from uw to v.
|
||||
* If uw is vertical (and thus passes thru v), the result is zero.
|
||||
*
|
||||
* The calculation is extremely accurate and stable, even when v
|
||||
* is very close to u or w. In particular if we set v->s = 0 and
|
||||
* let r be the negated result (this evaluates (uw)(v->t)), then
|
||||
* r is guaranteed to satisfy MIN(u->s,w->s) <= r <= MAX(u->s,w->s).
|
||||
*/
|
||||
GLdouble gapL, gapR;
|
||||
|
||||
assert( TransLeq( u, v ) && TransLeq( v, w ));
|
||||
|
||||
gapL = v->t - u->t;
|
||||
gapR = w->t - v->t;
|
||||
|
||||
if( gapL + gapR > 0 ) {
|
||||
if( gapL < gapR ) {
|
||||
return (v->s - u->s) + (u->s - w->s) * (gapL / (gapL + gapR));
|
||||
} else {
|
||||
return (v->s - w->s) + (w->s - u->s) * (gapR / (gapL + gapR));
|
||||
}
|
||||
}
|
||||
/* vertical line */
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLdouble __gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w )
|
||||
{
|
||||
/* Returns a number whose sign matches TransEval(u,v,w) but which
|
||||
* is cheaper to evaluate. Returns > 0, == 0 , or < 0
|
||||
* as v is above, on, or below the edge uw.
|
||||
*/
|
||||
GLdouble gapL, gapR;
|
||||
|
||||
assert( TransLeq( u, v ) && TransLeq( v, w ));
|
||||
|
||||
gapL = v->t - u->t;
|
||||
gapR = w->t - v->t;
|
||||
|
||||
if( gapL + gapR > 0 ) {
|
||||
return (v->s - w->s) * gapL + (v->s - u->s) * gapR;
|
||||
}
|
||||
/* vertical line */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int __gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w )
|
||||
{
|
||||
/* For almost-degenerate situations, the results are not reliable.
|
||||
* Unless the floating-point arithmetic can be performed without
|
||||
* rounding errors, *any* implementation will give incorrect results
|
||||
* on some degenerate inputs, so the client must have some way to
|
||||
* handle this situation.
|
||||
*/
|
||||
return (u->s*(v->t - w->t) + v->s*(w->t - u->t) + w->s*(u->t - v->t)) >= 0;
|
||||
}
|
||||
|
||||
/* Given parameters a,x,b,y returns the value (b*x+a*y)/(a+b),
|
||||
* or (x+y)/2 if a==b==0. It requires that a,b >= 0, and enforces
|
||||
* this in the rare case that one argument is slightly negative.
|
||||
* The implementation is extremely stable numerically.
|
||||
* In particular it guarantees that the result r satisfies
|
||||
* MIN(x,y) <= r <= MAX(x,y), and the results are very accurate
|
||||
* even when a and b differ greatly in magnitude.
|
||||
*/
|
||||
#define RealInterpolate(a,x,b,y) \
|
||||
(a = (a < 0) ? 0 : a, b = (b < 0) ? 0 : b, \
|
||||
((a <= b) ? ((b == 0) ? ((x+y) / 2) \
|
||||
: (x + (y-x) * (a/(a+b)))) \
|
||||
: (y + (x-y) * (b/(a+b)))))
|
||||
|
||||
#ifndef FOR_TRITE_TEST_PROGRAM
|
||||
#define Interpolate(a,x,b,y) RealInterpolate(a,x,b,y)
|
||||
#else
|
||||
|
||||
/* Claim: the ONLY property the sweep algorithm relies on is that
|
||||
* MIN(x,y) <= r <= MAX(x,y). This is a nasty way to test that.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
extern int RandomInterpolate;
|
||||
|
||||
GLdouble Interpolate( GLdouble a, GLdouble x, GLdouble b, GLdouble y)
|
||||
{
|
||||
printf("*********************%d\n",RandomInterpolate);
|
||||
if( RandomInterpolate ) {
|
||||
a = 1.2 * drand48() - 0.1;
|
||||
a = (a < 0) ? 0 : ((a > 1) ? 1 : a);
|
||||
b = 1.0 - a;
|
||||
}
|
||||
return RealInterpolate(a,x,b,y);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define Swap(a,b) do { GLUvertex *t = a; a = b; b = t; } while (0)
|
||||
|
||||
void __gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1,
|
||||
GLUvertex *o2, GLUvertex *d2,
|
||||
GLUvertex *v )
|
||||
/* Given edges (o1,d1) and (o2,d2), compute their point of intersection.
|
||||
* The computed point is guaranteed to lie in the intersection of the
|
||||
* bounding rectangles defined by each edge.
|
||||
*/
|
||||
{
|
||||
GLdouble z1, z2;
|
||||
|
||||
/* This is certainly not the most efficient way to find the intersection
|
||||
* of two line segments, but it is very numerically stable.
|
||||
*
|
||||
* Strategy: find the two middle vertices in the VertLeq ordering,
|
||||
* and interpolate the intersection s-value from these. Then repeat
|
||||
* using the TransLeq ordering to find the intersection t-value.
|
||||
*/
|
||||
|
||||
if( ! VertLeq( o1, d1 )) { Swap( o1, d1 ); }
|
||||
if( ! VertLeq( o2, d2 )) { Swap( o2, d2 ); }
|
||||
if( ! VertLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); }
|
||||
|
||||
if( ! VertLeq( o2, d1 )) {
|
||||
/* Technically, no intersection -- do our best */
|
||||
v->s = (o2->s + d1->s) / 2;
|
||||
} else if( VertLeq( d1, d2 )) {
|
||||
/* Interpolate between o2 and d1 */
|
||||
z1 = EdgeEval( o1, o2, d1 );
|
||||
z2 = EdgeEval( o2, d1, d2 );
|
||||
if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
|
||||
v->s = Interpolate( z1, o2->s, z2, d1->s );
|
||||
} else {
|
||||
/* Interpolate between o2 and d2 */
|
||||
z1 = EdgeSign( o1, o2, d1 );
|
||||
z2 = -EdgeSign( o1, d2, d1 );
|
||||
if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
|
||||
v->s = Interpolate( z1, o2->s, z2, d2->s );
|
||||
}
|
||||
|
||||
/* Now repeat the process for t */
|
||||
|
||||
if( ! TransLeq( o1, d1 )) { Swap( o1, d1 ); }
|
||||
if( ! TransLeq( o2, d2 )) { Swap( o2, d2 ); }
|
||||
if( ! TransLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); }
|
||||
|
||||
if( ! TransLeq( o2, d1 )) {
|
||||
/* Technically, no intersection -- do our best */
|
||||
v->t = (o2->t + d1->t) / 2;
|
||||
} else if( TransLeq( d1, d2 )) {
|
||||
/* Interpolate between o2 and d1 */
|
||||
z1 = TransEval( o1, o2, d1 );
|
||||
z2 = TransEval( o2, d1, d2 );
|
||||
if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
|
||||
v->t = Interpolate( z1, o2->t, z2, d1->t );
|
||||
} else {
|
||||
/* Interpolate between o2 and d2 */
|
||||
z1 = TransSign( o1, o2, d1 );
|
||||
z2 = -TransSign( o1, d2, d1 );
|
||||
if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
|
||||
v->t = Interpolate( z1, o2->t, z2, d2->t );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __geom_h_
|
||||
#define __geom_h_
|
||||
|
||||
#include "mesh.h"
|
||||
|
||||
#ifdef NO_BRANCH_CONDITIONS
|
||||
/* MIPS architecture has special instructions to evaluate boolean
|
||||
* conditions -- more efficient than branching, IF you can get the
|
||||
* compiler to generate the right instructions (SGI compiler doesn't)
|
||||
*/
|
||||
#define VertEq(u,v) (((u)->s == (v)->s) & ((u)->t == (v)->t))
|
||||
#define VertLeq(u,v) (((u)->s < (v)->s) | \
|
||||
((u)->s == (v)->s & (u)->t <= (v)->t))
|
||||
#else
|
||||
#define VertEq(u,v) ((u)->s == (v)->s && (u)->t == (v)->t)
|
||||
#define VertLeq(u,v) (((u)->s < (v)->s) || \
|
||||
((u)->s == (v)->s && (u)->t <= (v)->t))
|
||||
#endif
|
||||
|
||||
#define EdgeEval(u,v,w) __gl_edgeEval(u,v,w)
|
||||
#define EdgeSign(u,v,w) __gl_edgeSign(u,v,w)
|
||||
|
||||
/* Versions of VertLeq, EdgeSign, EdgeEval with s and t transposed. */
|
||||
|
||||
#define TransLeq(u,v) (((u)->t < (v)->t) || \
|
||||
((u)->t == (v)->t && (u)->s <= (v)->s))
|
||||
#define TransEval(u,v,w) __gl_transEval(u,v,w)
|
||||
#define TransSign(u,v,w) __gl_transSign(u,v,w)
|
||||
|
||||
|
||||
#define EdgeGoesLeft(e) VertLeq( (e)->Dst, (e)->Org )
|
||||
#define EdgeGoesRight(e) VertLeq( (e)->Org, (e)->Dst )
|
||||
|
||||
#undef ABS
|
||||
#define ABS(x) ((x) < 0 ? -(x) : (x))
|
||||
#define VertL1dist(u,v) (ABS(u->s - v->s) + ABS(u->t - v->t))
|
||||
|
||||
#define VertCCW(u,v,w) __gl_vertCCW(u,v,w)
|
||||
|
||||
int __gl_vertLeq( GLUvertex *u, GLUvertex *v );
|
||||
GLdouble __gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w );
|
||||
GLdouble __gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w );
|
||||
GLdouble __gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w );
|
||||
GLdouble __gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w );
|
||||
int __gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w );
|
||||
void __gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1,
|
||||
GLUvertex *o2, GLUvertex *d2,
|
||||
GLUvertex *v );
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,356 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
|
||||
#ifndef __glu_h__
|
||||
#define __glu_h__
|
||||
|
||||
#define GLAPIENTRYP *
|
||||
#define GLAPIENTRY
|
||||
#define GLAPI
|
||||
|
||||
typedef int GLint;
|
||||
typedef unsigned int GLenum;
|
||||
typedef unsigned int GLsizei;
|
||||
typedef float GLfloat;
|
||||
typedef double GLdouble;
|
||||
typedef unsigned char GLubyte;
|
||||
typedef int GLboolean;
|
||||
typedef void GLvoid;
|
||||
|
||||
#define GL_FALSE 0
|
||||
#define GL_TRUE 1
|
||||
#define GL_LINE_LOOP 0x0002
|
||||
#define GL_LINE_STRIP 0x0003
|
||||
#define GL_TRIANGLES 0x0004
|
||||
#define GL_TRIANGLE_STRIP 0x0005
|
||||
#define GL_TRIANGLE_FAN 0x0006
|
||||
|
||||
// #if (defined(_MSC_VER) || defined(__MINGW32__)) && defined(BUILD_GLU32)
|
||||
// # undef GLAPI
|
||||
// # define GLAPI __declspec(dllexport)
|
||||
// #elif (defined(_MSC_VER) || defined(__MINGW32__)) && defined(_DLL)
|
||||
// /* tag specifying we're building for DLL runtime support */
|
||||
// # undef GLAPI
|
||||
// # define GLAPI __declspec(dllimport)
|
||||
// #elif !defined(GLAPI)
|
||||
// /* for use with static link lib build of Win32 edition only */
|
||||
// # define GLAPI extern
|
||||
// #endif /* _STATIC_MESA support */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*************************************************************/
|
||||
|
||||
/* Extensions */
|
||||
#define GLU_EXT_object_space_tess 1
|
||||
#define GLU_EXT_nurbs_tessellator 1
|
||||
|
||||
/* Boolean */
|
||||
#define GLU_FALSE 0
|
||||
#define GLU_TRUE 1
|
||||
|
||||
/* Version */
|
||||
#define GLU_VERSION_1_1 1
|
||||
#define GLU_VERSION_1_2 1
|
||||
#define GLU_VERSION_1_3 1
|
||||
|
||||
/* StringName */
|
||||
#define GLU_VERSION 100800
|
||||
#define GLU_EXTENSIONS 100801
|
||||
|
||||
/* ErrorCode */
|
||||
#define GLU_INVALID_ENUM 100900
|
||||
#define GLU_INVALID_VALUE 100901
|
||||
#define GLU_OUT_OF_MEMORY 100902
|
||||
#define GLU_INCOMPATIBLE_GL_VERSION 100903
|
||||
#define GLU_INVALID_OPERATION 100904
|
||||
|
||||
/* NurbsDisplay */
|
||||
/* GLU_FILL */
|
||||
#define GLU_OUTLINE_POLYGON 100240
|
||||
#define GLU_OUTLINE_PATCH 100241
|
||||
|
||||
/* NurbsCallback */
|
||||
#define GLU_NURBS_ERROR 100103
|
||||
#define GLU_ERROR 100103
|
||||
#define GLU_NURBS_BEGIN 100164
|
||||
#define GLU_NURBS_BEGIN_EXT 100164
|
||||
#define GLU_NURBS_VERTEX 100165
|
||||
#define GLU_NURBS_VERTEX_EXT 100165
|
||||
#define GLU_NURBS_NORMAL 100166
|
||||
#define GLU_NURBS_NORMAL_EXT 100166
|
||||
#define GLU_NURBS_COLOR 100167
|
||||
#define GLU_NURBS_COLOR_EXT 100167
|
||||
#define GLU_NURBS_TEXTURE_COORD 100168
|
||||
#define GLU_NURBS_TEX_COORD_EXT 100168
|
||||
#define GLU_NURBS_END 100169
|
||||
#define GLU_NURBS_END_EXT 100169
|
||||
#define GLU_NURBS_BEGIN_DATA 100170
|
||||
#define GLU_NURBS_BEGIN_DATA_EXT 100170
|
||||
#define GLU_NURBS_VERTEX_DATA 100171
|
||||
#define GLU_NURBS_VERTEX_DATA_EXT 100171
|
||||
#define GLU_NURBS_NORMAL_DATA 100172
|
||||
#define GLU_NURBS_NORMAL_DATA_EXT 100172
|
||||
#define GLU_NURBS_COLOR_DATA 100173
|
||||
#define GLU_NURBS_COLOR_DATA_EXT 100173
|
||||
#define GLU_NURBS_TEXTURE_COORD_DATA 100174
|
||||
#define GLU_NURBS_TEX_COORD_DATA_EXT 100174
|
||||
#define GLU_NURBS_END_DATA 100175
|
||||
#define GLU_NURBS_END_DATA_EXT 100175
|
||||
|
||||
/* NurbsError */
|
||||
#define GLU_NURBS_ERROR1 100251
|
||||
#define GLU_NURBS_ERROR2 100252
|
||||
#define GLU_NURBS_ERROR3 100253
|
||||
#define GLU_NURBS_ERROR4 100254
|
||||
#define GLU_NURBS_ERROR5 100255
|
||||
#define GLU_NURBS_ERROR6 100256
|
||||
#define GLU_NURBS_ERROR7 100257
|
||||
#define GLU_NURBS_ERROR8 100258
|
||||
#define GLU_NURBS_ERROR9 100259
|
||||
#define GLU_NURBS_ERROR10 100260
|
||||
#define GLU_NURBS_ERROR11 100261
|
||||
#define GLU_NURBS_ERROR12 100262
|
||||
#define GLU_NURBS_ERROR13 100263
|
||||
#define GLU_NURBS_ERROR14 100264
|
||||
#define GLU_NURBS_ERROR15 100265
|
||||
#define GLU_NURBS_ERROR16 100266
|
||||
#define GLU_NURBS_ERROR17 100267
|
||||
#define GLU_NURBS_ERROR18 100268
|
||||
#define GLU_NURBS_ERROR19 100269
|
||||
#define GLU_NURBS_ERROR20 100270
|
||||
#define GLU_NURBS_ERROR21 100271
|
||||
#define GLU_NURBS_ERROR22 100272
|
||||
#define GLU_NURBS_ERROR23 100273
|
||||
#define GLU_NURBS_ERROR24 100274
|
||||
#define GLU_NURBS_ERROR25 100275
|
||||
#define GLU_NURBS_ERROR26 100276
|
||||
#define GLU_NURBS_ERROR27 100277
|
||||
#define GLU_NURBS_ERROR28 100278
|
||||
#define GLU_NURBS_ERROR29 100279
|
||||
#define GLU_NURBS_ERROR30 100280
|
||||
#define GLU_NURBS_ERROR31 100281
|
||||
#define GLU_NURBS_ERROR32 100282
|
||||
#define GLU_NURBS_ERROR33 100283
|
||||
#define GLU_NURBS_ERROR34 100284
|
||||
#define GLU_NURBS_ERROR35 100285
|
||||
#define GLU_NURBS_ERROR36 100286
|
||||
#define GLU_NURBS_ERROR37 100287
|
||||
|
||||
/* NurbsProperty */
|
||||
#define GLU_AUTO_LOAD_MATRIX 100200
|
||||
#define GLU_CULLING 100201
|
||||
#define GLU_SAMPLING_TOLERANCE 100203
|
||||
#define GLU_DISPLAY_MODE 100204
|
||||
#define GLU_PARAMETRIC_TOLERANCE 100202
|
||||
#define GLU_SAMPLING_METHOD 100205
|
||||
#define GLU_U_STEP 100206
|
||||
#define GLU_V_STEP 100207
|
||||
#define GLU_NURBS_MODE 100160
|
||||
#define GLU_NURBS_MODE_EXT 100160
|
||||
#define GLU_NURBS_TESSELLATOR 100161
|
||||
#define GLU_NURBS_TESSELLATOR_EXT 100161
|
||||
#define GLU_NURBS_RENDERER 100162
|
||||
#define GLU_NURBS_RENDERER_EXT 100162
|
||||
|
||||
/* NurbsSampling */
|
||||
#define GLU_OBJECT_PARAMETRIC_ERROR 100208
|
||||
#define GLU_OBJECT_PARAMETRIC_ERROR_EXT 100208
|
||||
#define GLU_OBJECT_PATH_LENGTH 100209
|
||||
#define GLU_OBJECT_PATH_LENGTH_EXT 100209
|
||||
#define GLU_PATH_LENGTH 100215
|
||||
#define GLU_PARAMETRIC_ERROR 100216
|
||||
#define GLU_DOMAIN_DISTANCE 100217
|
||||
|
||||
/* NurbsTrim */
|
||||
#define GLU_MAP1_TRIM_2 100210
|
||||
#define GLU_MAP1_TRIM_3 100211
|
||||
|
||||
/* QuadricDrawStyle */
|
||||
#define GLU_POINT 100010
|
||||
#define GLU_LINE 100011
|
||||
#define GLU_FILL 100012
|
||||
#define GLU_SILHOUETTE 100013
|
||||
|
||||
/* QuadricCallback */
|
||||
/* GLU_ERROR */
|
||||
|
||||
/* QuadricNormal */
|
||||
#define GLU_SMOOTH 100000
|
||||
#define GLU_FLAT 100001
|
||||
#define GLU_NONE 100002
|
||||
|
||||
/* QuadricOrientation */
|
||||
#define GLU_OUTSIDE 100020
|
||||
#define GLU_INSIDE 100021
|
||||
|
||||
/* TessCallback */
|
||||
#define GLU_TESS_BEGIN 100100
|
||||
#define GLU_BEGIN 100100
|
||||
#define GLU_TESS_VERTEX 100101
|
||||
#define GLU_VERTEX 100101
|
||||
#define GLU_TESS_END 100102
|
||||
#define GLU_END 100102
|
||||
#define GLU_TESS_ERROR 100103
|
||||
#define GLU_TESS_EDGE_FLAG 100104
|
||||
#define GLU_EDGE_FLAG 100104
|
||||
#define GLU_TESS_COMBINE 100105
|
||||
#define GLU_TESS_BEGIN_DATA 100106
|
||||
#define GLU_TESS_VERTEX_DATA 100107
|
||||
#define GLU_TESS_END_DATA 100108
|
||||
#define GLU_TESS_ERROR_DATA 100109
|
||||
#define GLU_TESS_EDGE_FLAG_DATA 100110
|
||||
#define GLU_TESS_COMBINE_DATA 100111
|
||||
|
||||
/* TessContour */
|
||||
#define GLU_CW 100120
|
||||
#define GLU_CCW 100121
|
||||
#define GLU_INTERIOR 100122
|
||||
#define GLU_EXTERIOR 100123
|
||||
#define GLU_UNKNOWN 100124
|
||||
|
||||
/* TessProperty */
|
||||
#define GLU_TESS_WINDING_RULE 100140
|
||||
#define GLU_TESS_BOUNDARY_ONLY 100141
|
||||
#define GLU_TESS_TOLERANCE 100142
|
||||
|
||||
/* TessError */
|
||||
#define GLU_TESS_ERROR1 100151
|
||||
#define GLU_TESS_ERROR2 100152
|
||||
#define GLU_TESS_ERROR3 100153
|
||||
#define GLU_TESS_ERROR4 100154
|
||||
#define GLU_TESS_ERROR5 100155
|
||||
#define GLU_TESS_ERROR6 100156
|
||||
#define GLU_TESS_ERROR7 100157
|
||||
#define GLU_TESS_ERROR8 100158
|
||||
#define GLU_TESS_MISSING_BEGIN_POLYGON 100151
|
||||
#define GLU_TESS_MISSING_BEGIN_CONTOUR 100152
|
||||
#define GLU_TESS_MISSING_END_POLYGON 100153
|
||||
#define GLU_TESS_MISSING_END_CONTOUR 100154
|
||||
#define GLU_TESS_COORD_TOO_LARGE 100155
|
||||
#define GLU_TESS_NEED_COMBINE_CALLBACK 100156
|
||||
|
||||
/* TessWinding */
|
||||
#define GLU_TESS_WINDING_ODD 100130
|
||||
#define GLU_TESS_WINDING_NONZERO 100131
|
||||
#define GLU_TESS_WINDING_POSITIVE 100132
|
||||
#define GLU_TESS_WINDING_NEGATIVE 100133
|
||||
#define GLU_TESS_WINDING_ABS_GEQ_TWO 100134
|
||||
|
||||
/*************************************************************/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
class GLUnurbs;
|
||||
class GLUquadric;
|
||||
class GLUtesselator;
|
||||
#else
|
||||
typedef struct GLUnurbs GLUnurbs;
|
||||
typedef struct GLUquadric GLUquadric;
|
||||
typedef struct GLUtesselator GLUtesselator;
|
||||
#endif
|
||||
|
||||
typedef GLUnurbs GLUnurbsObj;
|
||||
typedef GLUquadric GLUquadricObj;
|
||||
typedef GLUtesselator GLUtesselatorObj;
|
||||
typedef GLUtesselator GLUtriangulatorObj;
|
||||
|
||||
#define GLU_TESS_MAX_COORD 1.0e150
|
||||
|
||||
/* Internal convenience typedefs */
|
||||
typedef void (GLAPIENTRYP _GLUfuncptr)(void);
|
||||
|
||||
GLAPI void GLAPIENTRY gluBeginCurve (GLUnurbs* nurb);
|
||||
GLAPI void GLAPIENTRY gluBeginPolygon (GLUtesselator* tess);
|
||||
GLAPI void GLAPIENTRY gluBeginSurface (GLUnurbs* nurb);
|
||||
GLAPI void GLAPIENTRY gluBeginTrim (GLUnurbs* nurb);
|
||||
GLAPI GLint GLAPIENTRY gluBuild1DMipmapLevels (GLenum target, GLint internalFormat, GLsizei width, GLenum format, GLenum type, GLint level, GLint base, GLint max, const void *data);
|
||||
GLAPI GLint GLAPIENTRY gluBuild1DMipmaps (GLenum target, GLint internalFormat, GLsizei width, GLenum format, GLenum type, const void *data);
|
||||
GLAPI GLint GLAPIENTRY gluBuild2DMipmapLevels (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint level, GLint base, GLint max, const void *data);
|
||||
GLAPI GLint GLAPIENTRY gluBuild2DMipmaps (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data);
|
||||
GLAPI GLint GLAPIENTRY gluBuild3DMipmapLevels (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLint level, GLint base, GLint max, const void *data);
|
||||
GLAPI GLint GLAPIENTRY gluBuild3DMipmaps (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
|
||||
GLAPI GLboolean GLAPIENTRY gluCheckExtension (const GLubyte *extName, const GLubyte *extString);
|
||||
GLAPI void GLAPIENTRY gluCylinder (GLUquadric* quad, GLdouble base, GLdouble top, GLdouble height, GLint slices, GLint stacks);
|
||||
GLAPI void GLAPIENTRY gluDeleteNurbsRenderer (GLUnurbs* nurb);
|
||||
GLAPI void GLAPIENTRY gluDeleteQuadric (GLUquadric* quad);
|
||||
GLAPI void GLAPIENTRY gluDeleteTess (GLUtesselator* tess);
|
||||
GLAPI void GLAPIENTRY gluDisk (GLUquadric* quad, GLdouble inner, GLdouble outer, GLint slices, GLint loops);
|
||||
GLAPI void GLAPIENTRY gluEndCurve (GLUnurbs* nurb);
|
||||
GLAPI void GLAPIENTRY gluEndPolygon (GLUtesselator* tess);
|
||||
GLAPI void GLAPIENTRY gluEndSurface (GLUnurbs* nurb);
|
||||
GLAPI void GLAPIENTRY gluEndTrim (GLUnurbs* nurb);
|
||||
GLAPI const GLubyte * GLAPIENTRY gluErrorString (GLenum error);
|
||||
GLAPI void GLAPIENTRY gluGetNurbsProperty (GLUnurbs* nurb, GLenum property, GLfloat* data);
|
||||
GLAPI const GLubyte * GLAPIENTRY gluGetString (GLenum name);
|
||||
GLAPI void GLAPIENTRY gluGetTessProperty (GLUtesselator* tess, GLenum which, GLdouble* data);
|
||||
GLAPI void GLAPIENTRY gluLoadSamplingMatrices (GLUnurbs* nurb, const GLfloat *model, const GLfloat *perspective, const GLint *view);
|
||||
GLAPI void GLAPIENTRY gluLookAt (GLdouble eyeX, GLdouble eyeY, GLdouble eyeZ, GLdouble centerX, GLdouble centerY, GLdouble centerZ, GLdouble upX, GLdouble upY, GLdouble upZ);
|
||||
GLAPI GLUnurbs* GLAPIENTRY gluNewNurbsRenderer (void);
|
||||
GLAPI GLUquadric* GLAPIENTRY gluNewQuadric (void);
|
||||
GLAPI GLUtesselator* GLAPIENTRY gluNewTess (void);
|
||||
GLAPI void GLAPIENTRY gluNextContour (GLUtesselator* tess, GLenum type);
|
||||
GLAPI void GLAPIENTRY gluNurbsCallback (GLUnurbs* nurb, GLenum which, _GLUfuncptr CallBackFunc);
|
||||
GLAPI void GLAPIENTRY gluNurbsCallbackData (GLUnurbs* nurb, GLvoid* userData);
|
||||
GLAPI void GLAPIENTRY gluNurbsCallbackDataEXT (GLUnurbs* nurb, GLvoid* userData);
|
||||
GLAPI void GLAPIENTRY gluNurbsCurve (GLUnurbs* nurb, GLint knotCount, GLfloat *knots, GLint stride, GLfloat *control, GLint order, GLenum type);
|
||||
GLAPI void GLAPIENTRY gluNurbsProperty (GLUnurbs* nurb, GLenum property, GLfloat value);
|
||||
GLAPI void GLAPIENTRY gluNurbsSurface (GLUnurbs* nurb, GLint sKnotCount, GLfloat* sKnots, GLint tKnotCount, GLfloat* tKnots, GLint sStride, GLint tStride, GLfloat* control, GLint sOrder, GLint tOrder, GLenum type);
|
||||
GLAPI void GLAPIENTRY gluOrtho2D (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top);
|
||||
GLAPI void GLAPIENTRY gluPartialDisk (GLUquadric* quad, GLdouble inner, GLdouble outer, GLint slices, GLint loops, GLdouble start, GLdouble sweep);
|
||||
GLAPI void GLAPIENTRY gluPerspective (GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar);
|
||||
GLAPI void GLAPIENTRY gluPickMatrix (GLdouble x, GLdouble y, GLdouble delX, GLdouble delY, GLint *viewport);
|
||||
GLAPI GLint GLAPIENTRY gluProject (GLdouble objX, GLdouble objY, GLdouble objZ, const GLdouble *model, const GLdouble *proj, const GLint *view, GLdouble* winX, GLdouble* winY, GLdouble* winZ);
|
||||
GLAPI void GLAPIENTRY gluPwlCurve (GLUnurbs* nurb, GLint count, GLfloat* data, GLint stride, GLenum type);
|
||||
GLAPI void GLAPIENTRY gluQuadricCallback (GLUquadric* quad, GLenum which, _GLUfuncptr CallBackFunc);
|
||||
GLAPI void GLAPIENTRY gluQuadricDrawStyle (GLUquadric* quad, GLenum draw);
|
||||
GLAPI void GLAPIENTRY gluQuadricNormals (GLUquadric* quad, GLenum normal);
|
||||
GLAPI void GLAPIENTRY gluQuadricOrientation (GLUquadric* quad, GLenum orientation);
|
||||
GLAPI void GLAPIENTRY gluQuadricTexture (GLUquadric* quad, GLboolean texture);
|
||||
GLAPI GLint GLAPIENTRY gluScaleImage (GLenum format, GLsizei wIn, GLsizei hIn, GLenum typeIn, const void *dataIn, GLsizei wOut, GLsizei hOut, GLenum typeOut, GLvoid* dataOut);
|
||||
GLAPI void GLAPIENTRY gluSphere (GLUquadric* quad, GLdouble radius, GLint slices, GLint stacks);
|
||||
GLAPI void GLAPIENTRY gluTessBeginContour (GLUtesselator* tess);
|
||||
GLAPI void GLAPIENTRY gluTessBeginPolygon (GLUtesselator* tess, GLvoid* data);
|
||||
GLAPI void GLAPIENTRY gluTessCallback (GLUtesselator* tess, GLenum which, _GLUfuncptr CallBackFunc);
|
||||
GLAPI void GLAPIENTRY gluTessEndContour (GLUtesselator* tess);
|
||||
GLAPI void GLAPIENTRY gluTessEndPolygon (GLUtesselator* tess);
|
||||
GLAPI void GLAPIENTRY gluTessNormal (GLUtesselator* tess, GLdouble valueX, GLdouble valueY, GLdouble valueZ);
|
||||
GLAPI void GLAPIENTRY gluTessProperty (GLUtesselator* tess, GLenum which, GLdouble data);
|
||||
GLAPI void GLAPIENTRY gluTessVertex (GLUtesselator* tess, GLdouble *location, GLvoid* data);
|
||||
GLAPI GLint GLAPIENTRY gluUnProject (GLdouble winX, GLdouble winY, GLdouble winZ, const GLdouble *model, const GLdouble *proj, const GLint *view, GLdouble* objX, GLdouble* objY, GLdouble* objZ);
|
||||
GLAPI GLint GLAPIENTRY gluUnProject4 (GLdouble winX, GLdouble winY, GLdouble winZ, GLdouble clipW, const GLdouble *model, const GLdouble *proj, const GLint *view, GLdouble nearVal, GLdouble farVal, GLdouble* objX, GLdouble* objY, GLdouble* objZ, GLdouble* objW);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __glu_h__ */
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
** gluos.h - operating system dependencies for GLU
|
||||
**
|
||||
*/
|
||||
#ifdef __VMS
|
||||
#ifdef __cplusplus
|
||||
#pragma message disable nocordel
|
||||
#pragma message disable codeunreachable
|
||||
#pragma message disable codcauunr
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __WATCOMC__
|
||||
/* Disable *lots* of warnings to get a clean build. I can't be bothered fixing the
|
||||
* code at the moment, as it is pretty ugly.
|
||||
*/
|
||||
#pragma warning 7 10
|
||||
#pragma warning 13 10
|
||||
#pragma warning 14 10
|
||||
#pragma warning 367 10
|
||||
#pragma warning 379 10
|
||||
#pragma warning 726 10
|
||||
#pragma warning 836 10
|
||||
#endif
|
||||
|
||||
#ifdef BUILD_FOR_SNAP
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#elif defined(_WIN32)
|
||||
|
||||
#include <stdlib.h> /* For _MAX_PATH definition */
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOGDI
|
||||
#define NOIME
|
||||
#define NOMINMAX
|
||||
|
||||
#ifdef __MINGW64_VERSION_MAJOR
|
||||
#undef _WIN32_WINNT
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32_WINNT
|
||||
/* XXX: Workaround a bug in mingw-w64's headers when NOGDI is set and
|
||||
* _WIN32_WINNT >= 0x0600 */
|
||||
#define _WIN32_WINNT 0x0400
|
||||
#endif
|
||||
#ifndef STRICT
|
||||
#define STRICT 1
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
/* Disable warnings */
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(disable : 4101)
|
||||
#pragma warning(disable : 4244)
|
||||
#pragma warning(disable : 4761)
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1300
|
||||
#pragma comment(linker, "/OPT:NOWIN98")
|
||||
#endif
|
||||
|
||||
#ifndef WINGDIAPI
|
||||
#define WINGDIAPI
|
||||
#endif
|
||||
|
||||
#elif defined(__OS2__)
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#define WINGDIAPI
|
||||
|
||||
#else
|
||||
|
||||
/* Disable Microsoft-specific keywords */
|
||||
#define GLAPIENTRY
|
||||
#define WINGDIAPI
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#include "memalloc.h"
|
||||
#include "string.h"
|
||||
|
||||
int __gl_memInit( size_t maxFast )
|
||||
{
|
||||
#ifndef NO_MALLOPT
|
||||
/* mallopt( M_MXFAST, maxFast );*/
|
||||
#ifdef MEMORY_DEBUG
|
||||
mallopt( M_DEBUG, 1 );
|
||||
#endif
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef MEMORY_DEBUG
|
||||
void *__gl_memAlloc( size_t n )
|
||||
{
|
||||
return memset( malloc( n ), 0xa5, n );
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __memalloc_simple_h_
|
||||
#define __memalloc_simple_h_
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define memRealloc realloc
|
||||
#define memFree free
|
||||
|
||||
#define memInit __gl_memInit
|
||||
/*extern void __gl_memInit( size_t );*/
|
||||
extern int __gl_memInit( size_t );
|
||||
|
||||
#ifndef MEMORY_DEBUG
|
||||
#define memAlloc malloc
|
||||
#else
|
||||
#define memAlloc __gl_memAlloc
|
||||
extern void * __gl_memAlloc( size_t );
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,798 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gluos.h"
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
#include "mesh.h"
|
||||
#include "memalloc.h"
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
static GLUvertex *allocVertex()
|
||||
{
|
||||
return (GLUvertex *)memAlloc( sizeof( GLUvertex ));
|
||||
}
|
||||
|
||||
static GLUface *allocFace()
|
||||
{
|
||||
return (GLUface *)memAlloc( sizeof( GLUface ));
|
||||
}
|
||||
|
||||
/************************ Utility Routines ************************/
|
||||
|
||||
/* Allocate and free half-edges in pairs for efficiency.
|
||||
* The *only* place that should use this fact is allocation/free.
|
||||
*/
|
||||
typedef struct { GLUhalfEdge e, eSym; } EdgePair;
|
||||
|
||||
/* MakeEdge creates a new pair of half-edges which form their own loop.
|
||||
* No vertex or face structures are allocated, but these must be assigned
|
||||
* before the current edge operation is completed.
|
||||
*/
|
||||
static GLUhalfEdge *MakeEdge( GLUhalfEdge *eNext )
|
||||
{
|
||||
GLUhalfEdge *e;
|
||||
GLUhalfEdge *eSym;
|
||||
GLUhalfEdge *ePrev;
|
||||
EdgePair *pair = (EdgePair *)memAlloc( sizeof( EdgePair ));
|
||||
if (pair == NULL) return NULL;
|
||||
|
||||
e = &pair->e;
|
||||
eSym = &pair->eSym;
|
||||
|
||||
/* Make sure eNext points to the first edge of the edge pair */
|
||||
if( eNext->Sym < eNext ) { eNext = eNext->Sym; }
|
||||
|
||||
/* Insert in circular doubly-linked list before eNext.
|
||||
* Note that the prev pointer is stored in Sym->next.
|
||||
*/
|
||||
ePrev = eNext->Sym->next;
|
||||
eSym->next = ePrev;
|
||||
ePrev->Sym->next = e;
|
||||
e->next = eNext;
|
||||
eNext->Sym->next = eSym;
|
||||
|
||||
e->Sym = eSym;
|
||||
e->Onext = e;
|
||||
e->Lnext = eSym;
|
||||
e->Org = NULL;
|
||||
e->Lface = NULL;
|
||||
e->winding = 0;
|
||||
e->activeRegion = NULL;
|
||||
|
||||
eSym->Sym = e;
|
||||
eSym->Onext = eSym;
|
||||
eSym->Lnext = e;
|
||||
eSym->Org = NULL;
|
||||
eSym->Lface = NULL;
|
||||
eSym->winding = 0;
|
||||
eSym->activeRegion = NULL;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
/* Splice( a, b ) is best described by the Guibas/Stolfi paper or the
|
||||
* CS348a notes (see mesh.h). Basically it modifies the mesh so that
|
||||
* a->Onext and b->Onext are exchanged. This can have various effects
|
||||
* depending on whether a and b belong to different face or vertex rings.
|
||||
* For more explanation see __gl_meshSplice() below.
|
||||
*/
|
||||
static void Splice( GLUhalfEdge *a, GLUhalfEdge *b )
|
||||
{
|
||||
GLUhalfEdge *aOnext = a->Onext;
|
||||
GLUhalfEdge *bOnext = b->Onext;
|
||||
|
||||
aOnext->Sym->Lnext = b;
|
||||
bOnext->Sym->Lnext = a;
|
||||
a->Onext = bOnext;
|
||||
b->Onext = aOnext;
|
||||
}
|
||||
|
||||
/* MakeVertex( newVertex, eOrig, vNext ) attaches a new vertex and makes it the
|
||||
* origin of all edges in the vertex loop to which eOrig belongs. "vNext" gives
|
||||
* a place to insert the new vertex in the global vertex list. We insert
|
||||
* the new vertex *before* vNext so that algorithms which walk the vertex
|
||||
* list will not see the newly created vertices.
|
||||
*/
|
||||
static void MakeVertex( GLUvertex *newVertex,
|
||||
GLUhalfEdge *eOrig, GLUvertex *vNext )
|
||||
{
|
||||
GLUhalfEdge *e;
|
||||
GLUvertex *vPrev;
|
||||
GLUvertex *vNew = newVertex;
|
||||
|
||||
assert(vNew != NULL);
|
||||
|
||||
/* insert in circular doubly-linked list before vNext */
|
||||
vPrev = vNext->prev;
|
||||
vNew->prev = vPrev;
|
||||
vPrev->next = vNew;
|
||||
vNew->next = vNext;
|
||||
vNext->prev = vNew;
|
||||
|
||||
vNew->anEdge = eOrig;
|
||||
vNew->data = NULL;
|
||||
/* leave coords, s, t undefined */
|
||||
|
||||
/* fix other edges on this vertex loop */
|
||||
e = eOrig;
|
||||
do {
|
||||
e->Org = vNew;
|
||||
e = e->Onext;
|
||||
} while( e != eOrig );
|
||||
}
|
||||
|
||||
/* MakeFace( newFace, eOrig, fNext ) attaches a new face and makes it the left
|
||||
* face of all edges in the face loop to which eOrig belongs. "fNext" gives
|
||||
* a place to insert the new face in the global face list. We insert
|
||||
* the new face *before* fNext so that algorithms which walk the face
|
||||
* list will not see the newly created faces.
|
||||
*/
|
||||
static void MakeFace( GLUface *newFace, GLUhalfEdge *eOrig, GLUface *fNext )
|
||||
{
|
||||
GLUhalfEdge *e;
|
||||
GLUface *fPrev;
|
||||
GLUface *fNew = newFace;
|
||||
|
||||
assert(fNew != NULL);
|
||||
|
||||
/* insert in circular doubly-linked list before fNext */
|
||||
fPrev = fNext->prev;
|
||||
fNew->prev = fPrev;
|
||||
fPrev->next = fNew;
|
||||
fNew->next = fNext;
|
||||
fNext->prev = fNew;
|
||||
|
||||
fNew->anEdge = eOrig;
|
||||
fNew->data = NULL;
|
||||
fNew->trail = NULL;
|
||||
fNew->marked = FALSE;
|
||||
|
||||
/* The new face is marked "inside" if the old one was. This is a
|
||||
* convenience for the common case where a face has been split in two.
|
||||
*/
|
||||
fNew->inside = fNext->inside;
|
||||
|
||||
/* fix other edges on this face loop */
|
||||
e = eOrig;
|
||||
do {
|
||||
e->Lface = fNew;
|
||||
e = e->Lnext;
|
||||
} while( e != eOrig );
|
||||
}
|
||||
|
||||
/* KillEdge( eDel ) destroys an edge (the half-edges eDel and eDel->Sym),
|
||||
* and removes from the global edge list.
|
||||
*/
|
||||
static void KillEdge( GLUhalfEdge *eDel )
|
||||
{
|
||||
GLUhalfEdge *ePrev, *eNext;
|
||||
|
||||
/* Half-edges are allocated in pairs, see EdgePair above */
|
||||
if( eDel->Sym < eDel ) { eDel = eDel->Sym; }
|
||||
|
||||
/* delete from circular doubly-linked list */
|
||||
eNext = eDel->next;
|
||||
ePrev = eDel->Sym->next;
|
||||
eNext->Sym->next = ePrev;
|
||||
ePrev->Sym->next = eNext;
|
||||
|
||||
memFree( eDel );
|
||||
}
|
||||
|
||||
|
||||
/* KillVertex( vDel ) destroys a vertex and removes it from the global
|
||||
* vertex list. It updates the vertex loop to point to a given new vertex.
|
||||
*/
|
||||
static void KillVertex( GLUvertex *vDel, GLUvertex *newOrg )
|
||||
{
|
||||
GLUhalfEdge *e, *eStart = vDel->anEdge;
|
||||
GLUvertex *vPrev, *vNext;
|
||||
|
||||
/* change the origin of all affected edges */
|
||||
e = eStart;
|
||||
do {
|
||||
e->Org = newOrg;
|
||||
e = e->Onext;
|
||||
} while( e != eStart );
|
||||
|
||||
/* delete from circular doubly-linked list */
|
||||
vPrev = vDel->prev;
|
||||
vNext = vDel->next;
|
||||
vNext->prev = vPrev;
|
||||
vPrev->next = vNext;
|
||||
|
||||
memFree( vDel );
|
||||
}
|
||||
|
||||
/* KillFace( fDel ) destroys a face and removes it from the global face
|
||||
* list. It updates the face loop to point to a given new face.
|
||||
*/
|
||||
static void KillFace( GLUface *fDel, GLUface *newLface )
|
||||
{
|
||||
GLUhalfEdge *e, *eStart = fDel->anEdge;
|
||||
GLUface *fPrev, *fNext;
|
||||
|
||||
/* change the left face of all affected edges */
|
||||
e = eStart;
|
||||
do {
|
||||
e->Lface = newLface;
|
||||
e = e->Lnext;
|
||||
} while( e != eStart );
|
||||
|
||||
/* delete from circular doubly-linked list */
|
||||
fPrev = fDel->prev;
|
||||
fNext = fDel->next;
|
||||
fNext->prev = fPrev;
|
||||
fPrev->next = fNext;
|
||||
|
||||
memFree( fDel );
|
||||
}
|
||||
|
||||
|
||||
/****************** Basic Edge Operations **********************/
|
||||
|
||||
/* __gl_meshMakeEdge creates one edge, two vertices, and a loop (face).
|
||||
* The loop consists of the two new half-edges.
|
||||
*/
|
||||
GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh )
|
||||
{
|
||||
GLUvertex *newVertex1= allocVertex();
|
||||
GLUvertex *newVertex2= allocVertex();
|
||||
GLUface *newFace= allocFace();
|
||||
GLUhalfEdge *e;
|
||||
|
||||
/* if any one is null then all get freed */
|
||||
if (newVertex1 == NULL || newVertex2 == NULL || newFace == NULL) {
|
||||
if (newVertex1 != NULL) memFree(newVertex1);
|
||||
if (newVertex2 != NULL) memFree(newVertex2);
|
||||
if (newFace != NULL) memFree(newFace);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
e = MakeEdge( &mesh->eHead );
|
||||
if (e == NULL) {
|
||||
memFree(newVertex1);
|
||||
memFree(newVertex2);
|
||||
memFree(newFace);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MakeVertex( newVertex1, e, &mesh->vHead );
|
||||
MakeVertex( newVertex2, e->Sym, &mesh->vHead );
|
||||
MakeFace( newFace, e, &mesh->fHead );
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
/* __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
|
||||
* mesh connectivity and topology. It changes the mesh so that
|
||||
* eOrg->Onext <- OLD( eDst->Onext )
|
||||
* eDst->Onext <- OLD( eOrg->Onext )
|
||||
* where OLD(...) means the value before the meshSplice operation.
|
||||
*
|
||||
* This can have two effects on the vertex structure:
|
||||
* - if eOrg->Org != eDst->Org, the two vertices are merged together
|
||||
* - if eOrg->Org == eDst->Org, the origin is split into two vertices
|
||||
* In both cases, eDst->Org is changed and eOrg->Org is untouched.
|
||||
*
|
||||
* Similarly (and independently) for the face structure,
|
||||
* - if eOrg->Lface == eDst->Lface, one loop is split into two
|
||||
* - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one
|
||||
* In both cases, eDst->Lface is changed and eOrg->Lface is unaffected.
|
||||
*
|
||||
* Some special cases:
|
||||
* If eDst == eOrg, the operation has no effect.
|
||||
* If eDst == eOrg->Lnext, the new face will have a single edge.
|
||||
* If eDst == eOrg->Lprev, the old face will have a single edge.
|
||||
* If eDst == eOrg->Onext, the new vertex will have a single edge.
|
||||
* If eDst == eOrg->Oprev, the old vertex will have a single edge.
|
||||
*/
|
||||
int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst )
|
||||
{
|
||||
int joiningLoops = FALSE;
|
||||
int joiningVertices = FALSE;
|
||||
|
||||
if( eOrg == eDst ) return 1;
|
||||
|
||||
if( eDst->Org != eOrg->Org ) {
|
||||
/* We are merging two disjoint vertices -- destroy eDst->Org */
|
||||
joiningVertices = TRUE;
|
||||
KillVertex( eDst->Org, eOrg->Org );
|
||||
}
|
||||
if( eDst->Lface != eOrg->Lface ) {
|
||||
/* We are connecting two disjoint loops -- destroy eDst->Lface */
|
||||
joiningLoops = TRUE;
|
||||
KillFace( eDst->Lface, eOrg->Lface );
|
||||
}
|
||||
|
||||
/* Change the edge structure */
|
||||
Splice( eDst, eOrg );
|
||||
|
||||
if( ! joiningVertices ) {
|
||||
GLUvertex *newVertex= allocVertex();
|
||||
if (newVertex == NULL) return 0;
|
||||
|
||||
/* We split one vertex into two -- the new vertex is eDst->Org.
|
||||
* Make sure the old vertex points to a valid half-edge.
|
||||
*/
|
||||
MakeVertex( newVertex, eDst, eOrg->Org );
|
||||
eOrg->Org->anEdge = eOrg;
|
||||
}
|
||||
if( ! joiningLoops ) {
|
||||
GLUface *newFace= allocFace();
|
||||
if (newFace == NULL) return 0;
|
||||
|
||||
/* We split one loop into two -- the new loop is eDst->Lface.
|
||||
* Make sure the old face points to a valid half-edge.
|
||||
*/
|
||||
MakeFace( newFace, eDst, eOrg->Lface );
|
||||
eOrg->Lface->anEdge = eOrg;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* __gl_meshDelete( eDel ) removes the edge eDel. There are several cases:
|
||||
* if (eDel->Lface != eDel->Rface), we join two loops into one; the loop
|
||||
* eDel->Lface is deleted. Otherwise, we are splitting one loop into two;
|
||||
* the newly created loop will contain eDel->Dst. If the deletion of eDel
|
||||
* would create isolated vertices, those are deleted as well.
|
||||
*
|
||||
* This function could be implemented as two calls to __gl_meshSplice
|
||||
* plus a few calls to memFree, but this would allocate and delete
|
||||
* unnecessary vertices and faces.
|
||||
*/
|
||||
int __gl_meshDelete( GLUhalfEdge *eDel )
|
||||
{
|
||||
GLUhalfEdge *eDelSym = eDel->Sym;
|
||||
int joiningLoops = FALSE;
|
||||
|
||||
/* First step: disconnect the origin vertex eDel->Org. We make all
|
||||
* changes to get a consistent mesh in this "intermediate" state.
|
||||
*/
|
||||
if( eDel->Lface != eDel->Rface ) {
|
||||
/* We are joining two loops into one -- remove the left face */
|
||||
joiningLoops = TRUE;
|
||||
KillFace( eDel->Lface, eDel->Rface );
|
||||
}
|
||||
|
||||
if( eDel->Onext == eDel ) {
|
||||
KillVertex( eDel->Org, NULL );
|
||||
} else {
|
||||
/* Make sure that eDel->Org and eDel->Rface point to valid half-edges */
|
||||
eDel->Rface->anEdge = eDel->Oprev;
|
||||
eDel->Org->anEdge = eDel->Onext;
|
||||
|
||||
Splice( eDel, eDel->Oprev );
|
||||
if( ! joiningLoops ) {
|
||||
GLUface *newFace= allocFace();
|
||||
if (newFace == NULL) return 0;
|
||||
|
||||
/* We are splitting one loop into two -- create a new loop for eDel. */
|
||||
MakeFace( newFace, eDel, eDel->Lface );
|
||||
}
|
||||
}
|
||||
|
||||
/* Claim: the mesh is now in a consistent state, except that eDel->Org
|
||||
* may have been deleted. Now we disconnect eDel->Dst.
|
||||
*/
|
||||
if( eDelSym->Onext == eDelSym ) {
|
||||
KillVertex( eDelSym->Org, NULL );
|
||||
KillFace( eDelSym->Lface, NULL );
|
||||
} else {
|
||||
/* Make sure that eDel->Dst and eDel->Lface point to valid half-edges */
|
||||
eDel->Lface->anEdge = eDelSym->Oprev;
|
||||
eDelSym->Org->anEdge = eDelSym->Onext;
|
||||
Splice( eDelSym, eDelSym->Oprev );
|
||||
}
|
||||
|
||||
/* Any isolated vertices or faces have already been freed. */
|
||||
KillEdge( eDel );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/******************** Other Edge Operations **********************/
|
||||
|
||||
/* All these routines can be implemented with the basic edge
|
||||
* operations above. They are provided for convenience and efficiency.
|
||||
*/
|
||||
|
||||
|
||||
/* __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that
|
||||
* eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex.
|
||||
* eOrg and eNew will have the same left face.
|
||||
*/
|
||||
GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg )
|
||||
{
|
||||
GLUhalfEdge *eNewSym;
|
||||
GLUhalfEdge *eNew = MakeEdge( eOrg );
|
||||
if (eNew == NULL) return NULL;
|
||||
|
||||
eNewSym = eNew->Sym;
|
||||
|
||||
/* Connect the new edge appropriately */
|
||||
Splice( eNew, eOrg->Lnext );
|
||||
|
||||
/* Set the vertex and face information */
|
||||
eNew->Org = eOrg->Dst;
|
||||
{
|
||||
GLUvertex *newVertex= allocVertex();
|
||||
if (newVertex == NULL) return NULL;
|
||||
|
||||
MakeVertex( newVertex, eNewSym, eNew->Org );
|
||||
}
|
||||
eNew->Lface = eNewSym->Lface = eOrg->Lface;
|
||||
|
||||
return eNew;
|
||||
}
|
||||
|
||||
|
||||
/* __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew,
|
||||
* such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org.
|
||||
* eOrg and eNew will have the same left face.
|
||||
*/
|
||||
GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg )
|
||||
{
|
||||
GLUhalfEdge *eNew;
|
||||
GLUhalfEdge *tempHalfEdge= __gl_meshAddEdgeVertex( eOrg );
|
||||
if (tempHalfEdge == NULL) return NULL;
|
||||
|
||||
eNew = tempHalfEdge->Sym;
|
||||
|
||||
/* Disconnect eOrg from eOrg->Dst and connect it to eNew->Org */
|
||||
Splice( eOrg->Sym, eOrg->Sym->Oprev );
|
||||
Splice( eOrg->Sym, eNew );
|
||||
|
||||
/* Set the vertex and face information */
|
||||
eOrg->Dst = eNew->Org;
|
||||
eNew->Dst->anEdge = eNew->Sym; /* may have pointed to eOrg->Sym */
|
||||
eNew->Rface = eOrg->Rface;
|
||||
eNew->winding = eOrg->winding; /* copy old winding information */
|
||||
eNew->Sym->winding = eOrg->Sym->winding;
|
||||
|
||||
return eNew;
|
||||
}
|
||||
|
||||
|
||||
/* __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst
|
||||
* to eDst->Org, and returns the corresponding half-edge eNew.
|
||||
* If eOrg->Lface == eDst->Lface, this splits one loop into two,
|
||||
* and the newly created loop is eNew->Lface. Otherwise, two disjoint
|
||||
* loops are merged into one, and the loop eDst->Lface is destroyed.
|
||||
*
|
||||
* If (eOrg == eDst), the new face will have only two edges.
|
||||
* If (eOrg->Lnext == eDst), the old face is reduced to a single edge.
|
||||
* If (eOrg->Lnext->Lnext == eDst), the old face is reduced to two edges.
|
||||
*/
|
||||
GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst )
|
||||
{
|
||||
GLUhalfEdge *eNewSym;
|
||||
int joiningLoops = FALSE;
|
||||
GLUhalfEdge *eNew = MakeEdge( eOrg );
|
||||
if (eNew == NULL) return NULL;
|
||||
|
||||
eNewSym = eNew->Sym;
|
||||
|
||||
if( eDst->Lface != eOrg->Lface ) {
|
||||
/* We are connecting two disjoint loops -- destroy eDst->Lface */
|
||||
joiningLoops = TRUE;
|
||||
KillFace( eDst->Lface, eOrg->Lface );
|
||||
}
|
||||
|
||||
/* Connect the new edge appropriately */
|
||||
Splice( eNew, eOrg->Lnext );
|
||||
Splice( eNewSym, eDst );
|
||||
|
||||
/* Set the vertex and face information */
|
||||
eNew->Org = eOrg->Dst;
|
||||
eNewSym->Org = eDst->Org;
|
||||
eNew->Lface = eNewSym->Lface = eOrg->Lface;
|
||||
|
||||
/* Make sure the old face points to a valid half-edge */
|
||||
eOrg->Lface->anEdge = eNewSym;
|
||||
|
||||
if( ! joiningLoops ) {
|
||||
GLUface *newFace= allocFace();
|
||||
if (newFace == NULL) return NULL;
|
||||
|
||||
/* We split one loop into two -- the new loop is eNew->Lface */
|
||||
MakeFace( newFace, eNew, eOrg->Lface );
|
||||
}
|
||||
return eNew;
|
||||
}
|
||||
|
||||
|
||||
/******************** Other Operations **********************/
|
||||
|
||||
/* __gl_meshZapFace( fZap ) destroys a face and removes it from the
|
||||
* global face list. All edges of fZap will have a NULL pointer as their
|
||||
* left face. Any edges which also have a NULL pointer as their right face
|
||||
* are deleted entirely (along with any isolated vertices this produces).
|
||||
* An entire mesh can be deleted by zapping its faces, one at a time,
|
||||
* in any order. Zapped faces cannot be used in further mesh operations!
|
||||
*/
|
||||
void __gl_meshZapFace( GLUface *fZap )
|
||||
{
|
||||
GLUhalfEdge *eStart = fZap->anEdge;
|
||||
GLUhalfEdge *e, *eNext, *eSym;
|
||||
GLUface *fPrev, *fNext;
|
||||
|
||||
/* walk around face, deleting edges whose right face is also NULL */
|
||||
eNext = eStart->Lnext;
|
||||
do {
|
||||
e = eNext;
|
||||
eNext = e->Lnext;
|
||||
|
||||
e->Lface = NULL;
|
||||
if( e->Rface == NULL ) {
|
||||
/* delete the edge -- see __gl_MeshDelete above */
|
||||
|
||||
if( e->Onext == e ) {
|
||||
KillVertex( e->Org, NULL );
|
||||
} else {
|
||||
/* Make sure that e->Org points to a valid half-edge */
|
||||
e->Org->anEdge = e->Onext;
|
||||
Splice( e, e->Oprev );
|
||||
}
|
||||
eSym = e->Sym;
|
||||
if( eSym->Onext == eSym ) {
|
||||
KillVertex( eSym->Org, NULL );
|
||||
} else {
|
||||
/* Make sure that eSym->Org points to a valid half-edge */
|
||||
eSym->Org->anEdge = eSym->Onext;
|
||||
Splice( eSym, eSym->Oprev );
|
||||
}
|
||||
KillEdge( e );
|
||||
}
|
||||
} while( e != eStart );
|
||||
|
||||
/* delete from circular doubly-linked list */
|
||||
fPrev = fZap->prev;
|
||||
fNext = fZap->next;
|
||||
fNext->prev = fPrev;
|
||||
fPrev->next = fNext;
|
||||
|
||||
memFree( fZap );
|
||||
}
|
||||
|
||||
|
||||
/* __gl_meshNewMesh() creates a new mesh with no edges, no vertices,
|
||||
* and no loops (what we usually call a "face").
|
||||
*/
|
||||
GLUmesh *__gl_meshNewMesh( void )
|
||||
{
|
||||
GLUvertex *v;
|
||||
GLUface *f;
|
||||
GLUhalfEdge *e;
|
||||
GLUhalfEdge *eSym;
|
||||
GLUmesh *mesh = (GLUmesh *)memAlloc( sizeof( GLUmesh ));
|
||||
if (mesh == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
v = &mesh->vHead;
|
||||
f = &mesh->fHead;
|
||||
e = &mesh->eHead;
|
||||
eSym = &mesh->eHeadSym;
|
||||
|
||||
v->next = v->prev = v;
|
||||
v->anEdge = NULL;
|
||||
v->data = NULL;
|
||||
|
||||
f->next = f->prev = f;
|
||||
f->anEdge = NULL;
|
||||
f->data = NULL;
|
||||
f->trail = NULL;
|
||||
f->marked = FALSE;
|
||||
f->inside = FALSE;
|
||||
|
||||
e->next = e;
|
||||
e->Sym = eSym;
|
||||
e->Onext = NULL;
|
||||
e->Lnext = NULL;
|
||||
e->Org = NULL;
|
||||
e->Lface = NULL;
|
||||
e->winding = 0;
|
||||
e->activeRegion = NULL;
|
||||
|
||||
eSym->next = eSym;
|
||||
eSym->Sym = e;
|
||||
eSym->Onext = NULL;
|
||||
eSym->Lnext = NULL;
|
||||
eSym->Org = NULL;
|
||||
eSym->Lface = NULL;
|
||||
eSym->winding = 0;
|
||||
eSym->activeRegion = NULL;
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
|
||||
/* __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in
|
||||
* both meshes, and returns the new mesh (the old meshes are destroyed).
|
||||
*/
|
||||
GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 )
|
||||
{
|
||||
GLUface *f1 = &mesh1->fHead;
|
||||
GLUvertex *v1 = &mesh1->vHead;
|
||||
GLUhalfEdge *e1 = &mesh1->eHead;
|
||||
GLUface *f2 = &mesh2->fHead;
|
||||
GLUvertex *v2 = &mesh2->vHead;
|
||||
GLUhalfEdge *e2 = &mesh2->eHead;
|
||||
|
||||
/* Add the faces, vertices, and edges of mesh2 to those of mesh1 */
|
||||
if( f2->next != f2 ) {
|
||||
f1->prev->next = f2->next;
|
||||
f2->next->prev = f1->prev;
|
||||
f2->prev->next = f1;
|
||||
f1->prev = f2->prev;
|
||||
}
|
||||
|
||||
if( v2->next != v2 ) {
|
||||
v1->prev->next = v2->next;
|
||||
v2->next->prev = v1->prev;
|
||||
v2->prev->next = v1;
|
||||
v1->prev = v2->prev;
|
||||
}
|
||||
|
||||
if( e2->next != e2 ) {
|
||||
e1->Sym->next->Sym->next = e2->next;
|
||||
e2->next->Sym->next = e1->Sym->next;
|
||||
e2->Sym->next->Sym->next = e1;
|
||||
e1->Sym->next = e2->Sym->next;
|
||||
}
|
||||
|
||||
memFree( mesh2 );
|
||||
return mesh1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DELETE_BY_ZAPPING
|
||||
|
||||
/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
|
||||
*/
|
||||
void __gl_meshDeleteMesh( GLUmesh *mesh )
|
||||
{
|
||||
GLUface *fHead = &mesh->fHead;
|
||||
|
||||
while( fHead->next != fHead ) {
|
||||
__gl_meshZapFace( fHead->next );
|
||||
}
|
||||
assert( mesh->vHead.next == &mesh->vHead );
|
||||
|
||||
memFree( mesh );
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
|
||||
*/
|
||||
void __gl_meshDeleteMesh( GLUmesh *mesh )
|
||||
{
|
||||
GLUface *f, *fNext;
|
||||
GLUvertex *v, *vNext;
|
||||
GLUhalfEdge *e, *eNext;
|
||||
|
||||
for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) {
|
||||
fNext = f->next;
|
||||
memFree( f );
|
||||
}
|
||||
|
||||
for( v = mesh->vHead.next; v != &mesh->vHead; v = vNext ) {
|
||||
vNext = v->next;
|
||||
memFree( v );
|
||||
}
|
||||
|
||||
for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) {
|
||||
/* One call frees both e and e->Sym (see EdgePair above) */
|
||||
eNext = e->next;
|
||||
memFree( e );
|
||||
}
|
||||
|
||||
memFree( mesh );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
/* __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency.
|
||||
*/
|
||||
void __gl_meshCheckMesh( GLUmesh *mesh )
|
||||
{
|
||||
GLUface *fHead = &mesh->fHead;
|
||||
GLUvertex *vHead = &mesh->vHead;
|
||||
GLUhalfEdge *eHead = &mesh->eHead;
|
||||
GLUface *f, *fPrev;
|
||||
GLUvertex *v, *vPrev;
|
||||
GLUhalfEdge *e, *ePrev;
|
||||
|
||||
fPrev = fHead;
|
||||
for( fPrev = fHead ; (f = fPrev->next) != fHead; fPrev = f) {
|
||||
assert( f->prev == fPrev );
|
||||
e = f->anEdge;
|
||||
do {
|
||||
assert( e->Sym != e );
|
||||
assert( e->Sym->Sym == e );
|
||||
assert( e->Lnext->Onext->Sym == e );
|
||||
assert( e->Onext->Sym->Lnext == e );
|
||||
assert( e->Lface == f );
|
||||
e = e->Lnext;
|
||||
} while( e != f->anEdge );
|
||||
}
|
||||
assert( f->prev == fPrev && f->anEdge == NULL && f->data == NULL );
|
||||
|
||||
vPrev = vHead;
|
||||
for( vPrev = vHead ; (v = vPrev->next) != vHead; vPrev = v) {
|
||||
assert( v->prev == vPrev );
|
||||
e = v->anEdge;
|
||||
do {
|
||||
assert( e->Sym != e );
|
||||
assert( e->Sym->Sym == e );
|
||||
assert( e->Lnext->Onext->Sym == e );
|
||||
assert( e->Onext->Sym->Lnext == e );
|
||||
assert( e->Org == v );
|
||||
e = e->Onext;
|
||||
} while( e != v->anEdge );
|
||||
}
|
||||
assert( v->prev == vPrev && v->anEdge == NULL && v->data == NULL );
|
||||
|
||||
ePrev = eHead;
|
||||
for( ePrev = eHead ; (e = ePrev->next) != eHead; ePrev = e) {
|
||||
assert( e->Sym->next == ePrev->Sym );
|
||||
assert( e->Sym != e );
|
||||
assert( e->Sym->Sym == e );
|
||||
assert( e->Org != NULL );
|
||||
assert( e->Dst != NULL );
|
||||
assert( e->Lnext->Onext->Sym == e );
|
||||
assert( e->Onext->Sym->Lnext == e );
|
||||
}
|
||||
assert( e->Sym->next == ePrev->Sym
|
||||
&& e->Sym == &mesh->eHeadSym
|
||||
&& e->Sym->Sym == e
|
||||
&& e->Org == NULL && e->Dst == NULL
|
||||
&& e->Lface == NULL && e->Rface == NULL );
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __mesh_h_
|
||||
#define __mesh_h_
|
||||
|
||||
#include "glu.h"
|
||||
|
||||
typedef struct GLUmesh GLUmesh;
|
||||
|
||||
typedef struct GLUvertex GLUvertex;
|
||||
typedef struct GLUface GLUface;
|
||||
typedef struct GLUhalfEdge GLUhalfEdge;
|
||||
|
||||
typedef struct ActiveRegion ActiveRegion; /* Internal data */
|
||||
|
||||
/* The mesh structure is similar in spirit, notation, and operations
|
||||
* to the "quad-edge" structure (see L. Guibas and J. Stolfi, Primitives
|
||||
* for the manipulation of general subdivisions and the computation of
|
||||
* Voronoi diagrams, ACM Transactions on Graphics, 4(2):74-123, April 1985).
|
||||
* For a simplified description, see the course notes for CS348a,
|
||||
* "Mathematical Foundations of Computer Graphics", available at the
|
||||
* Stanford bookstore (and taught during the fall quarter).
|
||||
* The implementation also borrows a tiny subset of the graph-based approach
|
||||
* use in Mantyla's Geometric Work Bench (see M. Mantyla, An Introduction
|
||||
* to Sold Modeling, Computer Science Press, Rockville, Maryland, 1988).
|
||||
*
|
||||
* The fundamental data structure is the "half-edge". Two half-edges
|
||||
* go together to make an edge, but they point in opposite directions.
|
||||
* Each half-edge has a pointer to its mate (the "symmetric" half-edge Sym),
|
||||
* its origin vertex (Org), the face on its left side (Lface), and the
|
||||
* adjacent half-edges in the CCW direction around the origin vertex
|
||||
* (Onext) and around the left face (Lnext). There is also a "next"
|
||||
* pointer for the global edge list (see below).
|
||||
*
|
||||
* The notation used for mesh navigation:
|
||||
* Sym = the mate of a half-edge (same edge, but opposite direction)
|
||||
* Onext = edge CCW around origin vertex (keep same origin)
|
||||
* Dnext = edge CCW around destination vertex (keep same dest)
|
||||
* Lnext = edge CCW around left face (dest becomes new origin)
|
||||
* Rnext = edge CCW around right face (origin becomes new dest)
|
||||
*
|
||||
* "prev" means to substitute CW for CCW in the definitions above.
|
||||
*
|
||||
* The mesh keeps global lists of all vertices, faces, and edges,
|
||||
* stored as doubly-linked circular lists with a dummy header node.
|
||||
* The mesh stores pointers to these dummy headers (vHead, fHead, eHead).
|
||||
*
|
||||
* The circular edge list is special; since half-edges always occur
|
||||
* in pairs (e and e->Sym), each half-edge stores a pointer in only
|
||||
* one direction. Starting at eHead and following the e->next pointers
|
||||
* will visit each *edge* once (ie. e or e->Sym, but not both).
|
||||
* e->Sym stores a pointer in the opposite direction, thus it is
|
||||
* always true that e->Sym->next->Sym->next == e.
|
||||
*
|
||||
* Each vertex has a pointer to next and previous vertices in the
|
||||
* circular list, and a pointer to a half-edge with this vertex as
|
||||
* the origin (NULL if this is the dummy header). There is also a
|
||||
* field "data" for client data.
|
||||
*
|
||||
* Each face has a pointer to the next and previous faces in the
|
||||
* circular list, and a pointer to a half-edge with this face as
|
||||
* the left face (NULL if this is the dummy header). There is also
|
||||
* a field "data" for client data.
|
||||
*
|
||||
* Note that what we call a "face" is really a loop; faces may consist
|
||||
* of more than one loop (ie. not simply connected), but there is no
|
||||
* record of this in the data structure. The mesh may consist of
|
||||
* several disconnected regions, so it may not be possible to visit
|
||||
* the entire mesh by starting at a half-edge and traversing the edge
|
||||
* structure.
|
||||
*
|
||||
* The mesh does NOT support isolated vertices; a vertex is deleted along
|
||||
* with its last edge. Similarly when two faces are merged, one of the
|
||||
* faces is deleted (see __gl_meshDelete below). For mesh operations,
|
||||
* all face (loop) and vertex pointers must not be NULL. However, once
|
||||
* mesh manipulation is finished, __gl_MeshZapFace can be used to delete
|
||||
* faces of the mesh, one at a time. All external faces can be "zapped"
|
||||
* before the mesh is returned to the client; then a NULL face indicates
|
||||
* a region which is not part of the output polygon.
|
||||
*/
|
||||
|
||||
struct GLUvertex {
|
||||
GLUvertex *next; /* next vertex (never NULL) */
|
||||
GLUvertex *prev; /* previous vertex (never NULL) */
|
||||
GLUhalfEdge *anEdge; /* a half-edge with this origin */
|
||||
void *data; /* client's data */
|
||||
|
||||
/* Internal data (keep hidden) */
|
||||
GLdouble coords[3]; /* vertex location in 3D */
|
||||
GLdouble s, t; /* projection onto the sweep plane */
|
||||
long pqHandle; /* to allow deletion from priority queue */
|
||||
};
|
||||
|
||||
struct GLUface {
|
||||
GLUface *next; /* next face (never NULL) */
|
||||
GLUface *prev; /* previous face (never NULL) */
|
||||
GLUhalfEdge *anEdge; /* a half edge with this left face */
|
||||
void *data; /* room for client's data */
|
||||
|
||||
/* Internal data (keep hidden) */
|
||||
GLUface *trail; /* "stack" for conversion to strips */
|
||||
GLboolean marked; /* flag for conversion to strips */
|
||||
GLboolean inside; /* this face is in the polygon interior */
|
||||
};
|
||||
|
||||
struct GLUhalfEdge {
|
||||
GLUhalfEdge *next; /* doubly-linked list (prev==Sym->next) */
|
||||
GLUhalfEdge *Sym; /* same edge, opposite direction */
|
||||
GLUhalfEdge *Onext; /* next edge CCW around origin */
|
||||
GLUhalfEdge *Lnext; /* next edge CCW around left face */
|
||||
GLUvertex *Org; /* origin vertex (Overtex too long) */
|
||||
GLUface *Lface; /* left face */
|
||||
|
||||
/* Internal data (keep hidden) */
|
||||
ActiveRegion *activeRegion; /* a region with this upper edge (sweep.c) */
|
||||
int winding; /* change in winding number when crossing
|
||||
from the right face to the left face */
|
||||
};
|
||||
|
||||
#define Rface Sym->Lface
|
||||
#define Dst Sym->Org
|
||||
|
||||
#define Oprev Sym->Lnext
|
||||
#define Lprev Onext->Sym
|
||||
#define Dprev Lnext->Sym
|
||||
#define Rprev Sym->Onext
|
||||
#define Dnext Rprev->Sym /* 3 pointers */
|
||||
#define Rnext Oprev->Sym /* 3 pointers */
|
||||
|
||||
|
||||
struct GLUmesh {
|
||||
GLUvertex vHead; /* dummy header for vertex list */
|
||||
GLUface fHead; /* dummy header for face list */
|
||||
GLUhalfEdge eHead; /* dummy header for edge list */
|
||||
GLUhalfEdge eHeadSym; /* and its symmetric counterpart */
|
||||
};
|
||||
|
||||
/* The mesh operations below have three motivations: completeness,
|
||||
* convenience, and efficiency. The basic mesh operations are MakeEdge,
|
||||
* Splice, and Delete. All the other edge operations can be implemented
|
||||
* in terms of these. The other operations are provided for convenience
|
||||
* and/or efficiency.
|
||||
*
|
||||
* When a face is split or a vertex is added, they are inserted into the
|
||||
* global list *before* the existing vertex or face (ie. e->Org or e->Lface).
|
||||
* This makes it easier to process all vertices or faces in the global lists
|
||||
* without worrying about processing the same data twice. As a convenience,
|
||||
* when a face is split, the "inside" flag is copied from the old face.
|
||||
* Other internal data (v->data, v->activeRegion, f->data, f->marked,
|
||||
* f->trail, e->winding) is set to zero.
|
||||
*
|
||||
* ********************** Basic Edge Operations **************************
|
||||
*
|
||||
* __gl_meshMakeEdge( mesh ) creates one edge, two vertices, and a loop.
|
||||
* The loop (face) consists of the two new half-edges.
|
||||
*
|
||||
* __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
|
||||
* mesh connectivity and topology. It changes the mesh so that
|
||||
* eOrg->Onext <- OLD( eDst->Onext )
|
||||
* eDst->Onext <- OLD( eOrg->Onext )
|
||||
* where OLD(...) means the value before the meshSplice operation.
|
||||
*
|
||||
* This can have two effects on the vertex structure:
|
||||
* - if eOrg->Org != eDst->Org, the two vertices are merged together
|
||||
* - if eOrg->Org == eDst->Org, the origin is split into two vertices
|
||||
* In both cases, eDst->Org is changed and eOrg->Org is untouched.
|
||||
*
|
||||
* Similarly (and independently) for the face structure,
|
||||
* - if eOrg->Lface == eDst->Lface, one loop is split into two
|
||||
* - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one
|
||||
* In both cases, eDst->Lface is changed and eOrg->Lface is unaffected.
|
||||
*
|
||||
* __gl_meshDelete( eDel ) removes the edge eDel. There are several cases:
|
||||
* if (eDel->Lface != eDel->Rface), we join two loops into one; the loop
|
||||
* eDel->Lface is deleted. Otherwise, we are splitting one loop into two;
|
||||
* the newly created loop will contain eDel->Dst. If the deletion of eDel
|
||||
* would create isolated vertices, those are deleted as well.
|
||||
*
|
||||
* ********************** Other Edge Operations **************************
|
||||
*
|
||||
* __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that
|
||||
* eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex.
|
||||
* eOrg and eNew will have the same left face.
|
||||
*
|
||||
* __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew,
|
||||
* such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org.
|
||||
* eOrg and eNew will have the same left face.
|
||||
*
|
||||
* __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst
|
||||
* to eDst->Org, and returns the corresponding half-edge eNew.
|
||||
* If eOrg->Lface == eDst->Lface, this splits one loop into two,
|
||||
* and the newly created loop is eNew->Lface. Otherwise, two disjoint
|
||||
* loops are merged into one, and the loop eDst->Lface is destroyed.
|
||||
*
|
||||
* ************************ Other Operations *****************************
|
||||
*
|
||||
* __gl_meshNewMesh() creates a new mesh with no edges, no vertices,
|
||||
* and no loops (what we usually call a "face").
|
||||
*
|
||||
* __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in
|
||||
* both meshes, and returns the new mesh (the old meshes are destroyed).
|
||||
*
|
||||
* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
|
||||
*
|
||||
* __gl_meshZapFace( fZap ) destroys a face and removes it from the
|
||||
* global face list. All edges of fZap will have a NULL pointer as their
|
||||
* left face. Any edges which also have a NULL pointer as their right face
|
||||
* are deleted entirely (along with any isolated vertices this produces).
|
||||
* An entire mesh can be deleted by zapping its faces, one at a time,
|
||||
* in any order. Zapped faces cannot be used in further mesh operations!
|
||||
*
|
||||
* __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency.
|
||||
*/
|
||||
|
||||
GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh );
|
||||
int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst );
|
||||
int __gl_meshDelete( GLUhalfEdge *eDel );
|
||||
|
||||
GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg );
|
||||
GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg );
|
||||
GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst );
|
||||
|
||||
GLUmesh *__gl_meshNewMesh( void );
|
||||
GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 );
|
||||
void __gl_meshDeleteMesh( GLUmesh *mesh );
|
||||
void __gl_meshZapFace( GLUface *fZap );
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define __gl_meshCheckMesh( mesh )
|
||||
#else
|
||||
void __gl_meshCheckMesh( GLUmesh *mesh );
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gluos.h"
|
||||
#include "mesh.h"
|
||||
#include "tess.h"
|
||||
#include "normal.h"
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#define Dot(u,v) (u[0]*v[0] + u[1]*v[1] + u[2]*v[2])
|
||||
|
||||
#if 0
|
||||
static void Normalize( GLdouble v[3] )
|
||||
{
|
||||
GLdouble len = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
|
||||
|
||||
assert( len > 0 );
|
||||
len = sqrt( len );
|
||||
v[0] /= len;
|
||||
v[1] /= len;
|
||||
v[2] /= len;
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef ABS
|
||||
#define ABS(x) ((x) < 0 ? -(x) : (x))
|
||||
|
||||
static int LongAxis( GLdouble v[3] )
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if( ABS(v[1]) > ABS(v[0]) ) { i = 1; }
|
||||
if( ABS(v[2]) > ABS(v[i]) ) { i = 2; }
|
||||
return i;
|
||||
}
|
||||
|
||||
static void ComputeNormal( GLUtesselator *tess, GLdouble norm[3] )
|
||||
{
|
||||
GLUvertex *v, *v1, *v2;
|
||||
GLdouble c, tLen2, maxLen2;
|
||||
GLdouble maxVal[3], minVal[3], d1[3], d2[3], tNorm[3];
|
||||
GLUvertex *maxVert[3], *minVert[3];
|
||||
GLUvertex *vHead = &tess->mesh->vHead;
|
||||
int i;
|
||||
|
||||
maxVal[0] = maxVal[1] = maxVal[2] = -2 * GLU_TESS_MAX_COORD;
|
||||
minVal[0] = minVal[1] = minVal[2] = 2 * GLU_TESS_MAX_COORD;
|
||||
|
||||
for( v = vHead->next; v != vHead; v = v->next ) {
|
||||
for( i = 0; i < 3; ++i ) {
|
||||
c = v->coords[i];
|
||||
if( c < minVal[i] ) { minVal[i] = c; minVert[i] = v; }
|
||||
if( c > maxVal[i] ) { maxVal[i] = c; maxVert[i] = v; }
|
||||
}
|
||||
}
|
||||
|
||||
/* Find two vertices separated by at least 1/sqrt(3) of the maximum
|
||||
* distance between any two vertices
|
||||
*/
|
||||
i = 0;
|
||||
if( maxVal[1] - minVal[1] > maxVal[0] - minVal[0] ) { i = 1; }
|
||||
if( maxVal[2] - minVal[2] > maxVal[i] - minVal[i] ) { i = 2; }
|
||||
if( minVal[i] >= maxVal[i] ) {
|
||||
/* All vertices are the same -- normal doesn't matter */
|
||||
norm[0] = 0; norm[1] = 0; norm[2] = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Look for a third vertex which forms the triangle with maximum area
|
||||
* (Length of normal == twice the triangle area)
|
||||
*/
|
||||
maxLen2 = 0;
|
||||
v1 = minVert[i];
|
||||
v2 = maxVert[i];
|
||||
d1[0] = v1->coords[0] - v2->coords[0];
|
||||
d1[1] = v1->coords[1] - v2->coords[1];
|
||||
d1[2] = v1->coords[2] - v2->coords[2];
|
||||
for( v = vHead->next; v != vHead; v = v->next ) {
|
||||
d2[0] = v->coords[0] - v2->coords[0];
|
||||
d2[1] = v->coords[1] - v2->coords[1];
|
||||
d2[2] = v->coords[2] - v2->coords[2];
|
||||
tNorm[0] = d1[1]*d2[2] - d1[2]*d2[1];
|
||||
tNorm[1] = d1[2]*d2[0] - d1[0]*d2[2];
|
||||
tNorm[2] = d1[0]*d2[1] - d1[1]*d2[0];
|
||||
tLen2 = tNorm[0]*tNorm[0] + tNorm[1]*tNorm[1] + tNorm[2]*tNorm[2];
|
||||
if( tLen2 > maxLen2 ) {
|
||||
maxLen2 = tLen2;
|
||||
norm[0] = tNorm[0];
|
||||
norm[1] = tNorm[1];
|
||||
norm[2] = tNorm[2];
|
||||
}
|
||||
}
|
||||
|
||||
if( maxLen2 <= 0 ) {
|
||||
/* All points lie on a single line -- any decent normal will do */
|
||||
norm[0] = norm[1] = norm[2] = 0;
|
||||
norm[LongAxis(d1)] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void CheckOrientation( GLUtesselator *tess )
|
||||
{
|
||||
GLdouble area;
|
||||
GLUface *f, *fHead = &tess->mesh->fHead;
|
||||
GLUvertex *v, *vHead = &tess->mesh->vHead;
|
||||
GLUhalfEdge *e;
|
||||
|
||||
/* When we compute the normal automatically, we choose the orientation
|
||||
* so that the sum of the signed areas of all contours is non-negative.
|
||||
*/
|
||||
area = 0;
|
||||
for( f = fHead->next; f != fHead; f = f->next ) {
|
||||
e = f->anEdge;
|
||||
if( e->winding <= 0 ) continue;
|
||||
do {
|
||||
area += (e->Org->s - e->Dst->s) * (e->Org->t + e->Dst->t);
|
||||
e = e->Lnext;
|
||||
} while( e != f->anEdge );
|
||||
}
|
||||
if( area < 0 ) {
|
||||
/* Reverse the orientation by flipping all the t-coordinates */
|
||||
for( v = vHead->next; v != vHead; v = v->next ) {
|
||||
v->t = - v->t;
|
||||
}
|
||||
tess->tUnit[0] = - tess->tUnit[0];
|
||||
tess->tUnit[1] = - tess->tUnit[1];
|
||||
tess->tUnit[2] = - tess->tUnit[2];
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FOR_TRITE_TEST_PROGRAM
|
||||
#include <stdlib.h>
|
||||
extern int RandomSweep;
|
||||
#define S_UNIT_X (RandomSweep ? (2*drand48()-1) : 1.0)
|
||||
#define S_UNIT_Y (RandomSweep ? (2*drand48()-1) : 0.0)
|
||||
#else
|
||||
#if defined(SLANTED_SWEEP)
|
||||
/* The "feature merging" is not intended to be complete. There are
|
||||
* special cases where edges are nearly parallel to the sweep line
|
||||
* which are not implemented. The algorithm should still behave
|
||||
* robustly (ie. produce a reasonable tesselation) in the presence
|
||||
* of such edges, however it may miss features which could have been
|
||||
* merged. We could minimize this effect by choosing the sweep line
|
||||
* direction to be something unusual (ie. not parallel to one of the
|
||||
* coordinate axes).
|
||||
*/
|
||||
#define S_UNIT_X 0.50941539564955385 /* Pre-normalized */
|
||||
#define S_UNIT_Y 0.86052074622010633
|
||||
#else
|
||||
#define S_UNIT_X 1.0
|
||||
#define S_UNIT_Y 0.0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Determine the polygon normal and project vertices onto the plane
|
||||
* of the polygon.
|
||||
*/
|
||||
void __gl_projectPolygon( GLUtesselator *tess )
|
||||
{
|
||||
GLUvertex *v, *vHead = &tess->mesh->vHead;
|
||||
GLdouble norm[3];
|
||||
GLdouble *sUnit, *tUnit;
|
||||
int i, computedNormal = FALSE;
|
||||
|
||||
norm[0] = tess->normal[0];
|
||||
norm[1] = tess->normal[1];
|
||||
norm[2] = tess->normal[2];
|
||||
if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) {
|
||||
ComputeNormal( tess, norm );
|
||||
computedNormal = TRUE;
|
||||
}
|
||||
sUnit = tess->sUnit;
|
||||
tUnit = tess->tUnit;
|
||||
i = LongAxis( norm );
|
||||
|
||||
#if defined(FOR_TRITE_TEST_PROGRAM) || defined(TRUE_PROJECT)
|
||||
/* Choose the initial sUnit vector to be approximately perpendicular
|
||||
* to the normal.
|
||||
*/
|
||||
Normalize( norm );
|
||||
|
||||
sUnit[i] = 0;
|
||||
sUnit[(i+1)%3] = S_UNIT_X;
|
||||
sUnit[(i+2)%3] = S_UNIT_Y;
|
||||
|
||||
/* Now make it exactly perpendicular */
|
||||
w = Dot( sUnit, norm );
|
||||
sUnit[0] -= w * norm[0];
|
||||
sUnit[1] -= w * norm[1];
|
||||
sUnit[2] -= w * norm[2];
|
||||
Normalize( sUnit );
|
||||
|
||||
/* Choose tUnit so that (sUnit,tUnit,norm) form a right-handed frame */
|
||||
tUnit[0] = norm[1]*sUnit[2] - norm[2]*sUnit[1];
|
||||
tUnit[1] = norm[2]*sUnit[0] - norm[0]*sUnit[2];
|
||||
tUnit[2] = norm[0]*sUnit[1] - norm[1]*sUnit[0];
|
||||
Normalize( tUnit );
|
||||
#else
|
||||
/* Project perpendicular to a coordinate axis -- better numerically */
|
||||
sUnit[i] = 0;
|
||||
sUnit[(i+1)%3] = S_UNIT_X;
|
||||
sUnit[(i+2)%3] = S_UNIT_Y;
|
||||
|
||||
tUnit[i] = 0;
|
||||
tUnit[(i+1)%3] = (norm[i] > 0) ? -S_UNIT_Y : S_UNIT_Y;
|
||||
tUnit[(i+2)%3] = (norm[i] > 0) ? S_UNIT_X : -S_UNIT_X;
|
||||
#endif
|
||||
|
||||
/* Project the vertices onto the sweep plane */
|
||||
for( v = vHead->next; v != vHead; v = v->next ) {
|
||||
v->s = Dot( v->coords, sUnit );
|
||||
v->t = Dot( v->coords, tUnit );
|
||||
}
|
||||
if( computedNormal ) {
|
||||
CheckOrientation( tess );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __normal_h_
|
||||
#define __normal_h_
|
||||
|
||||
#include "tess.h"
|
||||
|
||||
/* __gl_projectPolygon( tess ) determines the polygon normal
|
||||
* and project vertices onto the plane of the polygon.
|
||||
*/
|
||||
void __gl_projectPolygon( GLUtesselator *tess );
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
#include "priorityq-heap.h"
|
||||
#include "memalloc.h"
|
||||
|
||||
#define INIT_SIZE 32
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifdef FOR_TRITE_TEST_PROGRAM
|
||||
#define LEQ(x,y) (*pq->leq)(x,y)
|
||||
#else
|
||||
/* Violates modularity, but a little faster */
|
||||
#include "geom.h"
|
||||
#define LEQ(x,y) VertLeq((GLUvertex *)x, (GLUvertex *)y)
|
||||
#endif
|
||||
|
||||
/* really __gl_pqHeapNewPriorityQ */
|
||||
PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) )
|
||||
{
|
||||
PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ ));
|
||||
if (pq == NULL) return NULL;
|
||||
|
||||
pq->size = 0;
|
||||
pq->max = INIT_SIZE;
|
||||
pq->nodes = (PQnode *)memAlloc( (INIT_SIZE + 1) * sizeof(pq->nodes[0]) );
|
||||
if (pq->nodes == NULL) {
|
||||
memFree(pq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pq->handles = (PQhandleElem *)memAlloc( (INIT_SIZE + 1) * sizeof(pq->handles[0]) );
|
||||
if (pq->handles == NULL) {
|
||||
memFree(pq->nodes);
|
||||
memFree(pq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pq->initialized = FALSE;
|
||||
pq->freeList = 0;
|
||||
pq->leq = leq;
|
||||
|
||||
pq->nodes[1].handle = 1; /* so that Minimum() returns NULL */
|
||||
pq->handles[1].key = NULL;
|
||||
return pq;
|
||||
}
|
||||
|
||||
/* really __gl_pqHeapDeletePriorityQ */
|
||||
void pqDeletePriorityQ( PriorityQ *pq )
|
||||
{
|
||||
memFree( pq->handles );
|
||||
memFree( pq->nodes );
|
||||
memFree( pq );
|
||||
}
|
||||
|
||||
|
||||
static void FloatDown( PriorityQ *pq, long curr )
|
||||
{
|
||||
PQnode *n = pq->nodes;
|
||||
PQhandleElem *h = pq->handles;
|
||||
PQhandle hCurr, hChild;
|
||||
long child;
|
||||
|
||||
hCurr = n[curr].handle;
|
||||
for( ;; ) {
|
||||
child = curr << 1;
|
||||
if( child < pq->size && LEQ( h[n[child+1].handle].key,
|
||||
h[n[child].handle].key )) {
|
||||
++child;
|
||||
}
|
||||
|
||||
assert(child <= pq->max);
|
||||
|
||||
hChild = n[child].handle;
|
||||
if( child > pq->size || LEQ( h[hCurr].key, h[hChild].key )) {
|
||||
n[curr].handle = hCurr;
|
||||
h[hCurr].node = curr;
|
||||
break;
|
||||
}
|
||||
n[curr].handle = hChild;
|
||||
h[hChild].node = curr;
|
||||
curr = child;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void FloatUp( PriorityQ *pq, long curr )
|
||||
{
|
||||
PQnode *n = pq->nodes;
|
||||
PQhandleElem *h = pq->handles;
|
||||
PQhandle hCurr, hParent;
|
||||
long parent;
|
||||
|
||||
hCurr = n[curr].handle;
|
||||
for( ;; ) {
|
||||
parent = curr >> 1;
|
||||
hParent = n[parent].handle;
|
||||
if( parent == 0 || LEQ( h[hParent].key, h[hCurr].key )) {
|
||||
n[curr].handle = hCurr;
|
||||
h[hCurr].node = curr;
|
||||
break;
|
||||
}
|
||||
n[curr].handle = hParent;
|
||||
h[hParent].node = curr;
|
||||
curr = parent;
|
||||
}
|
||||
}
|
||||
|
||||
/* really __gl_pqHeapInit */
|
||||
void pqInit( PriorityQ *pq )
|
||||
{
|
||||
long i;
|
||||
|
||||
/* This method of building a heap is O(n), rather than O(n lg n). */
|
||||
|
||||
for( i = pq->size; i >= 1; --i ) {
|
||||
FloatDown( pq, i );
|
||||
}
|
||||
pq->initialized = TRUE;
|
||||
}
|
||||
|
||||
/* really __gl_pqHeapInsert */
|
||||
/* returns LONG_MAX iff out of memory */
|
||||
PQhandle pqInsert( PriorityQ *pq, PQkey keyNew )
|
||||
{
|
||||
long curr;
|
||||
PQhandle free_handle;
|
||||
|
||||
curr = ++ pq->size;
|
||||
if( (curr*2) > pq->max ) {
|
||||
PQnode *saveNodes= pq->nodes;
|
||||
PQhandleElem *saveHandles= pq->handles;
|
||||
|
||||
/* If the heap overflows, double its size. */
|
||||
pq->max <<= 1;
|
||||
pq->nodes = (PQnode *)memRealloc( pq->nodes,
|
||||
(size_t)
|
||||
((pq->max + 1) * sizeof( pq->nodes[0] )));
|
||||
if (pq->nodes == NULL) {
|
||||
pq->nodes = saveNodes; /* restore ptr to free upon return */
|
||||
return LONG_MAX;
|
||||
}
|
||||
pq->handles = (PQhandleElem *)memRealloc( pq->handles,
|
||||
(size_t)
|
||||
((pq->max + 1) *
|
||||
sizeof( pq->handles[0] )));
|
||||
if (pq->handles == NULL) {
|
||||
pq->handles = saveHandles; /* restore ptr to free upon return */
|
||||
return LONG_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
if( pq->freeList == 0 ) {
|
||||
free_handle = curr;
|
||||
} else {
|
||||
free_handle = pq->freeList;
|
||||
pq->freeList = pq->handles[free_handle].node;
|
||||
}
|
||||
|
||||
pq->nodes[curr].handle = free_handle;
|
||||
pq->handles[free_handle].node = curr;
|
||||
pq->handles[free_handle].key = keyNew;
|
||||
|
||||
if( pq->initialized ) {
|
||||
FloatUp( pq, curr );
|
||||
}
|
||||
assert(free_handle != LONG_MAX);
|
||||
return free_handle;
|
||||
}
|
||||
|
||||
/* really __gl_pqHeapExtractMin */
|
||||
PQkey pqExtractMin( PriorityQ *pq )
|
||||
{
|
||||
PQnode *n = pq->nodes;
|
||||
PQhandleElem *h = pq->handles;
|
||||
PQhandle hMin = n[1].handle;
|
||||
PQkey min = h[hMin].key;
|
||||
|
||||
if( pq->size > 0 ) {
|
||||
n[1].handle = n[pq->size].handle;
|
||||
h[n[1].handle].node = 1;
|
||||
|
||||
h[hMin].key = NULL;
|
||||
h[hMin].node = pq->freeList;
|
||||
pq->freeList = hMin;
|
||||
|
||||
if( -- pq->size > 0 ) {
|
||||
FloatDown( pq, 1 );
|
||||
}
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
/* really __gl_pqHeapDelete */
|
||||
void pqDelete( PriorityQ *pq, PQhandle hCurr )
|
||||
{
|
||||
PQnode *n = pq->nodes;
|
||||
PQhandleElem *h = pq->handles;
|
||||
long curr;
|
||||
|
||||
assert( hCurr >= 1 && hCurr <= pq->max && h[hCurr].key != NULL );
|
||||
|
||||
curr = h[hCurr].node;
|
||||
n[curr].handle = n[pq->size].handle;
|
||||
h[n[curr].handle].node = curr;
|
||||
|
||||
if( curr <= -- pq->size ) {
|
||||
if( curr <= 1 || LEQ( h[n[curr>>1].handle].key, h[n[curr].handle].key )) {
|
||||
FloatDown( pq, curr );
|
||||
} else {
|
||||
FloatUp( pq, curr );
|
||||
}
|
||||
}
|
||||
h[hCurr].key = NULL;
|
||||
h[hCurr].node = pq->freeList;
|
||||
pq->freeList = hCurr;
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __priorityq_heap_h_
|
||||
#define __priorityq_heap_h_
|
||||
|
||||
/* Use #define's so that another heap implementation can use this one */
|
||||
|
||||
#define PQkey PQHeapKey
|
||||
#define PQhandle PQHeapHandle
|
||||
#define PriorityQ PriorityQHeap
|
||||
|
||||
#define pqNewPriorityQ(leq) __gl_pqHeapNewPriorityQ(leq)
|
||||
#define pqDeletePriorityQ(pq) __gl_pqHeapDeletePriorityQ(pq)
|
||||
|
||||
/* The basic operations are insertion of a new key (pqInsert),
|
||||
* and examination/extraction of a key whose value is minimum
|
||||
* (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete);
|
||||
* for this purpose pqInsert returns a "handle" which is supplied
|
||||
* as the argument.
|
||||
*
|
||||
* An initial heap may be created efficiently by calling pqInsert
|
||||
* repeatedly, then calling pqInit. In any case pqInit must be called
|
||||
* before any operations other than pqInsert are used.
|
||||
*
|
||||
* If the heap is empty, pqMinimum/pqExtractMin will return a NULL key.
|
||||
* This may also be tested with pqIsEmpty.
|
||||
*/
|
||||
#define pqInit(pq) __gl_pqHeapInit(pq)
|
||||
#define pqInsert(pq,key) __gl_pqHeapInsert(pq,key)
|
||||
#define pqMinimum(pq) __gl_pqHeapMinimum(pq)
|
||||
#define pqExtractMin(pq) __gl_pqHeapExtractMin(pq)
|
||||
#define pqDelete(pq,handle) __gl_pqHeapDelete(pq,handle)
|
||||
#define pqIsEmpty(pq) __gl_pqHeapIsEmpty(pq)
|
||||
|
||||
|
||||
/* Since we support deletion the data structure is a little more
|
||||
* complicated than an ordinary heap. "nodes" is the heap itself;
|
||||
* active nodes are stored in the range 1..pq->size. When the
|
||||
* heap exceeds its allocated size (pq->max), its size doubles.
|
||||
* The children of node i are nodes 2i and 2i+1.
|
||||
*
|
||||
* Each node stores an index into an array "handles". Each handle
|
||||
* stores a key, plus a pointer back to the node which currently
|
||||
* represents that key (ie. nodes[handles[i].node].handle == i).
|
||||
*/
|
||||
|
||||
typedef void *PQkey;
|
||||
typedef long PQhandle;
|
||||
typedef struct PriorityQ PriorityQ;
|
||||
|
||||
typedef struct { PQhandle handle; } PQnode;
|
||||
typedef struct { PQkey key; PQhandle node; } PQhandleElem;
|
||||
|
||||
struct PriorityQ {
|
||||
PQnode *nodes;
|
||||
PQhandleElem *handles;
|
||||
long size, max;
|
||||
PQhandle freeList;
|
||||
int initialized;
|
||||
int (*leq)(PQkey key1, PQkey key2);
|
||||
};
|
||||
|
||||
PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) );
|
||||
void pqDeletePriorityQ( PriorityQ *pq );
|
||||
|
||||
void pqInit( PriorityQ *pq );
|
||||
PQhandle pqInsert( PriorityQ *pq, PQkey key );
|
||||
PQkey pqExtractMin( PriorityQ *pq );
|
||||
void pqDelete( PriorityQ *pq, PQhandle handle );
|
||||
|
||||
|
||||
#define __gl_pqHeapMinimum(pq) ((pq)->handles[(pq)->nodes[1].handle].key)
|
||||
#define __gl_pqHeapIsEmpty(pq) ((pq)->size == 0)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __priorityq_sort_h_
|
||||
#define __priorityq_sort_h_
|
||||
|
||||
#include "priorityq-heap.h"
|
||||
|
||||
#undef PQkey
|
||||
#undef PQhandle
|
||||
#undef PriorityQ
|
||||
#undef pqNewPriorityQ
|
||||
#undef pqDeletePriorityQ
|
||||
#undef pqInit
|
||||
#undef pqInsert
|
||||
#undef pqMinimum
|
||||
#undef pqExtractMin
|
||||
#undef pqDelete
|
||||
#undef pqIsEmpty
|
||||
|
||||
/* Use #define's so that another heap implementation can use this one */
|
||||
|
||||
#define PQkey PQSortKey
|
||||
#define PQhandle PQSortHandle
|
||||
#define PriorityQ PriorityQSort
|
||||
|
||||
#define pqNewPriorityQ(leq) __gl_pqSortNewPriorityQ(leq)
|
||||
#define pqDeletePriorityQ(pq) __gl_pqSortDeletePriorityQ(pq)
|
||||
|
||||
/* The basic operations are insertion of a new key (pqInsert),
|
||||
* and examination/extraction of a key whose value is minimum
|
||||
* (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete);
|
||||
* for this purpose pqInsert returns a "handle" which is supplied
|
||||
* as the argument.
|
||||
*
|
||||
* An initial heap may be created efficiently by calling pqInsert
|
||||
* repeatedly, then calling pqInit. In any case pqInit must be called
|
||||
* before any operations other than pqInsert are used.
|
||||
*
|
||||
* If the heap is empty, pqMinimum/pqExtractMin will return a NULL key.
|
||||
* This may also be tested with pqIsEmpty.
|
||||
*/
|
||||
#define pqInit(pq) __gl_pqSortInit(pq)
|
||||
#define pqInsert(pq,key) __gl_pqSortInsert(pq,key)
|
||||
#define pqMinimum(pq) __gl_pqSortMinimum(pq)
|
||||
#define pqExtractMin(pq) __gl_pqSortExtractMin(pq)
|
||||
#define pqDelete(pq,handle) __gl_pqSortDelete(pq,handle)
|
||||
#define pqIsEmpty(pq) __gl_pqSortIsEmpty(pq)
|
||||
|
||||
|
||||
/* Since we support deletion the data structure is a little more
|
||||
* complicated than an ordinary heap. "nodes" is the heap itself;
|
||||
* active nodes are stored in the range 1..pq->size. When the
|
||||
* heap exceeds its allocated size (pq->max), its size doubles.
|
||||
* The children of node i are nodes 2i and 2i+1.
|
||||
*
|
||||
* Each node stores an index into an array "handles". Each handle
|
||||
* stores a key, plus a pointer back to the node which currently
|
||||
* represents that key (ie. nodes[handles[i].node].handle == i).
|
||||
*/
|
||||
|
||||
typedef PQHeapKey PQkey;
|
||||
typedef PQHeapHandle PQhandle;
|
||||
typedef struct PriorityQ PriorityQ;
|
||||
|
||||
struct PriorityQ {
|
||||
PriorityQHeap *heap;
|
||||
PQkey *keys;
|
||||
PQkey **order;
|
||||
PQhandle size, max;
|
||||
int initialized;
|
||||
int (*leq)(PQkey key1, PQkey key2);
|
||||
};
|
||||
|
||||
PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) );
|
||||
void pqDeletePriorityQ( PriorityQ *pq );
|
||||
|
||||
int pqInit( PriorityQ *pq );
|
||||
PQhandle pqInsert( PriorityQ *pq, PQkey key );
|
||||
PQkey pqExtractMin( PriorityQ *pq );
|
||||
void pqDelete( PriorityQ *pq, PQhandle handle );
|
||||
|
||||
PQkey pqMinimum( PriorityQ *pq );
|
||||
int pqIsEmpty( PriorityQ *pq );
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gluos.h"
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h> /* LONG_MAX */
|
||||
#include "memalloc.h"
|
||||
|
||||
/* Include all the code for the regular heap-based queue here. */
|
||||
|
||||
#include "priorityq-heap.c"
|
||||
|
||||
/* Now redefine all the function names to map to their "Sort" versions. */
|
||||
|
||||
#include "priorityq-sort.h"
|
||||
|
||||
/* really __gl_pqSortNewPriorityQ */
|
||||
PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) )
|
||||
{
|
||||
PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ ));
|
||||
if (pq == NULL) return NULL;
|
||||
|
||||
pq->heap = __gl_pqHeapNewPriorityQ( leq );
|
||||
if (pq->heap == NULL) {
|
||||
memFree(pq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pq->keys = (PQHeapKey *)memAlloc( INIT_SIZE * sizeof(pq->keys[0]) );
|
||||
if (pq->keys == NULL) {
|
||||
__gl_pqHeapDeletePriorityQ(pq->heap);
|
||||
memFree(pq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pq->size = 0;
|
||||
pq->max = INIT_SIZE;
|
||||
pq->initialized = FALSE;
|
||||
pq->leq = leq;
|
||||
return pq;
|
||||
}
|
||||
|
||||
/* really __gl_pqSortDeletePriorityQ */
|
||||
void pqDeletePriorityQ( PriorityQ *pq )
|
||||
{
|
||||
assert(pq != NULL);
|
||||
if (pq->heap != NULL) __gl_pqHeapDeletePriorityQ( pq->heap );
|
||||
if (pq->order != NULL) memFree( pq->order );
|
||||
if (pq->keys != NULL) memFree( pq->keys );
|
||||
memFree( pq );
|
||||
}
|
||||
|
||||
|
||||
#define LT(x,y) (! LEQ(y,x))
|
||||
#define GT(x,y) (! LEQ(x,y))
|
||||
#define Swap(a,b) do{PQkey *tmp = *a; *a = *b; *b = tmp;}while(0)
|
||||
|
||||
/* really __gl_pqSortInit */
|
||||
int pqInit( PriorityQ *pq )
|
||||
{
|
||||
PQkey **p, **r, **i, **j, *piv;
|
||||
struct { PQkey **p, **r; } Stack[50], *top = Stack;
|
||||
unsigned long seed = 2016473283;
|
||||
|
||||
/* Create an array of indirect pointers to the keys, so that we
|
||||
* the handles we have returned are still valid.
|
||||
*/
|
||||
/*
|
||||
pq->order = (PQHeapKey **)memAlloc( (size_t)
|
||||
(pq->size * sizeof(pq->order[0])) );
|
||||
*/
|
||||
pq->order = (PQHeapKey **)memAlloc( (size_t)
|
||||
((pq->size+1) * sizeof(pq->order[0])) );
|
||||
/* the previous line is a patch to compensate for the fact that IBM */
|
||||
/* machines return a null on a malloc of zero bytes (unlike SGI), */
|
||||
/* so we have to put in this defense to guard against a memory */
|
||||
/* fault four lines down. from fossum@austin.ibm.com. */
|
||||
if (pq->order == NULL) return 0;
|
||||
|
||||
p = pq->order;
|
||||
r = p + pq->size - 1;
|
||||
for( piv = pq->keys, i = p; i <= r; ++piv, ++i ) {
|
||||
*i = piv;
|
||||
}
|
||||
|
||||
/* Sort the indirect pointers in descending order,
|
||||
* using randomized Quicksort
|
||||
*/
|
||||
top->p = p; top->r = r; ++top;
|
||||
while( --top >= Stack ) {
|
||||
p = top->p;
|
||||
r = top->r;
|
||||
while( r > p + 10 ) {
|
||||
seed = seed * 1539415821 + 1;
|
||||
i = p + seed % (r - p + 1);
|
||||
piv = *i;
|
||||
*i = *p;
|
||||
*p = piv;
|
||||
i = p - 1;
|
||||
j = r + 1;
|
||||
do {
|
||||
do { ++i; } while( GT( **i, *piv ));
|
||||
do { --j; } while( LT( **j, *piv ));
|
||||
Swap( i, j );
|
||||
} while( i < j );
|
||||
Swap( i, j ); /* Undo last swap */
|
||||
if( i - p < r - j ) {
|
||||
top->p = j+1; top->r = r; ++top;
|
||||
r = i-1;
|
||||
} else {
|
||||
top->p = p; top->r = i-1; ++top;
|
||||
p = j+1;
|
||||
}
|
||||
}
|
||||
/* Insertion sort small lists */
|
||||
for( i = p+1; i <= r; ++i ) {
|
||||
piv = *i;
|
||||
for( j = i; j > p && LT( **(j-1), *piv ); --j ) {
|
||||
*j = *(j-1);
|
||||
}
|
||||
*j = piv;
|
||||
}
|
||||
}
|
||||
pq->max = pq->size;
|
||||
pq->initialized = TRUE;
|
||||
__gl_pqHeapInit( pq->heap ); /* always succeeds */
|
||||
|
||||
#ifndef NDEBUG
|
||||
p = pq->order;
|
||||
r = p + pq->size - 1;
|
||||
for( i = p; i < r; ++i ) {
|
||||
assert( LEQ( **(i+1), **i ));
|
||||
}
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* really __gl_pqSortInsert */
|
||||
/* returns LONG_MAX iff out of memory */
|
||||
PQhandle pqInsert( PriorityQ *pq, PQkey keyNew )
|
||||
{
|
||||
long curr;
|
||||
|
||||
if( pq->initialized ) {
|
||||
return __gl_pqHeapInsert( pq->heap, keyNew );
|
||||
}
|
||||
curr = pq->size;
|
||||
if( ++ pq->size >= pq->max ) {
|
||||
PQkey *saveKey= pq->keys;
|
||||
|
||||
/* If the heap overflows, double its size. */
|
||||
pq->max <<= 1;
|
||||
pq->keys = (PQHeapKey *)memRealloc( pq->keys,
|
||||
(size_t)
|
||||
(pq->max * sizeof( pq->keys[0] )));
|
||||
if (pq->keys == NULL) {
|
||||
pq->keys = saveKey; /* restore ptr to free upon return */
|
||||
return LONG_MAX;
|
||||
}
|
||||
}
|
||||
assert(curr != LONG_MAX);
|
||||
pq->keys[curr] = keyNew;
|
||||
|
||||
/* Negative handles index the sorted array. */
|
||||
return -(curr+1);
|
||||
}
|
||||
|
||||
/* really __gl_pqSortExtractMin */
|
||||
PQkey pqExtractMin( PriorityQ *pq )
|
||||
{
|
||||
PQkey sortMin, heapMin;
|
||||
|
||||
if( pq->size == 0 ) {
|
||||
return __gl_pqHeapExtractMin( pq->heap );
|
||||
}
|
||||
sortMin = *(pq->order[pq->size-1]);
|
||||
if( ! __gl_pqHeapIsEmpty( pq->heap )) {
|
||||
heapMin = __gl_pqHeapMinimum( pq->heap );
|
||||
if( LEQ( heapMin, sortMin )) {
|
||||
return __gl_pqHeapExtractMin( pq->heap );
|
||||
}
|
||||
}
|
||||
do {
|
||||
-- pq->size;
|
||||
} while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL );
|
||||
return sortMin;
|
||||
}
|
||||
|
||||
/* really __gl_pqSortMinimum */
|
||||
PQkey pqMinimum( PriorityQ *pq )
|
||||
{
|
||||
PQkey sortMin, heapMin;
|
||||
|
||||
if( pq->size == 0 ) {
|
||||
return __gl_pqHeapMinimum( pq->heap );
|
||||
}
|
||||
sortMin = *(pq->order[pq->size-1]);
|
||||
if( ! __gl_pqHeapIsEmpty( pq->heap )) {
|
||||
heapMin = __gl_pqHeapMinimum( pq->heap );
|
||||
if( LEQ( heapMin, sortMin )) {
|
||||
return heapMin;
|
||||
}
|
||||
}
|
||||
return sortMin;
|
||||
}
|
||||
|
||||
/* really __gl_pqSortIsEmpty */
|
||||
int pqIsEmpty( PriorityQ *pq )
|
||||
{
|
||||
return (pq->size == 0) && __gl_pqHeapIsEmpty( pq->heap );
|
||||
}
|
||||
|
||||
/* really __gl_pqSortDelete */
|
||||
void pqDelete( PriorityQ *pq, PQhandle curr )
|
||||
{
|
||||
if( curr >= 0 ) {
|
||||
__gl_pqHeapDelete( pq->heap, curr );
|
||||
return;
|
||||
}
|
||||
curr = -(curr+1);
|
||||
assert( curr < pq->max && pq->keys[curr] != NULL );
|
||||
|
||||
pq->keys[curr] = NULL;
|
||||
while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL ) {
|
||||
-- pq->size;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __priorityq_sort_h_
|
||||
#define __priorityq_sort_h_
|
||||
|
||||
#include "priorityq-heap.h"
|
||||
|
||||
#undef PQkey
|
||||
#undef PQhandle
|
||||
#undef PriorityQ
|
||||
#undef pqNewPriorityQ
|
||||
#undef pqDeletePriorityQ
|
||||
#undef pqInit
|
||||
#undef pqInsert
|
||||
#undef pqMinimum
|
||||
#undef pqExtractMin
|
||||
#undef pqDelete
|
||||
#undef pqIsEmpty
|
||||
|
||||
/* Use #define's so that another heap implementation can use this one */
|
||||
|
||||
#define PQkey PQSortKey
|
||||
#define PQhandle PQSortHandle
|
||||
#define PriorityQ PriorityQSort
|
||||
|
||||
#define pqNewPriorityQ(leq) __gl_pqSortNewPriorityQ(leq)
|
||||
#define pqDeletePriorityQ(pq) __gl_pqSortDeletePriorityQ(pq)
|
||||
|
||||
/* The basic operations are insertion of a new key (pqInsert),
|
||||
* and examination/extraction of a key whose value is minimum
|
||||
* (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete);
|
||||
* for this purpose pqInsert returns a "handle" which is supplied
|
||||
* as the argument.
|
||||
*
|
||||
* An initial heap may be created efficiently by calling pqInsert
|
||||
* repeatedly, then calling pqInit. In any case pqInit must be called
|
||||
* before any operations other than pqInsert are used.
|
||||
*
|
||||
* If the heap is empty, pqMinimum/pqExtractMin will return a NULL key.
|
||||
* This may also be tested with pqIsEmpty.
|
||||
*/
|
||||
#define pqInit(pq) __gl_pqSortInit(pq)
|
||||
#define pqInsert(pq,key) __gl_pqSortInsert(pq,key)
|
||||
#define pqMinimum(pq) __gl_pqSortMinimum(pq)
|
||||
#define pqExtractMin(pq) __gl_pqSortExtractMin(pq)
|
||||
#define pqDelete(pq,handle) __gl_pqSortDelete(pq,handle)
|
||||
#define pqIsEmpty(pq) __gl_pqSortIsEmpty(pq)
|
||||
|
||||
|
||||
/* Since we support deletion the data structure is a little more
|
||||
* complicated than an ordinary heap. "nodes" is the heap itself;
|
||||
* active nodes are stored in the range 1..pq->size. When the
|
||||
* heap exceeds its allocated size (pq->max), its size doubles.
|
||||
* The children of node i are nodes 2i and 2i+1.
|
||||
*
|
||||
* Each node stores an index into an array "handles". Each handle
|
||||
* stores a key, plus a pointer back to the node which currently
|
||||
* represents that key (ie. nodes[handles[i].node].handle == i).
|
||||
*/
|
||||
|
||||
typedef PQHeapKey PQkey;
|
||||
typedef PQHeapHandle PQhandle;
|
||||
typedef struct PriorityQ PriorityQ;
|
||||
|
||||
struct PriorityQ {
|
||||
PriorityQHeap *heap;
|
||||
PQkey *keys;
|
||||
PQkey **order;
|
||||
PQhandle size, max;
|
||||
int initialized;
|
||||
int (*leq)(PQkey key1, PQkey key2);
|
||||
};
|
||||
|
||||
PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) );
|
||||
void pqDeletePriorityQ( PriorityQ *pq );
|
||||
|
||||
int pqInit( PriorityQ *pq );
|
||||
PQhandle pqInsert( PriorityQ *pq, PQkey key );
|
||||
PQkey pqExtractMin( PriorityQ *pq );
|
||||
void pqDelete( PriorityQ *pq, PQhandle handle );
|
||||
|
||||
PQkey pqMinimum( PriorityQ *pq );
|
||||
int pqIsEmpty( PriorityQ *pq );
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,502 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gluos.h"
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include "mesh.h"
|
||||
#include "tess.h"
|
||||
#include "render.h"
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
/* This structure remembers the information we need about a primitive
|
||||
* to be able to render it later, once we have determined which
|
||||
* primitive is able to use the most triangles.
|
||||
*/
|
||||
struct FaceCount {
|
||||
long size; /* number of triangles used */
|
||||
GLUhalfEdge *eStart; /* edge where this primitive starts */
|
||||
void (*render)(GLUtesselator *, GLUhalfEdge *, long);
|
||||
/* routine to render this primitive */
|
||||
};
|
||||
|
||||
static struct FaceCount MaximumFan( GLUhalfEdge *eOrig );
|
||||
static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig );
|
||||
|
||||
static void RenderFan( GLUtesselator *tess, GLUhalfEdge *eStart, long size );
|
||||
static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *eStart, long size );
|
||||
static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *eStart,
|
||||
long size );
|
||||
|
||||
static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig );
|
||||
static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *head );
|
||||
|
||||
|
||||
|
||||
/************************ Strips and Fans decomposition ******************/
|
||||
|
||||
/* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
|
||||
* fans, strips, and separate triangles. A substantial effort is made
|
||||
* to use as few rendering primitives as possible (ie. to make the fans
|
||||
* and strips as large as possible).
|
||||
*
|
||||
* The rendering output is provided as callbacks (see the api).
|
||||
*/
|
||||
void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh )
|
||||
{
|
||||
GLUface *f;
|
||||
|
||||
/* Make a list of separate triangles so we can render them all at once */
|
||||
tess->lonelyTriList = NULL;
|
||||
|
||||
for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
|
||||
f->marked = FALSE;
|
||||
}
|
||||
for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
|
||||
|
||||
/* We examine all faces in an arbitrary order. Whenever we find
|
||||
* an unprocessed face F, we output a group of faces including F
|
||||
* whose size is maximum.
|
||||
*/
|
||||
if( f->inside && ! f->marked ) {
|
||||
RenderMaximumFaceGroup( tess, f );
|
||||
assert( f->marked );
|
||||
}
|
||||
}
|
||||
if( tess->lonelyTriList != NULL ) {
|
||||
RenderLonelyTriangles( tess, tess->lonelyTriList );
|
||||
tess->lonelyTriList = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig )
|
||||
{
|
||||
/* We want to find the largest triangle fan or strip of unmarked faces
|
||||
* which includes the given face fOrig. There are 3 possible fans
|
||||
* passing through fOrig (one centered at each vertex), and 3 possible
|
||||
* strips (one for each CCW permutation of the vertices). Our strategy
|
||||
* is to try all of these, and take the primitive which uses the most
|
||||
* triangles (a greedy approach).
|
||||
*/
|
||||
GLUhalfEdge *e = fOrig->anEdge;
|
||||
struct FaceCount max, newFace;
|
||||
|
||||
max.size = 1;
|
||||
max.eStart = e;
|
||||
max.render = &RenderTriangle;
|
||||
|
||||
if( ! tess->flagBoundary ) {
|
||||
newFace = MaximumFan( e ); if( newFace.size > max.size ) { max = newFace; }
|
||||
newFace = MaximumFan( e->Lnext ); if( newFace.size > max.size ) { max = newFace; }
|
||||
newFace = MaximumFan( e->Lprev ); if( newFace.size > max.size ) { max = newFace; }
|
||||
|
||||
newFace = MaximumStrip( e ); if( newFace.size > max.size ) { max = newFace; }
|
||||
newFace = MaximumStrip( e->Lnext ); if( newFace.size > max.size ) { max = newFace; }
|
||||
newFace = MaximumStrip( e->Lprev ); if( newFace.size > max.size ) { max = newFace; }
|
||||
}
|
||||
(*(max.render))( tess, max.eStart, max.size );
|
||||
}
|
||||
|
||||
|
||||
/* Macros which keep track of faces we have marked temporarily, and allow
|
||||
* us to backtrack when necessary. With triangle fans, this is not
|
||||
* really necessary, since the only awkward case is a loop of triangles
|
||||
* around a single origin vertex. However with strips the situation is
|
||||
* more complicated, and we need a general tracking method like the
|
||||
* one here.
|
||||
*/
|
||||
#define Marked(f) (! (f)->inside || (f)->marked)
|
||||
|
||||
#define AddToTrail(f,t) ((f)->trail = (t), (t) = (f), (f)->marked = TRUE)
|
||||
|
||||
#define FreeTrail(t) do { \
|
||||
while( (t) != NULL ) { \
|
||||
(t)->marked = FALSE; t = (t)->trail; \
|
||||
} \
|
||||
} while(0) /* absorb trailing semicolon */
|
||||
|
||||
|
||||
|
||||
static struct FaceCount MaximumFan( GLUhalfEdge *eOrig )
|
||||
{
|
||||
/* eOrig->Lface is the face we want to render. We want to find the size
|
||||
* of a maximal fan around eOrig->Org. To do this we just walk around
|
||||
* the origin vertex as far as possible in both directions.
|
||||
*/
|
||||
struct FaceCount newFace = { 0, NULL, &RenderFan };
|
||||
GLUface *trail = NULL;
|
||||
GLUhalfEdge *e;
|
||||
|
||||
for( e = eOrig; ! Marked( e->Lface ); e = e->Onext ) {
|
||||
AddToTrail( e->Lface, trail );
|
||||
++newFace.size;
|
||||
}
|
||||
for( e = eOrig; ! Marked( e->Rface ); e = e->Oprev ) {
|
||||
AddToTrail( e->Rface, trail );
|
||||
++newFace.size;
|
||||
}
|
||||
newFace.eStart = e;
|
||||
/*LINTED*/
|
||||
FreeTrail( trail );
|
||||
return newFace;
|
||||
}
|
||||
|
||||
|
||||
#define IsEven(n) (((n) & 1) == 0)
|
||||
|
||||
static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig )
|
||||
{
|
||||
/* Here we are looking for a maximal strip that contains the vertices
|
||||
* eOrig->Org, eOrig->Dst, eOrig->Lnext->Dst (in that order or the
|
||||
* reverse, such that all triangles are oriented CCW).
|
||||
*
|
||||
* Again we walk forward and backward as far as possible. However for
|
||||
* strips there is a twist: to get CCW orientations, there must be
|
||||
* an *even* number of triangles in the strip on one side of eOrig.
|
||||
* We walk the strip starting on a side with an even number of triangles;
|
||||
* if both side have an odd number, we are forced to shorten one side.
|
||||
*/
|
||||
struct FaceCount newFace = { 0, NULL, &RenderStrip };
|
||||
long headSize = 0, tailSize = 0;
|
||||
GLUface *trail = NULL;
|
||||
GLUhalfEdge *e, *eTail, *eHead;
|
||||
|
||||
for( e = eOrig; ! Marked( e->Lface ); ++tailSize, e = e->Onext ) {
|
||||
AddToTrail( e->Lface, trail );
|
||||
++tailSize;
|
||||
e = e->Dprev;
|
||||
if( Marked( e->Lface )) break;
|
||||
AddToTrail( e->Lface, trail );
|
||||
}
|
||||
eTail = e;
|
||||
|
||||
for( e = eOrig; ! Marked( e->Rface ); ++headSize, e = e->Dnext ) {
|
||||
AddToTrail( e->Rface, trail );
|
||||
++headSize;
|
||||
e = e->Oprev;
|
||||
if( Marked( e->Rface )) break;
|
||||
AddToTrail( e->Rface, trail );
|
||||
}
|
||||
eHead = e;
|
||||
|
||||
newFace.size = tailSize + headSize;
|
||||
if( IsEven( tailSize )) {
|
||||
newFace.eStart = eTail->Sym;
|
||||
} else if( IsEven( headSize )) {
|
||||
newFace.eStart = eHead;
|
||||
} else {
|
||||
/* Both sides have odd length, we must shorten one of them. In fact,
|
||||
* we must start from eHead to guarantee inclusion of eOrig->Lface.
|
||||
*/
|
||||
--newFace.size;
|
||||
newFace.eStart = eHead->Onext;
|
||||
}
|
||||
/*LINTED*/
|
||||
FreeTrail( trail );
|
||||
return newFace;
|
||||
}
|
||||
|
||||
|
||||
static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *e, long size )
|
||||
{
|
||||
/* Just add the triangle to a triangle list, so we can render all
|
||||
* the separate triangles at once.
|
||||
*/
|
||||
assert( size == 1 );
|
||||
AddToTrail( e->Lface, tess->lonelyTriList );
|
||||
}
|
||||
|
||||
|
||||
static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *f )
|
||||
{
|
||||
/* Now we render all the separate triangles which could not be
|
||||
* grouped into a triangle fan or strip.
|
||||
*/
|
||||
GLUhalfEdge *e;
|
||||
int newState;
|
||||
int edgeState = -1; /* force edge state output for first vertex */
|
||||
|
||||
CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLES );
|
||||
|
||||
for( ; f != NULL; f = f->trail ) {
|
||||
/* Loop once for each edge (there will always be 3 edges) */
|
||||
|
||||
e = f->anEdge;
|
||||
do {
|
||||
if( tess->flagBoundary ) {
|
||||
/* Set the "edge state" to TRUE just before we output the
|
||||
* first vertex of each edge on the polygon boundary.
|
||||
*/
|
||||
newState = ! e->Rface->inside;
|
||||
if( edgeState != newState ) {
|
||||
edgeState = newState;
|
||||
CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA( edgeState );
|
||||
}
|
||||
}
|
||||
CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
|
||||
|
||||
e = e->Lnext;
|
||||
} while( e != f->anEdge );
|
||||
}
|
||||
CALL_END_OR_END_DATA();
|
||||
}
|
||||
|
||||
|
||||
static void RenderFan( GLUtesselator *tess, GLUhalfEdge *e, long size )
|
||||
{
|
||||
/* Render as many CCW triangles as possible in a fan starting from
|
||||
* edge "e". The fan *should* contain exactly "size" triangles
|
||||
* (otherwise we've goofed up somewhere).
|
||||
*/
|
||||
CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_FAN );
|
||||
CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
|
||||
CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
|
||||
|
||||
while( ! Marked( e->Lface )) {
|
||||
e->Lface->marked = TRUE;
|
||||
--size;
|
||||
e = e->Onext;
|
||||
CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
|
||||
}
|
||||
|
||||
assert( size == 0 );
|
||||
CALL_END_OR_END_DATA();
|
||||
}
|
||||
|
||||
|
||||
static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *e, long size )
|
||||
{
|
||||
/* Render as many CCW triangles as possible in a strip starting from
|
||||
* edge "e". The strip *should* contain exactly "size" triangles
|
||||
* (otherwise we've goofed up somewhere).
|
||||
*/
|
||||
CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_STRIP );
|
||||
CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
|
||||
CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
|
||||
|
||||
while( ! Marked( e->Lface )) {
|
||||
e->Lface->marked = TRUE;
|
||||
--size;
|
||||
e = e->Dprev;
|
||||
CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
|
||||
if( Marked( e->Lface )) break;
|
||||
|
||||
e->Lface->marked = TRUE;
|
||||
--size;
|
||||
e = e->Onext;
|
||||
CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
|
||||
}
|
||||
|
||||
assert( size == 0 );
|
||||
CALL_END_OR_END_DATA();
|
||||
}
|
||||
|
||||
|
||||
/************************ Boundary contour decomposition ******************/
|
||||
|
||||
/* __gl_renderBoundary( tess, mesh ) takes a mesh, and outputs one
|
||||
* contour for each face marked "inside". The rendering output is
|
||||
* provided as callbacks (see the api).
|
||||
*/
|
||||
void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh )
|
||||
{
|
||||
GLUface *f;
|
||||
GLUhalfEdge *e;
|
||||
|
||||
for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
|
||||
if( f->inside ) {
|
||||
CALL_BEGIN_OR_BEGIN_DATA( GL_LINE_LOOP );
|
||||
e = f->anEdge;
|
||||
do {
|
||||
CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
|
||||
e = e->Lnext;
|
||||
} while( e != f->anEdge );
|
||||
CALL_END_OR_END_DATA();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/************************ Quick-and-dirty decomposition ******************/
|
||||
|
||||
#define SIGN_INCONSISTENT 2
|
||||
|
||||
static int ComputeNormal( GLUtesselator *tess, GLdouble norm[3], int check )
|
||||
/*
|
||||
* If check==FALSE, we compute the polygon normal and place it in norm[].
|
||||
* If check==TRUE, we check that each triangle in the fan from v0 has a
|
||||
* consistent orientation with respect to norm[]. If triangles are
|
||||
* consistently oriented CCW, return 1; if CW, return -1; if all triangles
|
||||
* are degenerate return 0; otherwise (no consistent orientation) return
|
||||
* SIGN_INCONSISTENT.
|
||||
*/
|
||||
{
|
||||
CachedVertex *v0 = tess->cache;
|
||||
CachedVertex *vn = v0 + tess->cacheCount;
|
||||
CachedVertex *vc;
|
||||
GLdouble dot, xc, yc, zc, xp, yp, zp, n[3];
|
||||
int sign = 0;
|
||||
|
||||
/* Find the polygon normal. It is important to get a reasonable
|
||||
* normal even when the polygon is self-intersecting (eg. a bowtie).
|
||||
* Otherwise, the computed normal could be very tiny, but perpendicular
|
||||
* to the true plane of the polygon due to numerical noise. Then all
|
||||
* the triangles would appear to be degenerate and we would incorrectly
|
||||
* decompose the polygon as a fan (or simply not render it at all).
|
||||
*
|
||||
* We use a sum-of-triangles normal algorithm rather than the more
|
||||
* efficient sum-of-trapezoids method (used in CheckOrientation()
|
||||
* in normal.c). This lets us explicitly reverse the signed area
|
||||
* of some triangles to get a reasonable normal in the self-intersecting
|
||||
* case.
|
||||
*/
|
||||
if( ! check ) {
|
||||
norm[0] = norm[1] = norm[2] = 0.0;
|
||||
}
|
||||
|
||||
vc = v0 + 1;
|
||||
xc = vc->coords[0] - v0->coords[0];
|
||||
yc = vc->coords[1] - v0->coords[1];
|
||||
zc = vc->coords[2] - v0->coords[2];
|
||||
while( ++vc < vn ) {
|
||||
xp = xc; yp = yc; zp = zc;
|
||||
xc = vc->coords[0] - v0->coords[0];
|
||||
yc = vc->coords[1] - v0->coords[1];
|
||||
zc = vc->coords[2] - v0->coords[2];
|
||||
|
||||
/* Compute (vp - v0) cross (vc - v0) */
|
||||
n[0] = yp*zc - zp*yc;
|
||||
n[1] = zp*xc - xp*zc;
|
||||
n[2] = xp*yc - yp*xc;
|
||||
|
||||
dot = n[0]*norm[0] + n[1]*norm[1] + n[2]*norm[2];
|
||||
if( ! check ) {
|
||||
/* Reverse the contribution of back-facing triangles to get
|
||||
* a reasonable normal for self-intersecting polygons (see above)
|
||||
*/
|
||||
if( dot >= 0 ) {
|
||||
norm[0] += n[0]; norm[1] += n[1]; norm[2] += n[2];
|
||||
} else {
|
||||
norm[0] -= n[0]; norm[1] -= n[1]; norm[2] -= n[2];
|
||||
}
|
||||
} else if( dot != 0 ) {
|
||||
/* Check the new orientation for consistency with previous triangles */
|
||||
if( dot > 0 ) {
|
||||
if( sign < 0 ) return SIGN_INCONSISTENT;
|
||||
sign = 1;
|
||||
} else {
|
||||
if( sign > 0 ) return SIGN_INCONSISTENT;
|
||||
sign = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return sign;
|
||||
}
|
||||
|
||||
/* __gl_renderCache( tess ) takes a single contour and tries to render it
|
||||
* as a triangle fan. This handles convex polygons, as well as some
|
||||
* non-convex polygons if we get lucky.
|
||||
*
|
||||
* Returns TRUE if the polygon was successfully rendered. The rendering
|
||||
* output is provided as callbacks (see the api).
|
||||
*/
|
||||
GLboolean __gl_renderCache( GLUtesselator *tess )
|
||||
{
|
||||
CachedVertex *v0 = tess->cache;
|
||||
CachedVertex *vn = v0 + tess->cacheCount;
|
||||
CachedVertex *vc;
|
||||
GLdouble norm[3];
|
||||
int sign;
|
||||
|
||||
if( tess->cacheCount < 3 ) {
|
||||
/* Degenerate contour -- no output */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
norm[0] = tess->normal[0];
|
||||
norm[1] = tess->normal[1];
|
||||
norm[2] = tess->normal[2];
|
||||
if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) {
|
||||
ComputeNormal( tess, norm, FALSE );
|
||||
}
|
||||
|
||||
sign = ComputeNormal( tess, norm, TRUE );
|
||||
if( sign == SIGN_INCONSISTENT ) {
|
||||
/* Fan triangles did not have a consistent orientation */
|
||||
return FALSE;
|
||||
}
|
||||
if( sign == 0 ) {
|
||||
/* All triangles were degenerate */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Make sure we do the right thing for each winding rule */
|
||||
switch( tess->windingRule ) {
|
||||
case GLU_TESS_WINDING_ODD:
|
||||
case GLU_TESS_WINDING_NONZERO:
|
||||
break;
|
||||
case GLU_TESS_WINDING_POSITIVE:
|
||||
if( sign < 0 ) return TRUE;
|
||||
break;
|
||||
case GLU_TESS_WINDING_NEGATIVE:
|
||||
if( sign > 0 ) return TRUE;
|
||||
break;
|
||||
case GLU_TESS_WINDING_ABS_GEQ_TWO:
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
CALL_BEGIN_OR_BEGIN_DATA( tess->boundaryOnly ? GL_LINE_LOOP
|
||||
: (tess->cacheCount > 3) ? GL_TRIANGLE_FAN
|
||||
: GL_TRIANGLES );
|
||||
|
||||
CALL_VERTEX_OR_VERTEX_DATA( v0->data );
|
||||
if( sign > 0 ) {
|
||||
for( vc = v0+1; vc < vn; ++vc ) {
|
||||
CALL_VERTEX_OR_VERTEX_DATA( vc->data );
|
||||
}
|
||||
} else {
|
||||
for( vc = vn-1; vc > v0; --vc ) {
|
||||
CALL_VERTEX_OR_VERTEX_DATA( vc->data );
|
||||
}
|
||||
}
|
||||
CALL_END_OR_END_DATA();
|
||||
return TRUE;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __render_h_
|
||||
#define __render_h_
|
||||
|
||||
#include "mesh.h"
|
||||
|
||||
/* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
|
||||
* fans, strips, and separate triangles. A substantial effort is made
|
||||
* to use as few rendering primitives as possible (ie. to make the fans
|
||||
* and strips as large as possible).
|
||||
*
|
||||
* The rendering output is provided as callbacks (see the api).
|
||||
*/
|
||||
void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh );
|
||||
void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh );
|
||||
|
||||
GLboolean __gl_renderCache( GLUtesselator *tess );
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __sweep_h_
|
||||
#define __sweep_h_
|
||||
|
||||
#include "mesh.h"
|
||||
|
||||
/* __gl_computeInterior( tess ) computes the planar arrangement specified
|
||||
* by the given contours, and further subdivides this arrangement
|
||||
* into regions. Each region is marked "inside" if it belongs
|
||||
* to the polygon, according to the rule given by tess->windingRule.
|
||||
* Each interior region is guaranteed be monotone.
|
||||
*/
|
||||
int __gl_computeInterior( GLUtesselator *tess );
|
||||
|
||||
|
||||
/* The following is here *only* for access by debugging routines */
|
||||
|
||||
#include "dict.h"
|
||||
|
||||
/* For each pair of adjacent edges crossing the sweep line, there is
|
||||
* an ActiveRegion to represent the region between them. The active
|
||||
* regions are kept in sorted order in a dynamic dictionary. As the
|
||||
* sweep line crosses each vertex, we update the affected regions.
|
||||
*/
|
||||
|
||||
struct ActiveRegion {
|
||||
GLUhalfEdge *eUp; /* upper edge, directed right to left */
|
||||
DictNode *nodeUp; /* dictionary node corresponding to eUp */
|
||||
int windingNumber; /* used to determine which regions are
|
||||
* inside the polygon */
|
||||
GLboolean inside; /* is this region inside the polygon? */
|
||||
GLboolean sentinel; /* marks fake edges at t = +/-infinity */
|
||||
GLboolean dirty; /* marks regions where the upper or lower
|
||||
* edge has changed, but we haven't checked
|
||||
* whether they intersect yet */
|
||||
GLboolean fixUpperEdge; /* marks temporary edges introduced when
|
||||
* we process a "right vertex" (one without
|
||||
* any edges leaving to the right) */
|
||||
};
|
||||
|
||||
#define RegionBelow(r) ((ActiveRegion *) dictKey(dictPred((r)->nodeUp)))
|
||||
#define RegionAbove(r) ((ActiveRegion *) dictKey(dictSucc((r)->nodeUp)))
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,632 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gluos.h"
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
#include <setjmp.h>
|
||||
#include "memalloc.h"
|
||||
#include "tess.h"
|
||||
#include "mesh.h"
|
||||
#include "normal.h"
|
||||
#include "sweep.h"
|
||||
#include "tessmono.h"
|
||||
#include "render.h"
|
||||
|
||||
#define GLU_TESS_DEFAULT_TOLERANCE 0.0
|
||||
#define GLU_TESS_MESH 100112 /* void (*)(GLUmesh *mesh) */
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
/*ARGSUSED*/ static void GLAPIENTRY noBegin( GLenum type ) {}
|
||||
/*ARGSUSED*/ static void GLAPIENTRY noEdgeFlag( GLboolean boundaryEdge ) {}
|
||||
/*ARGSUSED*/ static void GLAPIENTRY noVertex( void *data ) {}
|
||||
/*ARGSUSED*/ static void GLAPIENTRY noEnd( void ) {}
|
||||
/*ARGSUSED*/ static void GLAPIENTRY noError( GLenum errnum ) {}
|
||||
/*ARGSUSED*/ static void GLAPIENTRY noCombine( GLdouble coords[3], void *data[4],
|
||||
GLfloat weight[4], void **dataOut ) {}
|
||||
/*ARGSUSED*/ static void GLAPIENTRY noMesh( GLUmesh *mesh ) {}
|
||||
|
||||
|
||||
/*ARGSUSED*/ void GLAPIENTRY __gl_noBeginData( GLenum type,
|
||||
void *polygonData ) {}
|
||||
/*ARGSUSED*/ void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge,
|
||||
void *polygonData ) {}
|
||||
/*ARGSUSED*/ void GLAPIENTRY __gl_noVertexData( void *data,
|
||||
void *polygonData ) {}
|
||||
/*ARGSUSED*/ void GLAPIENTRY __gl_noEndData( void *polygonData ) {}
|
||||
/*ARGSUSED*/ void GLAPIENTRY __gl_noErrorData( GLenum errnum,
|
||||
void *polygonData ) {}
|
||||
/*ARGSUSED*/ void GLAPIENTRY __gl_noCombineData( GLdouble coords[3],
|
||||
void *data[4],
|
||||
GLfloat weight[4],
|
||||
void **outData,
|
||||
void *polygonData ) {}
|
||||
|
||||
/* Half-edges are allocated in pairs (see mesh.c) */
|
||||
typedef struct { GLUhalfEdge e, eSym; } EdgePair;
|
||||
|
||||
#undef MAX
|
||||
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
#define MAX_FAST_ALLOC (MAX(sizeof(EdgePair), \
|
||||
MAX(sizeof(GLUvertex),sizeof(GLUface))))
|
||||
|
||||
|
||||
GLUtesselator * GLAPIENTRY
|
||||
gluNewTess( void )
|
||||
{
|
||||
GLUtesselator *tess;
|
||||
|
||||
/* Only initialize fields which can be changed by the api. Other fields
|
||||
* are initialized where they are used.
|
||||
*/
|
||||
|
||||
if (memInit( MAX_FAST_ALLOC ) == 0) {
|
||||
return 0; /* out of memory */
|
||||
}
|
||||
tess = (GLUtesselator *)memAlloc( sizeof( GLUtesselator ));
|
||||
if (tess == NULL) {
|
||||
return 0; /* out of memory */
|
||||
}
|
||||
|
||||
tess->state = T_DORMANT;
|
||||
|
||||
tess->normal[0] = 0;
|
||||
tess->normal[1] = 0;
|
||||
tess->normal[2] = 0;
|
||||
|
||||
tess->relTolerance = GLU_TESS_DEFAULT_TOLERANCE;
|
||||
tess->windingRule = GLU_TESS_WINDING_ODD;
|
||||
tess->flagBoundary = FALSE;
|
||||
tess->boundaryOnly = FALSE;
|
||||
|
||||
tess->callBegin = &noBegin;
|
||||
tess->callEdgeFlag = &noEdgeFlag;
|
||||
tess->callVertex = &noVertex;
|
||||
tess->callEnd = &noEnd;
|
||||
|
||||
tess->callError = &noError;
|
||||
tess->callCombine = &noCombine;
|
||||
tess->callMesh = &noMesh;
|
||||
|
||||
tess->callBeginData= &__gl_noBeginData;
|
||||
tess->callEdgeFlagData= &__gl_noEdgeFlagData;
|
||||
tess->callVertexData= &__gl_noVertexData;
|
||||
tess->callEndData= &__gl_noEndData;
|
||||
tess->callErrorData= &__gl_noErrorData;
|
||||
tess->callCombineData= &__gl_noCombineData;
|
||||
|
||||
tess->polygonData= NULL;
|
||||
|
||||
return tess;
|
||||
}
|
||||
|
||||
static void MakeDormant( GLUtesselator *tess )
|
||||
{
|
||||
/* Return the tessellator to its original dormant state. */
|
||||
|
||||
if( tess->mesh != NULL ) {
|
||||
__gl_meshDeleteMesh( tess->mesh );
|
||||
}
|
||||
tess->state = T_DORMANT;
|
||||
tess->lastEdge = NULL;
|
||||
tess->mesh = NULL;
|
||||
}
|
||||
|
||||
#define RequireState( tess, s ) if( tess->state != s ) GotoState(tess,s)
|
||||
|
||||
static void GotoState( GLUtesselator *tess, enum TessState newState )
|
||||
{
|
||||
while( tess->state != newState ) {
|
||||
/* We change the current state one level at a time, to get to
|
||||
* the desired state.
|
||||
*/
|
||||
if( tess->state < newState ) {
|
||||
switch( tess->state ) {
|
||||
case T_DORMANT:
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_POLYGON );
|
||||
gluTessBeginPolygon( tess, NULL );
|
||||
break;
|
||||
case T_IN_POLYGON:
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_CONTOUR );
|
||||
gluTessBeginContour( tess );
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
} else {
|
||||
switch( tess->state ) {
|
||||
case T_IN_CONTOUR:
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_CONTOUR );
|
||||
gluTessEndContour( tess );
|
||||
break;
|
||||
case T_IN_POLYGON:
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_POLYGON );
|
||||
/* gluTessEndPolygon( tess ) is too much work! */
|
||||
MakeDormant( tess );
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GLAPIENTRY
|
||||
gluDeleteTess( GLUtesselator *tess )
|
||||
{
|
||||
RequireState( tess, T_DORMANT );
|
||||
memFree( tess );
|
||||
}
|
||||
|
||||
|
||||
void GLAPIENTRY
|
||||
gluTessProperty( GLUtesselator *tess, GLenum which, GLdouble value )
|
||||
{
|
||||
GLenum windingRule;
|
||||
|
||||
switch( which ) {
|
||||
case GLU_TESS_TOLERANCE:
|
||||
if( value < 0.0 || value > 1.0 ) break;
|
||||
tess->relTolerance = value;
|
||||
return;
|
||||
|
||||
case GLU_TESS_WINDING_RULE:
|
||||
windingRule = (GLenum) value;
|
||||
if( windingRule != value ) break; /* not an integer */
|
||||
|
||||
switch( windingRule ) {
|
||||
case GLU_TESS_WINDING_ODD:
|
||||
case GLU_TESS_WINDING_NONZERO:
|
||||
case GLU_TESS_WINDING_POSITIVE:
|
||||
case GLU_TESS_WINDING_NEGATIVE:
|
||||
case GLU_TESS_WINDING_ABS_GEQ_TWO:
|
||||
tess->windingRule = windingRule;
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
case GLU_TESS_BOUNDARY_ONLY:
|
||||
tess->boundaryOnly = (value != 0);
|
||||
return;
|
||||
|
||||
default:
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
|
||||
return;
|
||||
}
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_VALUE );
|
||||
}
|
||||
|
||||
/* Returns tessellator property */
|
||||
void GLAPIENTRY
|
||||
gluGetTessProperty( GLUtesselator *tess, GLenum which, GLdouble *value )
|
||||
{
|
||||
switch (which) {
|
||||
case GLU_TESS_TOLERANCE:
|
||||
/* tolerance should be in range [0..1] */
|
||||
assert(0.0 <= tess->relTolerance && tess->relTolerance <= 1.0);
|
||||
*value= tess->relTolerance;
|
||||
break;
|
||||
case GLU_TESS_WINDING_RULE:
|
||||
assert(tess->windingRule == GLU_TESS_WINDING_ODD ||
|
||||
tess->windingRule == GLU_TESS_WINDING_NONZERO ||
|
||||
tess->windingRule == GLU_TESS_WINDING_POSITIVE ||
|
||||
tess->windingRule == GLU_TESS_WINDING_NEGATIVE ||
|
||||
tess->windingRule == GLU_TESS_WINDING_ABS_GEQ_TWO);
|
||||
*value= tess->windingRule;
|
||||
break;
|
||||
case GLU_TESS_BOUNDARY_ONLY:
|
||||
assert(tess->boundaryOnly == TRUE || tess->boundaryOnly == FALSE);
|
||||
*value= tess->boundaryOnly;
|
||||
break;
|
||||
default:
|
||||
*value= 0.0;
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
|
||||
break;
|
||||
}
|
||||
} /* gluGetTessProperty() */
|
||||
|
||||
void GLAPIENTRY
|
||||
gluTessNormal( GLUtesselator *tess, GLdouble x, GLdouble y, GLdouble z )
|
||||
{
|
||||
tess->normal[0] = x;
|
||||
tess->normal[1] = y;
|
||||
tess->normal[2] = z;
|
||||
}
|
||||
|
||||
void GLAPIENTRY
|
||||
gluTessCallback( GLUtesselator *tess, GLenum which, _GLUfuncptr fn)
|
||||
{
|
||||
switch( which ) {
|
||||
case GLU_TESS_BEGIN:
|
||||
tess->callBegin = (fn == NULL) ? &noBegin : (void (GLAPIENTRY *)(GLenum)) fn;
|
||||
return;
|
||||
case GLU_TESS_BEGIN_DATA:
|
||||
tess->callBeginData = (fn == NULL) ?
|
||||
&__gl_noBeginData : (void (GLAPIENTRY *)(GLenum, void *)) fn;
|
||||
return;
|
||||
case GLU_TESS_EDGE_FLAG:
|
||||
tess->callEdgeFlag = (fn == NULL) ? &noEdgeFlag :
|
||||
(void (GLAPIENTRY *)(GLboolean)) fn;
|
||||
/* If the client wants boundary edges to be flagged,
|
||||
* we render everything as separate triangles (no strips or fans).
|
||||
*/
|
||||
tess->flagBoundary = (fn != NULL);
|
||||
return;
|
||||
case GLU_TESS_EDGE_FLAG_DATA:
|
||||
tess->callEdgeFlagData= (fn == NULL) ?
|
||||
&__gl_noEdgeFlagData : (void (GLAPIENTRY *)(GLboolean, void *)) fn;
|
||||
/* If the client wants boundary edges to be flagged,
|
||||
* we render everything as separate triangles (no strips or fans).
|
||||
*/
|
||||
tess->flagBoundary = (fn != NULL);
|
||||
return;
|
||||
case GLU_TESS_VERTEX:
|
||||
tess->callVertex = (fn == NULL) ? &noVertex :
|
||||
(void (GLAPIENTRY *)(void *)) fn;
|
||||
return;
|
||||
case GLU_TESS_VERTEX_DATA:
|
||||
tess->callVertexData = (fn == NULL) ?
|
||||
&__gl_noVertexData : (void (GLAPIENTRY *)(void *, void *)) fn;
|
||||
return;
|
||||
case GLU_TESS_END:
|
||||
tess->callEnd = (fn == NULL) ? &noEnd : (void (GLAPIENTRY *)(void)) fn;
|
||||
return;
|
||||
case GLU_TESS_END_DATA:
|
||||
tess->callEndData = (fn == NULL) ? &__gl_noEndData :
|
||||
(void (GLAPIENTRY *)(void *)) fn;
|
||||
return;
|
||||
case GLU_TESS_ERROR:
|
||||
tess->callError = (fn == NULL) ? &noError : (void (GLAPIENTRY *)(GLenum)) fn;
|
||||
return;
|
||||
case GLU_TESS_ERROR_DATA:
|
||||
tess->callErrorData = (fn == NULL) ?
|
||||
&__gl_noErrorData : (void (GLAPIENTRY *)(GLenum, void *)) fn;
|
||||
return;
|
||||
case GLU_TESS_COMBINE:
|
||||
tess->callCombine = (fn == NULL) ? &noCombine :
|
||||
(void (GLAPIENTRY *)(GLdouble [3],void *[4], GLfloat [4], void ** )) fn;
|
||||
return;
|
||||
case GLU_TESS_COMBINE_DATA:
|
||||
tess->callCombineData = (fn == NULL) ? &__gl_noCombineData :
|
||||
(void (GLAPIENTRY *)(GLdouble [3],
|
||||
void *[4],
|
||||
GLfloat [4],
|
||||
void **,
|
||||
void *)) fn;
|
||||
return;
|
||||
case GLU_TESS_MESH:
|
||||
tess->callMesh = (fn == NULL) ? &noMesh : (void (GLAPIENTRY *)(GLUmesh *)) fn;
|
||||
return;
|
||||
default:
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int AddVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
|
||||
{
|
||||
GLUhalfEdge *e;
|
||||
|
||||
e = tess->lastEdge;
|
||||
if( e == NULL ) {
|
||||
/* Make a self-loop (one vertex, one edge). */
|
||||
|
||||
e = __gl_meshMakeEdge( tess->mesh );
|
||||
if (e == NULL) return 0;
|
||||
if ( !__gl_meshSplice( e, e->Sym ) ) return 0;
|
||||
} else {
|
||||
/* Create a new vertex and edge which immediately follow e
|
||||
* in the ordering around the left face.
|
||||
*/
|
||||
if (__gl_meshSplitEdge( e ) == NULL) return 0;
|
||||
e = e->Lnext;
|
||||
}
|
||||
|
||||
/* The new vertex is now e->Org. */
|
||||
e->Org->data = data;
|
||||
e->Org->coords[0] = coords[0];
|
||||
e->Org->coords[1] = coords[1];
|
||||
e->Org->coords[2] = coords[2];
|
||||
|
||||
/* The winding of an edge says how the winding number changes as we
|
||||
* cross from the edge''s right face to its left face. We add the
|
||||
* vertices in such an order that a CCW contour will add +1 to
|
||||
* the winding number of the region inside the contour.
|
||||
*/
|
||||
e->winding = 1;
|
||||
e->Sym->winding = -1;
|
||||
|
||||
tess->lastEdge = e;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void CacheVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
|
||||
{
|
||||
CachedVertex *v = &tess->cache[tess->cacheCount];
|
||||
|
||||
v->data = data;
|
||||
v->coords[0] = coords[0];
|
||||
v->coords[1] = coords[1];
|
||||
v->coords[2] = coords[2];
|
||||
++tess->cacheCount;
|
||||
}
|
||||
|
||||
|
||||
static int EmptyCache( GLUtesselator *tess )
|
||||
{
|
||||
CachedVertex *v = tess->cache;
|
||||
CachedVertex *vLast;
|
||||
|
||||
tess->mesh = __gl_meshNewMesh();
|
||||
if (tess->mesh == NULL) return 0;
|
||||
|
||||
for( vLast = v + tess->cacheCount; v < vLast; ++v ) {
|
||||
if ( !AddVertex( tess, v->coords, v->data ) ) return 0;
|
||||
}
|
||||
tess->cacheCount = 0;
|
||||
tess->emptyCache = FALSE;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void GLAPIENTRY
|
||||
gluTessVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
|
||||
{
|
||||
int i, tooLarge = FALSE;
|
||||
GLdouble x, clamped[3];
|
||||
|
||||
RequireState( tess, T_IN_CONTOUR );
|
||||
|
||||
if( tess->emptyCache ) {
|
||||
if ( !EmptyCache( tess ) ) {
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
|
||||
return;
|
||||
}
|
||||
tess->lastEdge = NULL;
|
||||
}
|
||||
for( i = 0; i < 3; ++i ) {
|
||||
x = coords[i];
|
||||
if( x < - GLU_TESS_MAX_COORD ) {
|
||||
x = - GLU_TESS_MAX_COORD;
|
||||
tooLarge = TRUE;
|
||||
}
|
||||
if( x > GLU_TESS_MAX_COORD ) {
|
||||
x = GLU_TESS_MAX_COORD;
|
||||
tooLarge = TRUE;
|
||||
}
|
||||
clamped[i] = x;
|
||||
}
|
||||
if( tooLarge ) {
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_TESS_COORD_TOO_LARGE );
|
||||
}
|
||||
|
||||
if( tess->mesh == NULL ) {
|
||||
if( tess->cacheCount < TESS_MAX_CACHE ) {
|
||||
CacheVertex( tess, clamped, data );
|
||||
return;
|
||||
}
|
||||
if ( !EmptyCache( tess ) ) {
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ( !AddVertex( tess, clamped, data ) ) {
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GLAPIENTRY
|
||||
gluTessBeginPolygon( GLUtesselator *tess, void *data )
|
||||
{
|
||||
RequireState( tess, T_DORMANT );
|
||||
|
||||
tess->state = T_IN_POLYGON;
|
||||
tess->cacheCount = 0;
|
||||
tess->emptyCache = FALSE;
|
||||
tess->mesh = NULL;
|
||||
|
||||
tess->polygonData= data;
|
||||
}
|
||||
|
||||
|
||||
void GLAPIENTRY
|
||||
gluTessBeginContour( GLUtesselator *tess )
|
||||
{
|
||||
RequireState( tess, T_IN_POLYGON );
|
||||
|
||||
tess->state = T_IN_CONTOUR;
|
||||
tess->lastEdge = NULL;
|
||||
if( tess->cacheCount > 0 ) {
|
||||
/* Just set a flag so we don't get confused by empty contours
|
||||
* -- these can be generated accidentally with the obsolete
|
||||
* NextContour() interface.
|
||||
*/
|
||||
tess->emptyCache = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GLAPIENTRY
|
||||
gluTessEndContour( GLUtesselator *tess )
|
||||
{
|
||||
RequireState( tess, T_IN_CONTOUR );
|
||||
tess->state = T_IN_POLYGON;
|
||||
}
|
||||
|
||||
void GLAPIENTRY
|
||||
gluTessEndPolygon( GLUtesselator *tess )
|
||||
{
|
||||
GLUmesh *mesh;
|
||||
|
||||
if (setjmp(tess->env) != 0) {
|
||||
/* come back here if out of memory */
|
||||
CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
|
||||
return;
|
||||
}
|
||||
|
||||
RequireState( tess, T_IN_POLYGON );
|
||||
tess->state = T_DORMANT;
|
||||
|
||||
if( tess->mesh == NULL ) {
|
||||
if( ! tess->flagBoundary && tess->callMesh == &noMesh ) {
|
||||
|
||||
/* Try some special code to make the easy cases go quickly
|
||||
* (eg. convex polygons). This code does NOT handle multiple contours,
|
||||
* intersections, edge flags, and of course it does not generate
|
||||
* an explicit mesh either.
|
||||
*/
|
||||
if( __gl_renderCache( tess )) {
|
||||
tess->polygonData= NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ( !EmptyCache( tess ) ) longjmp(tess->env,1); /* could've used a label*/
|
||||
}
|
||||
|
||||
/* Determine the polygon normal and project vertices onto the plane
|
||||
* of the polygon.
|
||||
*/
|
||||
__gl_projectPolygon( tess );
|
||||
|
||||
/* __gl_computeInterior( tess ) computes the planar arrangement specified
|
||||
* by the given contours, and further subdivides this arrangement
|
||||
* into regions. Each region is marked "inside" if it belongs
|
||||
* to the polygon, according to the rule given by tess->windingRule.
|
||||
* Each interior region is guaranteed be monotone.
|
||||
*/
|
||||
if ( !__gl_computeInterior( tess ) ) {
|
||||
longjmp(tess->env,1); /* could've used a label */
|
||||
}
|
||||
|
||||
mesh = tess->mesh;
|
||||
if( ! tess->fatalError ) {
|
||||
int rc = 1;
|
||||
|
||||
/* If the user wants only the boundary contours, we throw away all edges
|
||||
* except those which separate the interior from the exterior.
|
||||
* Otherwise we tessellate all the regions marked "inside".
|
||||
*/
|
||||
if( tess->boundaryOnly ) {
|
||||
rc = __gl_meshSetWindingNumber( mesh, 1, TRUE );
|
||||
} else {
|
||||
rc = __gl_meshTessellateInterior( mesh );
|
||||
}
|
||||
if (rc == 0) longjmp(tess->env,1); /* could've used a label */
|
||||
|
||||
__gl_meshCheckMesh( mesh );
|
||||
|
||||
if( tess->callBegin != &noBegin || tess->callEnd != &noEnd
|
||||
|| tess->callVertex != &noVertex || tess->callEdgeFlag != &noEdgeFlag
|
||||
|| tess->callBeginData != &__gl_noBeginData
|
||||
|| tess->callEndData != &__gl_noEndData
|
||||
|| tess->callVertexData != &__gl_noVertexData
|
||||
|| tess->callEdgeFlagData != &__gl_noEdgeFlagData )
|
||||
{
|
||||
if( tess->boundaryOnly ) {
|
||||
__gl_renderBoundary( tess, mesh ); /* output boundary contours */
|
||||
} else {
|
||||
__gl_renderMesh( tess, mesh ); /* output strips and fans */
|
||||
}
|
||||
}
|
||||
if( tess->callMesh != &noMesh ) {
|
||||
|
||||
/* Throw away the exterior faces, so that all faces are interior.
|
||||
* This way the user doesn't have to check the "inside" flag,
|
||||
* and we don't need to even reveal its existence. It also leaves
|
||||
* the freedom for an implementation to not generate the exterior
|
||||
* faces in the first place.
|
||||
*/
|
||||
__gl_meshDiscardExterior( mesh );
|
||||
(*tess->callMesh)( mesh ); /* user wants the mesh itself */
|
||||
tess->mesh = NULL;
|
||||
tess->polygonData= NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
__gl_meshDeleteMesh( mesh );
|
||||
tess->polygonData= NULL;
|
||||
tess->mesh = NULL;
|
||||
}
|
||||
|
||||
|
||||
/*XXXblythe unused function*/
|
||||
#if 0
|
||||
void GLAPIENTRY
|
||||
gluDeleteMesh( GLUmesh *mesh )
|
||||
{
|
||||
__gl_meshDeleteMesh( mesh );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*******************************************************/
|
||||
|
||||
/* Obsolete calls -- for backward compatibility */
|
||||
|
||||
void GLAPIENTRY
|
||||
gluBeginPolygon( GLUtesselator *tess )
|
||||
{
|
||||
gluTessBeginPolygon( tess, NULL );
|
||||
gluTessBeginContour( tess );
|
||||
}
|
||||
|
||||
|
||||
/*ARGSUSED*/
|
||||
void GLAPIENTRY
|
||||
gluNextContour( GLUtesselator *tess, GLenum type )
|
||||
{
|
||||
gluTessEndContour( tess );
|
||||
gluTessBeginContour( tess );
|
||||
}
|
||||
|
||||
|
||||
void GLAPIENTRY
|
||||
gluEndPolygon( GLUtesselator *tess )
|
||||
{
|
||||
gluTessEndContour( tess );
|
||||
gluTessEndPolygon( tess );
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __tess_h_
|
||||
#define __tess_h_
|
||||
|
||||
#include "glu.h"
|
||||
#include <setjmp.h>
|
||||
#include "mesh.h"
|
||||
#include "dict.h"
|
||||
#include "priorityq.h"
|
||||
|
||||
/* The begin/end calls must be properly nested. We keep track of
|
||||
* the current state to enforce the ordering.
|
||||
*/
|
||||
enum TessState { T_DORMANT, T_IN_POLYGON, T_IN_CONTOUR };
|
||||
|
||||
/* We cache vertex data for single-contour polygons so that we can
|
||||
* try a quick-and-dirty decomposition first.
|
||||
*/
|
||||
#define TESS_MAX_CACHE 100
|
||||
|
||||
typedef struct CachedVertex {
|
||||
GLdouble coords[3];
|
||||
void *data;
|
||||
} CachedVertex;
|
||||
|
||||
struct GLUtesselator {
|
||||
|
||||
/*** state needed for collecting the input data ***/
|
||||
|
||||
enum TessState state; /* what begin/end calls have we seen? */
|
||||
|
||||
GLUhalfEdge *lastEdge; /* lastEdge->Org is the most recent vertex */
|
||||
GLUmesh *mesh; /* stores the input contours, and eventually
|
||||
the tessellation itself */
|
||||
|
||||
void (GLAPIENTRY *callError)( GLenum errnum );
|
||||
|
||||
/*** state needed for projecting onto the sweep plane ***/
|
||||
|
||||
GLdouble normal[3]; /* user-specified normal (if provided) */
|
||||
GLdouble sUnit[3]; /* unit vector in s-direction (debugging) */
|
||||
GLdouble tUnit[3]; /* unit vector in t-direction (debugging) */
|
||||
|
||||
/*** state needed for the line sweep ***/
|
||||
|
||||
GLdouble relTolerance; /* tolerance for merging features */
|
||||
GLenum windingRule; /* rule for determining polygon interior */
|
||||
GLboolean fatalError; /* fatal error: needed combine callback */
|
||||
|
||||
Dict *dict; /* edge dictionary for sweep line */
|
||||
PriorityQ *pq; /* priority queue of vertex events */
|
||||
GLUvertex *event; /* current sweep event being processed */
|
||||
|
||||
void (GLAPIENTRY *callCombine)( GLdouble coords[3], void *data[4],
|
||||
GLfloat weight[4], void **outData );
|
||||
|
||||
/*** state needed for rendering callbacks (see render.c) ***/
|
||||
|
||||
GLboolean flagBoundary; /* mark boundary edges (use EdgeFlag) */
|
||||
GLboolean boundaryOnly; /* Extract contours, not triangles */
|
||||
GLUface *lonelyTriList;
|
||||
/* list of triangles which could not be rendered as strips or fans */
|
||||
|
||||
void (GLAPIENTRY *callBegin)( GLenum type );
|
||||
void (GLAPIENTRY *callEdgeFlag)( GLboolean boundaryEdge );
|
||||
void (GLAPIENTRY *callVertex)( void *data );
|
||||
void (GLAPIENTRY *callEnd)( void );
|
||||
void (GLAPIENTRY *callMesh)( GLUmesh *mesh );
|
||||
|
||||
|
||||
/*** state needed to cache single-contour polygons for renderCache() */
|
||||
|
||||
GLboolean emptyCache; /* empty cache on next vertex() call */
|
||||
int cacheCount; /* number of cached vertices */
|
||||
CachedVertex cache[TESS_MAX_CACHE]; /* the vertex data */
|
||||
|
||||
/*** rendering callbacks that also pass polygon data ***/
|
||||
void (GLAPIENTRY *callBeginData)( GLenum type, void *polygonData );
|
||||
void (GLAPIENTRY *callEdgeFlagData)( GLboolean boundaryEdge,
|
||||
void *polygonData );
|
||||
void (GLAPIENTRY *callVertexData)( void *data, void *polygonData );
|
||||
void (GLAPIENTRY *callEndData)( void *polygonData );
|
||||
void (GLAPIENTRY *callErrorData)( GLenum errnum, void *polygonData );
|
||||
void (GLAPIENTRY *callCombineData)( GLdouble coords[3], void *data[4],
|
||||
GLfloat weight[4], void **outData,
|
||||
void *polygonData );
|
||||
|
||||
jmp_buf env; /* place to jump to when memAllocs fail */
|
||||
|
||||
void *polygonData; /* client data for current polygon */
|
||||
};
|
||||
|
||||
void GLAPIENTRY __gl_noBeginData( GLenum type, void *polygonData );
|
||||
void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge, void *polygonData );
|
||||
void GLAPIENTRY __gl_noVertexData( void *data, void *polygonData );
|
||||
void GLAPIENTRY __gl_noEndData( void *polygonData );
|
||||
void GLAPIENTRY __gl_noErrorData( GLenum errnum, void *polygonData );
|
||||
void GLAPIENTRY __gl_noCombineData( GLdouble coords[3], void *data[4],
|
||||
GLfloat weight[4], void **outData,
|
||||
void *polygonData );
|
||||
|
||||
#define CALL_BEGIN_OR_BEGIN_DATA(a) \
|
||||
if (tess->callBeginData != &__gl_noBeginData) \
|
||||
(*tess->callBeginData)((a),tess->polygonData); \
|
||||
else (*tess->callBegin)((a));
|
||||
|
||||
#define CALL_VERTEX_OR_VERTEX_DATA(a) \
|
||||
if (tess->callVertexData != &__gl_noVertexData) \
|
||||
(*tess->callVertexData)((a),tess->polygonData); \
|
||||
else (*tess->callVertex)((a));
|
||||
|
||||
#define CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA(a) \
|
||||
if (tess->callEdgeFlagData != &__gl_noEdgeFlagData) \
|
||||
(*tess->callEdgeFlagData)((a),tess->polygonData); \
|
||||
else (*tess->callEdgeFlag)((a));
|
||||
|
||||
#define CALL_END_OR_END_DATA() \
|
||||
if (tess->callEndData != &__gl_noEndData) \
|
||||
(*tess->callEndData)(tess->polygonData); \
|
||||
else (*tess->callEnd)();
|
||||
|
||||
#define CALL_COMBINE_OR_COMBINE_DATA(a,b,c,d) \
|
||||
if (tess->callCombineData != &__gl_noCombineData) \
|
||||
(*tess->callCombineData)((a),(b),(c),(d),tess->polygonData); \
|
||||
else (*tess->callCombine)((a),(b),(c),(d));
|
||||
|
||||
#define CALL_ERROR_OR_ERROR_DATA(a) \
|
||||
if (tess->callErrorData != &__gl_noErrorData) \
|
||||
(*tess->callErrorData)((a),tess->polygonData); \
|
||||
else (*tess->callError)((a));
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,231 @@
|
||||
#include "glu.h"
|
||||
#include "tess.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
typedef struct Triangle {
|
||||
int v[3];
|
||||
struct Triangle *prev;
|
||||
} Triangle;
|
||||
|
||||
typedef struct Vertex {
|
||||
double pt[3];
|
||||
int index;
|
||||
struct Vertex *prev;
|
||||
} Vertex;
|
||||
|
||||
typedef struct TessContext {
|
||||
Triangle *latest_t;
|
||||
int n_tris;
|
||||
|
||||
Vertex *v_prev;
|
||||
Vertex *v_prevprev;
|
||||
Vertex *latest_v;
|
||||
GLenum current_mode;
|
||||
int odd_even_strip;
|
||||
|
||||
void (*vertex_cb)(Vertex *, struct TessContext *);
|
||||
} TessContext;
|
||||
|
||||
void skip_vertex(Vertex *v, TessContext *ctx);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
TessContext *new_tess_context()
|
||||
{
|
||||
TessContext *result = (TessContext *)malloc(sizeof (struct TessContext));
|
||||
result->latest_t = NULL;
|
||||
result->latest_v = NULL;
|
||||
result->n_tris = 0;
|
||||
result->v_prev = NULL;
|
||||
result->v_prevprev = NULL;
|
||||
result->v_prev = NULL;
|
||||
result->v_prev = NULL;
|
||||
result->vertex_cb = &skip_vertex;
|
||||
result->odd_even_strip = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
void destroy_tess_context(TessContext *ctx)
|
||||
{
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
Vertex *new_vertex(TessContext *ctx, double x, double y)
|
||||
{
|
||||
Vertex *result = (Vertex *)malloc(sizeof(Vertex));
|
||||
result->prev = ctx->latest_v;
|
||||
result->pt[0] = x;
|
||||
result->pt[1] = y;
|
||||
result->pt[2] = 0;
|
||||
|
||||
if (ctx->latest_v == NULL) {
|
||||
result->index = 0;
|
||||
} else {
|
||||
result->index = ctx->latest_v->index+1;
|
||||
}
|
||||
return ctx->latest_v = result;
|
||||
}
|
||||
|
||||
|
||||
Triangle *new_triangle(TessContext *ctx, int v1, int v2, int v3)
|
||||
{
|
||||
Triangle *result = (Triangle *)malloc(sizeof(Triangle));
|
||||
result->prev = ctx->latest_t;
|
||||
result->v[0] = v1;
|
||||
result->v[1] = v2;
|
||||
result->v[2] = v3;
|
||||
ctx->n_tris++;
|
||||
return ctx->latest_t = result;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void skip_vertex(Vertex *v, TessContext *ctx) {};
|
||||
|
||||
void fan_vertex(Vertex *v, TessContext *ctx) {
|
||||
if (ctx->v_prevprev == NULL) {
|
||||
ctx->v_prevprev = v;
|
||||
return;
|
||||
}
|
||||
if (ctx->v_prev == NULL) {
|
||||
ctx->v_prev = v;
|
||||
return;
|
||||
}
|
||||
new_triangle(ctx, ctx->v_prevprev->index, ctx->v_prev->index, v->index);
|
||||
ctx->v_prev = v;
|
||||
}
|
||||
|
||||
void strip_vertex(Vertex *v, TessContext *ctx)
|
||||
{
|
||||
if (ctx->v_prev == NULL) {
|
||||
ctx->v_prev = v;
|
||||
return;
|
||||
}
|
||||
if (ctx->v_prevprev == NULL) {
|
||||
ctx->v_prevprev = v;
|
||||
return;
|
||||
}
|
||||
if (ctx->odd_even_strip) {
|
||||
new_triangle(ctx, ctx->v_prevprev->index, ctx->v_prev->index, v->index);
|
||||
} else {
|
||||
new_triangle(ctx, ctx->v_prev->index, ctx->v_prevprev->index, v->index);
|
||||
}
|
||||
ctx->odd_even_strip = !ctx->odd_even_strip;
|
||||
|
||||
ctx->v_prev = ctx->v_prevprev;
|
||||
ctx->v_prevprev = v;
|
||||
}
|
||||
|
||||
void triangle_vertex(Vertex *v, TessContext *ctx) {
|
||||
if (ctx->v_prevprev == NULL) {
|
||||
ctx->v_prevprev = v;
|
||||
return;
|
||||
}
|
||||
if (ctx->v_prev == NULL) {
|
||||
ctx->v_prev = v;
|
||||
return;
|
||||
}
|
||||
new_triangle(ctx, ctx->v_prevprev->index, ctx->v_prev->index, v->index);
|
||||
ctx->v_prev = ctx->v_prevprev = NULL;
|
||||
}
|
||||
|
||||
void vertex(void *vertex_data, void *poly_data)
|
||||
{
|
||||
Vertex *ptr = (Vertex *)vertex_data;
|
||||
TessContext *ctx = (TessContext *)poly_data;
|
||||
ctx->vertex_cb(ptr, ctx);
|
||||
}
|
||||
|
||||
void begin(GLenum which, void *poly_data)
|
||||
{
|
||||
TessContext *ctx = (TessContext *)poly_data;
|
||||
ctx->v_prev = ctx->v_prevprev = NULL;
|
||||
ctx->odd_even_strip = 0;
|
||||
switch (which) {
|
||||
case GL_TRIANGLES: ctx->vertex_cb = &triangle_vertex; break;
|
||||
case GL_TRIANGLE_STRIP: ctx->vertex_cb = &strip_vertex; break;
|
||||
case GL_TRIANGLE_FAN: ctx->vertex_cb = &fan_vertex; break;
|
||||
default:
|
||||
fprintf(stderr, "ERROR, can't handle %d\n", (int)which);
|
||||
ctx->vertex_cb = &skip_vertex;
|
||||
}
|
||||
}
|
||||
|
||||
void combine(const GLdouble newVertex[3],
|
||||
const void *neighborVertex[4],
|
||||
const GLfloat neighborWeight[4], void **outData, void *polyData)
|
||||
{
|
||||
TessContext *ctx = (TessContext *)polyData;
|
||||
Vertex *result = new_vertex(ctx, newVertex[0], newVertex[1]);
|
||||
*outData = result;
|
||||
}
|
||||
|
||||
void write_output(TessContext *ctx, double **coordinates_out, int **tris_out, int *vc, int *tc)
|
||||
{
|
||||
int n_verts = 1 + ctx->latest_v->index;
|
||||
*vc = n_verts;
|
||||
int n_tris_copy = ctx->n_tris;
|
||||
*tc = ctx->n_tris;
|
||||
*coordinates_out = (double *)malloc(n_verts * sizeof(double) * 2);
|
||||
*tris_out = (int *)(ctx->n_tris ? malloc(ctx->n_tris * sizeof(int) * 3) : NULL);
|
||||
|
||||
while (ctx->latest_v) {
|
||||
(*coordinates_out)[2*ctx->latest_v->index] = ctx->latest_v->pt[0];
|
||||
(*coordinates_out)[2*ctx->latest_v->index+1] = ctx->latest_v->pt[1];
|
||||
Vertex *prev = ctx->latest_v->prev;
|
||||
free(ctx->latest_v);
|
||||
ctx->latest_v = prev;
|
||||
}
|
||||
|
||||
while (ctx->latest_t) {
|
||||
(*tris_out)[3*(n_tris_copy-1)] = ctx->latest_t->v[0];
|
||||
(*tris_out)[3*(n_tris_copy-1)+1] = ctx->latest_t->v[1];
|
||||
(*tris_out)[3*(n_tris_copy-1)+2] = ctx->latest_t->v[2];
|
||||
Triangle *prev = ctx->latest_t->prev;
|
||||
free(ctx->latest_t);
|
||||
ctx->latest_t = prev;
|
||||
n_tris_copy--;
|
||||
}
|
||||
}
|
||||
|
||||
void tessellate
|
||||
(double **verts,
|
||||
int *nverts,
|
||||
int **tris,
|
||||
int *ntris,
|
||||
const double **contoursbegin,
|
||||
const double **contoursend)
|
||||
{
|
||||
const double *contourbegin, *contourend;
|
||||
Vertex *current_vertex;
|
||||
GLUtesselator *tess;
|
||||
TessContext *ctx;
|
||||
|
||||
tess = gluNewTess();
|
||||
ctx = new_tess_context();
|
||||
gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO);
|
||||
gluTessCallback(tess, GLU_TESS_VERTEX_DATA, (GLvoid (*) ()) &vertex);
|
||||
gluTessCallback(tess, GLU_TESS_BEGIN_DATA, (GLvoid (*) ()) &begin);
|
||||
gluTessCallback(tess, GLU_TESS_COMBINE_DATA, (GLvoid (*) ()) &combine);
|
||||
|
||||
gluTessBeginPolygon(tess, ctx);
|
||||
do {
|
||||
contourbegin = *contoursbegin++;
|
||||
contourend = *contoursbegin;
|
||||
gluTessBeginContour(tess);
|
||||
while (contourbegin != contourend) {
|
||||
current_vertex = new_vertex(ctx, contourbegin[0], contourbegin[1]);
|
||||
contourbegin += 2;
|
||||
gluTessVertex(tess, current_vertex->pt, current_vertex);
|
||||
}
|
||||
gluTessEndContour(tess);
|
||||
} while (contoursbegin != (contoursend - 1));
|
||||
gluTessEndPolygon(tess);
|
||||
|
||||
write_output(ctx, verts, tris, nverts, ntris);
|
||||
destroy_tess_context(ctx);
|
||||
gluDeleteTess(tess);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
typedef struct Vertex {
|
||||
double pt[3];
|
||||
int index;
|
||||
struct Vertex *prev;
|
||||
} Vertex;
|
||||
|
||||
void tessellate
|
||||
(double **verts,
|
||||
int *nverts,
|
||||
int **tris,
|
||||
int *ntris,
|
||||
const double **contoursbegin,
|
||||
const double **contoursend);
|
||||
@@ -0,0 +1,70 @@
|
||||
tessellate = (function() {
|
||||
|
||||
var c_tessellate = Module.cwrap('tessellate', 'void', ['number', 'number', 'number',
|
||||
'number', 'number', 'number']);
|
||||
var tessellate = function(loops)
|
||||
{
|
||||
var i;
|
||||
if (loops.length === 0)
|
||||
throw "Expected at least one loop";
|
||||
|
||||
var vertices = [];
|
||||
var boundaries = [0];
|
||||
|
||||
for (var l=0; l<loops.length; ++l) {
|
||||
var loop = loops[l];
|
||||
if (loop.length % 2 !== 0)
|
||||
throw "Expected even number of coordinates";
|
||||
vertices.push.apply(vertices, loop);
|
||||
boundaries.push(vertices.length);
|
||||
}
|
||||
|
||||
var p = Module._malloc(vertices.length * 8);
|
||||
|
||||
for (i=0; i<vertices.length; ++i)
|
||||
Module.setValue(p+i*8, vertices[i], "double");
|
||||
|
||||
var contours = Module._malloc(boundaries.length * 4);
|
||||
for (i=0; i<boundaries.length; ++i)
|
||||
Module.setValue(contours + 4 * i, p + 8 * boundaries[i], 'i32');
|
||||
|
||||
var ppcoordinates_out = Module._malloc(4);
|
||||
var pptris_out = Module._malloc(4);
|
||||
var pnverts = Module._malloc(4);
|
||||
var pntris = Module._malloc(4);
|
||||
|
||||
c_tessellate(ppcoordinates_out, pnverts, pptris_out, pntris,
|
||||
contours, contours+4*boundaries.length);
|
||||
|
||||
var pcoordinates_out = Module.getValue(ppcoordinates_out, 'i32');
|
||||
var ptris_out = Module.getValue(pptris_out, 'i32');
|
||||
|
||||
var nverts = Module.getValue(pnverts, 'i32');
|
||||
var ntris = Module.getValue(pntris, 'i32');
|
||||
|
||||
var result_vertices = new Float64Array(nverts * 2);
|
||||
var result_triangles = new Int32Array(ntris * 3);
|
||||
|
||||
for (i=0; i<2*nverts; ++i) {
|
||||
result_vertices[i] = Module.getValue(pcoordinates_out + i*8, 'double');
|
||||
}
|
||||
for (i=0; i<3*ntris; ++i) {
|
||||
result_triangles[i] = Module.getValue(ptris_out + i*4, 'i32');
|
||||
}
|
||||
Module._free(pnverts);
|
||||
Module._free(pntris);
|
||||
Module._free(ppcoordinates_out);
|
||||
Module._free(pptris_out);
|
||||
Module._free(pcoordinates_out);
|
||||
Module._free(ptris_out);
|
||||
Module._free(p);
|
||||
Module._free(contours);
|
||||
return {
|
||||
vertices: result_vertices,
|
||||
triangles: result_triangles
|
||||
};
|
||||
};
|
||||
|
||||
return tessellate;
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#include "gluos.h"
|
||||
#include <stdlib.h>
|
||||
#include "geom.h"
|
||||
#include "mesh.h"
|
||||
#include "tessmono.h"
|
||||
#include <assert.h>
|
||||
|
||||
#define AddWinding(eDst,eSrc) (eDst->winding += eSrc->winding, \
|
||||
eDst->Sym->winding += eSrc->Sym->winding)
|
||||
|
||||
/* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region
|
||||
* (what else would it do??) The region must consist of a single
|
||||
* loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this
|
||||
* case means that any vertical line intersects the interior of the
|
||||
* region in a single interval.
|
||||
*
|
||||
* Tessellation consists of adding interior edges (actually pairs of
|
||||
* half-edges), to split the region into non-overlapping triangles.
|
||||
*
|
||||
* The basic idea is explained in Preparata and Shamos (which I don''t
|
||||
* have handy right now), although their implementation is more
|
||||
* complicated than this one. The are two edge chains, an upper chain
|
||||
* and a lower chain. We process all vertices from both chains in order,
|
||||
* from right to left.
|
||||
*
|
||||
* The algorithm ensures that the following invariant holds after each
|
||||
* vertex is processed: the untessellated region consists of two
|
||||
* chains, where one chain (say the upper) is a single edge, and
|
||||
* the other chain is concave. The left vertex of the single edge
|
||||
* is always to the left of all vertices in the concave chain.
|
||||
*
|
||||
* Each step consists of adding the rightmost unprocessed vertex to one
|
||||
* of the two chains, and forming a fan of triangles from the rightmost
|
||||
* of two chain endpoints. Determining whether we can add each triangle
|
||||
* to the fan is a simple orientation test. By making the fan as large
|
||||
* as possible, we restore the invariant (check it yourself).
|
||||
*/
|
||||
int __gl_meshTessellateMonoRegion( GLUface *face )
|
||||
{
|
||||
GLUhalfEdge *up, *lo;
|
||||
|
||||
/* All edges are oriented CCW around the boundary of the region.
|
||||
* First, find the half-edge whose origin vertex is rightmost.
|
||||
* Since the sweep goes from left to right, face->anEdge should
|
||||
* be close to the edge we want.
|
||||
*/
|
||||
up = face->anEdge;
|
||||
assert( up->Lnext != up && up->Lnext->Lnext != up );
|
||||
|
||||
for( ; VertLeq( up->Dst, up->Org ); up = up->Lprev )
|
||||
;
|
||||
for( ; VertLeq( up->Org, up->Dst ); up = up->Lnext )
|
||||
;
|
||||
lo = up->Lprev;
|
||||
|
||||
while( up->Lnext != lo ) {
|
||||
if( VertLeq( up->Dst, lo->Org )) {
|
||||
/* up->Dst is on the left. It is safe to form triangles from lo->Org.
|
||||
* The EdgeGoesLeft test guarantees progress even when some triangles
|
||||
* are CW, given that the upper and lower chains are truly monotone.
|
||||
*/
|
||||
while( lo->Lnext != up && (EdgeGoesLeft( lo->Lnext )
|
||||
|| EdgeSign( lo->Org, lo->Dst, lo->Lnext->Dst ) <= 0 )) {
|
||||
GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo );
|
||||
if (tempHalfEdge == NULL) return 0;
|
||||
lo = tempHalfEdge->Sym;
|
||||
}
|
||||
lo = lo->Lprev;
|
||||
} else {
|
||||
/* lo->Org is on the left. We can make CCW triangles from up->Dst. */
|
||||
while( lo->Lnext != up && (EdgeGoesRight( up->Lprev )
|
||||
|| EdgeSign( up->Dst, up->Org, up->Lprev->Org ) >= 0 )) {
|
||||
GLUhalfEdge *tempHalfEdge= __gl_meshConnect( up, up->Lprev );
|
||||
if (tempHalfEdge == NULL) return 0;
|
||||
up = tempHalfEdge->Sym;
|
||||
}
|
||||
up = up->Lnext;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now lo->Org == up->Dst == the leftmost vertex. The remaining region
|
||||
* can be tessellated in a fan from this leftmost vertex.
|
||||
*/
|
||||
assert( lo->Lnext != up );
|
||||
while( lo->Lnext->Lnext != up ) {
|
||||
GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo );
|
||||
if (tempHalfEdge == NULL) return 0;
|
||||
lo = tempHalfEdge->Sym;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* __gl_meshTessellateInterior( mesh ) tessellates each region of
|
||||
* the mesh which is marked "inside" the polygon. Each such region
|
||||
* must be monotone.
|
||||
*/
|
||||
int __gl_meshTessellateInterior( GLUmesh *mesh )
|
||||
{
|
||||
GLUface *f, *next;
|
||||
|
||||
/*LINTED*/
|
||||
for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) {
|
||||
/* Make sure we don''t try to tessellate the new triangles. */
|
||||
next = f->next;
|
||||
if( f->inside ) {
|
||||
if ( !__gl_meshTessellateMonoRegion( f ) ) return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces
|
||||
* which are not marked "inside" the polygon. Since further mesh operations
|
||||
* on NULL faces are not allowed, the main purpose is to clean up the
|
||||
* mesh so that exterior loops are not represented in the data structure.
|
||||
*/
|
||||
void __gl_meshDiscardExterior( GLUmesh *mesh )
|
||||
{
|
||||
GLUface *f, *next;
|
||||
|
||||
/*LINTED*/
|
||||
for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) {
|
||||
/* Since f will be destroyed, save its next pointer. */
|
||||
next = f->next;
|
||||
if( ! f->inside ) {
|
||||
__gl_meshZapFace( f );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define MARKED_FOR_DELETION 0x7fffffff
|
||||
|
||||
/* __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the
|
||||
* winding numbers on all edges so that regions marked "inside" the
|
||||
* polygon have a winding number of "value", and regions outside
|
||||
* have a winding number of 0.
|
||||
*
|
||||
* If keepOnlyBoundary is TRUE, it also deletes all edges which do not
|
||||
* separate an interior region from an exterior one.
|
||||
*/
|
||||
int __gl_meshSetWindingNumber( GLUmesh *mesh, int value,
|
||||
GLboolean keepOnlyBoundary )
|
||||
{
|
||||
GLUhalfEdge *e, *eNext;
|
||||
|
||||
for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) {
|
||||
eNext = e->next;
|
||||
if( e->Rface->inside != e->Lface->inside ) {
|
||||
|
||||
/* This is a boundary edge (one side is interior, one is exterior). */
|
||||
e->winding = (e->Lface->inside) ? value : -value;
|
||||
} else {
|
||||
|
||||
/* Both regions are interior, or both are exterior. */
|
||||
if( ! keepOnlyBoundary ) {
|
||||
e->winding = 0;
|
||||
} else {
|
||||
if ( !__gl_meshDelete( e ) ) return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
|
||||
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice including the dates of first publication and
|
||||
* either this permission notice or a reference to
|
||||
* http://oss.sgi.com/projects/FreeB/
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of Silicon Graphics, Inc.
|
||||
* shall not be used in advertising or otherwise to promote the sale, use or
|
||||
* other dealings in this Software without prior written authorization from
|
||||
* Silicon Graphics, Inc.
|
||||
*/
|
||||
/*
|
||||
** Author: Eric Veach, July 1994.
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __tessmono_h_
|
||||
#define __tessmono_h_
|
||||
|
||||
/* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region
|
||||
* (what else would it do??) The region must consist of a single
|
||||
* loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this
|
||||
* case means that any vertical line intersects the interior of the
|
||||
* region in a single interval.
|
||||
*
|
||||
* Tessellation consists of adding interior edges (actually pairs of
|
||||
* half-edges), to split the region into non-overlapping triangles.
|
||||
*
|
||||
* __gl_meshTessellateInterior( mesh ) tessellates each region of
|
||||
* the mesh which is marked "inside" the polygon. Each such region
|
||||
* must be monotone.
|
||||
*
|
||||
* __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces
|
||||
* which are not marked "inside" the polygon. Since further mesh operations
|
||||
* on NULL faces are not allowed, the main purpose is to clean up the
|
||||
* mesh so that exterior loops are not represented in the data structure.
|
||||
*
|
||||
* __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the
|
||||
* winding numbers on all edges so that regions marked "inside" the
|
||||
* polygon have a winding number of "value", and regions outside
|
||||
* have a winding number of 0.
|
||||
*
|
||||
* If keepOnlyBoundary is TRUE, it also deletes all edges which do not
|
||||
* separate an interior region from an exterior one.
|
||||
*/
|
||||
|
||||
int __gl_meshTessellateMonoRegion( GLUface *face );
|
||||
int __gl_meshTessellateInterior( GLUmesh *mesh );
|
||||
void __gl_meshDiscardExterior( GLUmesh *mesh );
|
||||
int __gl_meshSetWindingNumber( GLUmesh *mesh, int value,
|
||||
GLboolean keepOnlyBoundary );
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user