Doom 3 RTX Initial Checkin.

This commit is contained in:
Justin Marshall
2026-04-22 00:55:07 -07:00
commit 6b65fbd7b1
2056 changed files with 848698 additions and 0 deletions
File diff suppressed because it is too large Load Diff
+36
View File
@@ -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
+222
View File
@@ -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();
}
+182
View File
@@ -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; }
+254
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+246
View File
@@ -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>
+116
View File
@@ -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>
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>
+46
View File
@@ -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
};
}
+254
View File
@@ -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()
}
+328
View File
@@ -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{};
};
}
+103
View File
@@ -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
};
}
+173
View File
@@ -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);
}
+193
View File
@@ -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);
}
+188
View File
@@ -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);
}
+209
View File
@@ -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);
}
+475
View File
@@ -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);
+115
View File
@@ -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;
}
}
+102
View File
@@ -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);
}
+70
View File
@@ -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()
}
+158
View File
@@ -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);
}
+233
View File
@@ -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);
}
+77
View File
@@ -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
};
}
+463
View File
@@ -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;
}
}
}
+139
View File
@@ -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.
+100
View File
@@ -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
+111
View File
@@ -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;
}
+100
View File
@@ -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
+264
View File
@@ -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 );
}
}
+84
View File
@@ -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
+356
View File
@@ -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__ */
+86
View File
@@ -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
+55
View File
@@ -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
+54
View File
@@ -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
+798
View File
@@ -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
+266
View File
@@ -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
+257
View File
@@ -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 );
}
}
+45
View File
@@ -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
+257
View File
@@ -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;
}
+107
View File
@@ -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
+117
View File
@@ -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
+260
View File
@@ -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;
}
}
+117
View File
@@ -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
+502
View File
@@ -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;
}
+52
View File
@@ -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
+77
View File
@@ -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
+632
View File
@@ -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 );
}
+165
View File
@@ -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
+231
View File
@@ -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);
}
+13
View File
@@ -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);
+70
View File
@@ -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;
})();
+201
View File
@@ -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;
}
+71
View File
@@ -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