Add Chromium-only Blender WebEngine parity work

This commit is contained in:
mes123456
2026-08-12 04:47:48 -04:00
commit 9fd26010f6
18225 changed files with 11622124 additions and 0 deletions

View File

@@ -0,0 +1,220 @@
#
# Copyright 2013 Pixar
#
# Licensed under the terms set forth in the LICENSE.txt file available at
# https://opensubdiv.org/license.
#
set(EXAMPLES_COMMON_SOURCE_FILES
font_image.cpp
hdr_reader.cpp
hud.cpp
objAnim.cpp
patchColors.cpp
viewerArgsUtils.cpp
)
set(EXAMPLES_COMMON_HEADER_FILES
font_image.h
hdr_reader.h
hud.h
objAnim.h
patchColors.h
shaderCache.h
simple_math.h
stb_image_write.h
stopwatch.h
viewerArgsUtils.h
)
include_directories(
"${OPENSUBDIV_INCLUDE_DIR}"
"${CMAKE_CURRENT_BINARY_DIR}"
)
if(OPENCL_FOUND)
include_directories("${OPENCL_INCLUDE_DIRS}")
list(APPEND EXAMPLES_COMMON_SOURCE_FILES
clDeviceContext.cpp
)
list(APPEND EXAMPLES_COMMON_HEADER_FILES
clDeviceContext.h
)
endif()
if(CUDA_FOUND)
include_directories("${CUDA_INCLUDE_DIRS}")
list(APPEND EXAMPLES_COMMON_SOURCE_FILES
cudaDeviceContext.cpp
)
list(APPEND EXAMPLES_COMMON_HEADER_FILES
cudaDeviceContext.h
)
endif()
if(DEFINED OPENGL_LOADER_INCLUDE_DIRS)
include_directories(${OPENGL_LOADER_INCLUDE_DIRS})
endif()
if(OPENGL_FOUND AND GLFW_FOUND)
list(APPEND EXAMPLES_COMMON_GL_SOURCE_FILES
glControlMeshDisplay.cpp
glHud.cpp
glUtils.cpp
glShaderCache.cpp
)
list(APPEND EXAMPLES_COMMON_GL_HEADER_FILES
glControlMeshDisplay.h
glHud.h
glUtils.h
glShaderCache.h
)
if (GLFW_FOUND)
include_directories("${GLFW_INCLUDE_DIR}")
endif()
add_library(examples_common_gl_obj
OBJECT
${EXAMPLES_COMMON_SOURCE_FILES}
${EXAMPLES_COMMON_HEADER_FILES}
${EXAMPLES_COMMON_GL_SOURCE_FILES}
${EXAMPLES_COMMON_GL_HEADER_FILES}
)
set_target_properties(examples_common_gl_obj
PROPERTIES
FOLDER "examples"
)
endif()
if(DXSDK_FOUND)
list(APPEND EXAMPLES_COMMON_DX11_SOURCE_FILES
d3d11ControlMeshDisplay.cpp
d3d11Hud.cpp
d3d11Utils.cpp
d3d11ShaderCache.cpp
)
list(APPEND EXAMPLES_COMMON_DX11_HEADER_FILES
d3d11ControlMeshDisplay.h
d3d11Hud.h
d3d11Utils.h
d3d11ShaderCache.h
)
include_directories("${DXSDK_INCLUDE_DIR}")
add_library(examples_common_dx11_obj
OBJECT
${EXAMPLES_COMMON_SOURCE_FILES}
${EXAMPLES_COMMON_HEADER_FILES}
${EXAMPLES_COMMON_DX11_SOURCE_FILES}
${EXAMPLES_COMMON_DX11_HEADER_FILES}
)
set_target_properties(examples_common_dx11_obj
PROPERTIES
FOLDER "examples"
)
endif()
if(METAL_FOUND)
include_directories("${METAL_INCLUDE_DIR}")
list(APPEND EXAMPLES_COMMON_MTL_SOURCE_FILES
mtlControlMeshDisplay.mm
mtlUtils.mm
mtlHud.mm
)
list(APPEND EXAMPLES_COMMON_MTL_HEADER_FILES
mtlControlMeshDisplay.h
mtlUtils.h
mtlHud.h
)
add_library(examples_common_mtl_obj
OBJECT
${EXAMPLES_COMMON_SOURCE_FILES}
${EXAMPLES_COMMON_HEADER_FILES}
${EXAMPLES_COMMON_MTL_SOURCE_FILES}
${EXAMPLES_COMMON_MTL_HEADER_FILES}
)
set_target_properties(examples_common_mtl_obj
PROPERTIES
FOLDER "examples"
)
endif()
#-------------------------------------------------------------------------------
if( PTEX_FOUND )
list(APPEND EXAMPLES_COMMON_PTEX_HEADER_FILES
ptexMipmapTextureLoader.h
)
list(APPEND EXAMPLES_COMMON_PTEX_SOURCE_FILES
ptexMipmapTextureLoader.cpp
)
if( OPENGL_FOUND )
list(APPEND EXAMPLES_COMMON_PTEX_SOURCE_FILES
glPtexMipmapTexture.cpp
)
list(APPEND EXAMPLES_COMMON_PTEX_HEADER_FILES
glPtexMipmapTexture.h
)
endif()
if( DXSDK_FOUND )
list(APPEND EXAMPLES_COMMON_PTEX_SOURCE_FILES
d3d11PtexMipmapTexture.cpp
)
list(APPEND EXAMPLES_COMMON_PTEX_HEADER_FILES
d3d11PtexMipmapTexture.h
)
endif()
if( METAL_FOUND )
list(APPEND EXAMPLES_COMMON_PTEX_SOURCE_FILES
mtlPtexMipmapTexture.mm
)
list(APPEND EXAMPLES_COMMON_PTEX_HEADER_FILES
mtlPtexMipmapTexture.h
)
endif()
set(EXAMPLES_COMMON_PTEX_SHADER_FILES
glslPtexCommon.glsl
hlslPtexCommon.hlsl
mtlPtexCommon.metal
)
set(EXAMPLES_COMMON_PTEX_INC_FILES )
if(EXAMPLES_COMMON_PTEX_SHADER_FILES)
osd_stringify("${EXAMPLES_COMMON_PTEX_SHADER_FILES}"
EXAMPLES_COMMON_PTEX_INC_FILES)
source_group("Shaders" FILES ${EXAMPLES_COMMON_PTEX_SHADER_FILES})
source_group("Inc" FILES ${EXAMPLES_COMMON_PTEX_INC_FILES})
endif()
include_directories( "${PTEX_INCLUDE_DIR}" )
add_library(examples_common_ptex_obj
OBJECT
${EXAMPLES_COMMON_PTEX_SOURCE_FILES}
${EXAMPLES_COMMON_PTEX_HEADER_FILES}
${EXAMPLES_COMMON_PTEX_INC_FILES}
)
set_target_properties(examples_common_ptex_obj
PROPERTIES
FOLDER "examples"
)
endif()

View File

@@ -0,0 +1,348 @@
//
// Copyright 2015 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#define CL_USE_DEPRECATED_OPENCL_2_0_APIS
#include "clDeviceContext.h"
#if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#elif defined(__APPLE__)
#include <OpenGL/OpenGL.h>
#include <OpenGL/CGLCurrent.h>
#else
#include <GL/glx.h>
#endif
#include <cstdio>
#include <cstring>
#include <string>
#if defined(OPENSUBDIV_HAS_DX11SDK)
#include <D3D11.h>
#if defined(OPENSUBDIV_HAS_CL_D3D11_H)
#include <CL/cl_d3d11.h>
#elif defined(OPENSUBDIV_HAS_CL_D3D11_EXT_H)
#include <CL/cl_d3d11_ext.h>
#endif
#endif
#define message(...) // fprintf(stderr, __VA_ARGS__)
#define error(...) fprintf(stderr, __VA_ARGS__)
// returns the first found platform.
//
static cl_platform_id
findPlatform() {
cl_uint numPlatforms;
cl_int ciErrNum = clGetPlatformIDs(0, NULL, &numPlatforms);
if (ciErrNum != CL_SUCCESS) {
error("Error %d in clGetPlatformIDs call.\n", ciErrNum);
return NULL;
}
if (numPlatforms == 0) {
error("No OpenCL platform found.\n");
return NULL;
}
cl_platform_id *clPlatformIDs = new cl_platform_id[numPlatforms];
ciErrNum = clGetPlatformIDs(numPlatforms, clPlatformIDs, NULL);
char chBuffer[1024];
for (cl_uint i = 0; i < numPlatforms; ++i) {
ciErrNum = clGetPlatformInfo(clPlatformIDs[i], CL_PLATFORM_NAME,
1024, chBuffer,NULL);
if (ciErrNum == CL_SUCCESS) {
cl_platform_id platformId = clPlatformIDs[i];
delete[] clPlatformIDs;
return platformId;
}
}
delete[] clPlatformIDs;
return NULL;
}
// returns the device in clDevices which supports the extension.
//
static int
findExtensionSupportedDevice(cl_device_id *clDevices,
int numDevices,
const char *extensionName) {
// find a device that supports sharing with GL/D3D11
// (SLI / X-fire configurations)
cl_int ciErrNum;
for (int i = 0; i < numDevices; ++i) {
// get extensions string size
size_t extensionSize;
ciErrNum = clGetDeviceInfo(clDevices[i],
CL_DEVICE_EXTENSIONS, 0, NULL,
&extensionSize );
if (ciErrNum != CL_SUCCESS) {
error("Error %d in clGetDeviceInfo\n", ciErrNum);
return -1;
}
if (extensionSize>0) {
// get extensions string
char *extensions = new char[extensionSize];
ciErrNum = clGetDeviceInfo(clDevices[i], CL_DEVICE_EXTENSIONS,
extensionSize, extensions,
&extensionSize);
if (ciErrNum != CL_SUCCESS) {
error("Error %d in clGetDeviceInfo\n", ciErrNum);
delete[] extensions;
continue;
}
std::string extString(extensions);
delete[] extensions;
// parse string. This is a bit deficient since the extensions
// string is space separated.
//
// The actual string would be "cl_khr_d3d11_sharing"
// or "cl_nv_d3d11_sharing"
if (extString.find(extensionName) != std::string::npos) {
return i;
}
}
}
return -1;
}
// --------------------------------------------------------------------------
CLDeviceContext::CLDeviceContext() :
_clContext(NULL), _clCommandQueue(NULL) {
}
CLDeviceContext::~CLDeviceContext() {
if (_clCommandQueue)
clReleaseCommandQueue(_clCommandQueue);
if (_clContext)
clReleaseContext(_clContext);
}
/*static*/
bool
CLDeviceContext::HAS_CL_VERSION_1_1 () {
#ifdef OPENSUBDIV_HAS_CLEW
static bool clewInitialized = false;
static bool clewLoadSuccess;
if (!clewInitialized) {
clewInitialized = true;
clewLoadSuccess = clewInit() == CLEW_SUCCESS;
if (!clewLoadSuccess) {
error("Loading OpenCL failed.\n");
}
}
return clewLoadSuccess;
#endif
return true;
}
bool
CLDeviceContext::Initialize() {
#ifdef OPENSUBDIV_HAS_CLEW
if (!clGetPlatformIDs) {
error("Error clGetPlatformIDs function not bound.\n");
return false;
}
#endif
cl_int ciErrNum;
cl_platform_id cpPlatform = findPlatform();
#if defined(_WIN32)
cl_context_properties props[] = {
CL_GL_CONTEXT_KHR, (cl_context_properties)wglGetCurrentContext(),
CL_WGL_HDC_KHR, (cl_context_properties)wglGetCurrentDC(),
CL_CONTEXT_PLATFORM, (cl_context_properties)cpPlatform,
0
};
#elif defined(__APPLE__)
CGLContextObj kCGLContext = CGLGetCurrentContext();
CGLShareGroupObj kCGLShareGroup = CGLGetShareGroup(kCGLContext);
cl_context_properties props[] = {
CL_CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE, (cl_context_properties)kCGLShareGroup,
0
};
#else
cl_context_properties props[] = {
CL_GL_CONTEXT_KHR, (cl_context_properties)glXGetCurrentContext(),
CL_GLX_DISPLAY_KHR, (cl_context_properties)glXGetCurrentDisplay(),
CL_CONTEXT_PLATFORM, (cl_context_properties)cpPlatform,
0
};
#endif
#if defined(__APPLE__)
_clContext = clCreateContext(props, 0, NULL, clLogMessagesToStdoutAPPLE,
NULL, &ciErrNum);
if (ciErrNum != CL_SUCCESS) {
error("Error %d in clCreateContext\n", ciErrNum);
return false;
}
size_t devicesSize = 0;
clGetGLContextInfoAPPLE(_clContext, kCGLContext,
CL_CGL_DEVICES_FOR_SUPPORTED_VIRTUAL_SCREENS_APPLE,
0, NULL, &devicesSize);
int numDevices = int(devicesSize / sizeof(cl_device_id));
if (numDevices == 0) {
error("No sharable devices.\n");
return false;
}
cl_device_id *clDevices = new cl_device_id[numDevices];
clGetGLContextInfoAPPLE(_clContext, kCGLContext,
CL_CGL_DEVICES_FOR_SUPPORTED_VIRTUAL_SCREENS_APPLE,
numDevices * sizeof(cl_device_id), clDevices, NULL);
int clDeviceUsed = 0;
if (ciErrNum != CL_SUCCESS) {
error("Error %d in clCreateContext\n", ciErrNum);
delete[] clDevices;
return false;
}
_clCommandQueue = clCreateCommandQueue(
_clContext, clDevices[clDeviceUsed], 0, &ciErrNum);
delete[] clDevices;
if (ciErrNum != CL_SUCCESS) {
error("Error %d in clCreateCommandQueue\n", ciErrNum);
return false;
}
#else // not __APPLE__
// get the number of GPU devices available to the platform
cl_uint numDevices = 0;
clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_GPU, 0, NULL, &numDevices);
if (numDevices == 0) {
error("No CL GPU device found.\n");
return false;
}
// create the device list
cl_device_id *clDevices = new cl_device_id[numDevices];
clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_GPU, numDevices, clDevices, NULL);
const char *extension = "cl_khr_gl_sharing";
int clDeviceUsed = findExtensionSupportedDevice(clDevices, numDevices,
extension);
if (clDeviceUsed < 0) {
error("No device found that supports CL/GL context sharing\n");
delete[] clDevices;
return false;
}
_clContext = clCreateContext(props, 1, &clDevices[clDeviceUsed],
NULL, NULL, &ciErrNum);
if (ciErrNum != CL_SUCCESS) {
error("Error %d in clCreateContext\n", ciErrNum);
delete[] clDevices;
return false;
}
_clCommandQueue = clCreateCommandQueueWithProperties(
_clContext, clDevices[clDeviceUsed], NULL, &ciErrNum);
delete[] clDevices;
if (ciErrNum != CL_SUCCESS) {
error("Error %d in clCreateCommandQueueWithProperties\n", ciErrNum);
return false;
}
#endif // not __APPLE__
return true;
}
// ---------------------------------------------------------------------------
bool
CLD3D11DeviceContext::Initialize(ID3D11DeviceContext *d3dDeviceContext) {
#if defined(OPENSUBDIV_HAS_DX11SDK) && \
(defined(OPENSUBDIV_HAS_CL_D3D11_H) || defined(OPENSUBDIV_HAS_CL_D3D11_EXT_H))
_d3dDeviceContext = d3dDeviceContext;
cl_int ciErrNum;
cl_platform_id cpPlatform = findPlatform();
ID3D11Device *device;
d3dDeviceContext->GetDevice(&device);
#if defined(OPENSUBDIV_HAS_CL_D3D11_H)
cl_context_properties props[] = {
CL_CONTEXT_D3D11_DEVICE_KHR, (cl_context_properties)device,
CL_CONTEXT_PLATFORM, (cl_context_properties)cpPlatform,
0
};
#elif defined(OPENSUBDIV_HAS_CL_D3D11_EXT_H)
cl_context_properties props[] = {
CL_CONTEXT_D3D11_DEVICE_NV, (cl_context_properties)device,
CL_CONTEXT_PLATFORM, (cl_context_properties)cpPlatform,
0
};
#endif
// get the number of GPU devices available to the platform
cl_uint numDevices = 0;
clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_GPU, 0, NULL, &numDevices);
if (numDevices == 0) {
error("No CL GPU device found.\n");
return false;
}
// create the device list
cl_device_id *clDevices = new cl_device_id[numDevices];
clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_GPU, numDevices, clDevices, NULL);
// we're cheating a little bit.
// try to find both cl_khr_d3d11_sharing and cl_nv_d3d11_sharing.
const char *extension = "_d3d11_sharing";
int clDeviceUsed = findExtensionSupportedDevice(clDevices, numDevices,
extension);
if (clDeviceUsed < 0) {
error("No device found that supports CL/D3D11 context sharing\n");
delete[] clDevices;
return false;
}
_clContext = clCreateContext(props, 1, &clDevices[clDeviceUsed],
NULL, NULL, &ciErrNum);
if (ciErrNum != CL_SUCCESS) {
error("Error %d in clCreateContext\n", ciErrNum);
delete[] clDevices;
return false;
}
_clCommandQueue = clCreateCommandQueueWithProperties(
_clContext, clDevices[clDeviceUsed], NULL, &ciErrNum);
delete[] clDevices;
if (ciErrNum != CL_SUCCESS) {
error("Error %d in clCreateCommandQueueWithProperties\n", ciErrNum);
return false;
}
return true;
#else
(void)d3dDeviceContext; // unused
return false;
#endif
}

View File

@@ -0,0 +1,53 @@
//
// Copyright 2015 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#ifndef OSD_EXAMPLES_COMMON_CL_DEVICE_CONTEXT_H
#define OSD_EXAMPLES_COMMON_CL_DEVICE_CONTEXT_H
#include <opensubdiv/osd/opencl.h>
class CLDeviceContext {
public:
CLDeviceContext();
~CLDeviceContext();
static bool HAS_CL_VERSION_1_1 ();
bool Initialize();
bool IsInitialized() const {
return (_clContext != NULL);
}
cl_context GetContext() const {
return _clContext;
}
cl_command_queue GetCommandQueue() const {
return _clCommandQueue;
}
protected:
cl_context _clContext;
cl_command_queue _clCommandQueue;
};
struct ID3D11DeviceContext;
class CLD3D11DeviceContext : public CLDeviceContext {
public:
bool Initialize(ID3D11DeviceContext *deviceContext);
ID3D11DeviceContext *GetDeviceContext() const {
return _d3dDeviceContext;
}
private:
ID3D11DeviceContext *_d3dDeviceContext;
};
#endif // OSD_EXAMPLES_COMMON_CL_DEVICE_CONTEXT_H

View File

@@ -0,0 +1,137 @@
//
// Copyright 2015 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#include "cudaDeviceContext.h"
#if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#elif defined(__APPLE__)
#include <OpenGL/OpenGL.h>
#else
#include <X11/Xlib.h>
#include <GL/glx.h>
#endif
#include <cstdio>
#include <cuda.h>
#include <cuda_runtime_api.h>
#include <cuda_gl_interop.h>
#if defined(OPENSUBDIV_HAS_DX11SDK)
#include <cuda_d3d11_interop.h>
#endif
#define message(fmt, ...)
//#define message(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
#define error(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
// -----------------------------------------------------------------------
#if CUDA_VERSION < 5000
static int _GetCudaDeviceForCurrentGLContext()
{
#if defined(_WIN32)
return 0;
#elif defined(__APPLE__)
return 0;
#else // X11
// If we don't have a current GL context, then choose the device which
// matches the current X11 screen number.
Display * display = glXGetCurrentDisplay();
if (!display) {
display = XOpenDisplay(NULL);
if (display) {
int screen = DefaultScreen(display);
XCloseDisplay(display);
message("CUDA init using device for default screen: %d\n", screen);
return screen;
}
return 0;
}
// We can't use the new interop API, so use the device
// corresponding to the screen number of the current GL context.
int screen = DefaultScreen(display);
message("CUDA init using device for screen: %d\n", screen);
return screen;
#endif // X11
}
#else // CUDA_VERSION >= 50000 -----------------------------------------
static int _GetCudaDeviceForCurrentGLContext()
{
// Find and use the CUDA device for the current GL context
unsigned int interopDeviceCount = 0;
int interopDevices[1];
cudaError_t status = cudaGLGetDevices(&interopDeviceCount, interopDevices,
1, cudaGLDeviceListCurrentFrame);
if (status == cudaErrorNoDevice || interopDeviceCount != 1) {
message("CUDA no interop devices found.\n");
return 0;
}
int device = interopDevices[0];
#if defined(_WIN32)
return device;
#elif defined(__APPLE__)
return device;
#else // X11
Display * display = glXGetCurrentDisplay();
int screen = DefaultScreen(display);
if (device != screen) {
error("The CUDA interop device (%d) does not match "
"the screen used by the current GL context (%d), "
"which may cause slow performance on systems "
"with multiple GPU devices.", device, screen);
}
message("CUDA init using device for current GL context: %d\n", device);
return device;
#endif
}
#endif // CUDA_VERSION -----------------------------------------------
CudaDeviceContext::CudaDeviceContext() :
_initialized(false) {
}
CudaDeviceContext::~CudaDeviceContext() {
cudaDeviceReset();
}
bool
CudaDeviceContext::Initialize() {
// see if any cuda device is available.
int deviceCount = 0;
cudaGetDeviceCount(&deviceCount);
message("CUDA device count: %d\n", deviceCount);
if (deviceCount <= 0) {
return false;
}
cudaGLSetGLDevice(_GetCudaDeviceForCurrentGLContext());
_initialized = true;
return true;
}
bool
CudaDeviceContext::Initialize(ID3D11Device *device) {
#if defined(OPENSUBDIV_HAS_DX11SDK)
cudaD3D11SetDirect3DDevice(device);
return true;
#else
(void)device; // unused
return false;
#endif
}

View File

@@ -0,0 +1,33 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#ifndef OSD_EXAMPLES_COMMON_CUDA_DEVICE_CONTEXT_H
#define OSD_EXAMPLES_COMMON_CUDA_DEVICE_CONTEXT_H
struct ID3D11Device;
class CudaDeviceContext {
public:
CudaDeviceContext();
~CudaDeviceContext();
/// Initialize cuda device from the current GL context
bool Initialize();
/// Initialize cuda device from the ID3D11Device
bool Initialize(ID3D11Device *device);
/// Returns true if the cuda device has already been initialized
bool IsInitialized() const {
return _initialized;
}
private:
bool _initialized;
};
#endif // OSD_EXAMPLES_COMMON_CUDA_DEVICE_CONTEXT_H

View File

@@ -0,0 +1,251 @@
//
// Copyright 2015 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#include "d3d11ControlMeshDisplay.h"
#include "../common/d3d11Utils.h"
#include <vector>
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
static const char *s_VS =
"cbuffer cbPerFrame : register( b0 ) { matrix g_mViewProjection; }; \n"
"struct vertexIn { float3 pos : POSITION0; float sharpness : COLOR0; }; \n"
"struct vertexOut { float4 pos : SV_POSITION; float sharpness : COLOR0; }; \n"
"vertexOut vs_main(vertexIn IN) { \n"
" vertexOut vout; \n"
" vout.pos = mul(g_mViewProjection, float4(IN.pos, 1)); \n"
" vout.sharpness = IN.sharpness; \n"
" return vout; \n"
"} \n";
static const char *s_PS =
"struct pixelIn { float4 pos : SV_POSITION; float sharpness : COLOR0; }; \n"
"Buffer<float> edgeSharpness : register(t0); \n"
"float4 sharpnessToColor(float s) { \n"
" // 0.0 2.0 4.0 \n"
" // green --- yellow --- red \n"
" return float4(min(1, s * 0.5), \n"
" min(1, 2 - s * 0.5), \n"
" 0, 1); \n"
"} \n"
"float4 ps_main(pixelIn IN, uint primitiveID : SV_PrimitiveID) \n"
" : SV_Target { \n"
" float sharpness = edgeSharpness[primitiveID]; \n"
" return sharpnessToColor(sharpness); \n"
"} \n";
namespace {
struct CB_CONTROL_MESH_DISPLAY
{
float mViewProjection[16];
};
};
D3D11ControlMeshDisplay::D3D11ControlMeshDisplay(
ID3D11DeviceContext *deviceContext) :
_displayEdges(true), _displayVertices(false),
_deviceContext(deviceContext), _inputLayout(0), _vertexShader(0),
_pixelShader(0), _rasterizerState(0), _constantBuffer(0),
_edgeSharpnessSRV(0), _edgeSharpness(0), _edgeIndices(0),
_numEdges(0), _numPoints(0) {
}
D3D11ControlMeshDisplay::~D3D11ControlMeshDisplay() {
SAFE_RELEASE(_inputLayout);
SAFE_RELEASE(_vertexShader);
SAFE_RELEASE(_pixelShader);
SAFE_RELEASE(_rasterizerState);
SAFE_RELEASE(_constantBuffer);
SAFE_RELEASE(_edgeSharpness);
SAFE_RELEASE(_edgeSharpnessSRV);
SAFE_RELEASE(_edgeIndices);
}
bool
D3D11ControlMeshDisplay::createProgram() {
ID3D11Device *device = NULL;
_deviceContext->GetDevice(&device);
ID3DBlob* pVSBlob;
ID3DBlob* pPSBlob;
pVSBlob = D3D11Utils::CompileShader(s_VS, "vs_main", "vs_4_0");
pPSBlob = D3D11Utils::CompileShader(s_PS, "ps_main", "ps_4_0");
assert(pVSBlob);
assert(pPSBlob);
D3D11_INPUT_ELEMENT_DESC inputElementDesc[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,
D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32_FLOAT, 0, sizeof(float)*3,
D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
device->CreateInputLayout(inputElementDesc, ARRAYSIZE(inputElementDesc),
pVSBlob->GetBufferPointer(),
pVSBlob->GetBufferSize(),
&_inputLayout);
assert(_inputLayout);
device->CreateVertexShader(pVSBlob->GetBufferPointer(),
pVSBlob->GetBufferSize(),
NULL, &_vertexShader);
assert(_vertexShader);
device->CreatePixelShader(pPSBlob->GetBufferPointer(),
pPSBlob->GetBufferSize(),
NULL, &_pixelShader);
assert(_pixelShader);
D3D11_RASTERIZER_DESC rasDesc;
rasDesc.FillMode = D3D11_FILL_SOLID;
rasDesc.CullMode = D3D11_CULL_NONE;
rasDesc.FrontCounterClockwise = FALSE;
rasDesc.DepthBias = 0;
rasDesc.DepthBiasClamp = 0;
rasDesc.SlopeScaledDepthBias = 0.0f;
rasDesc.DepthClipEnable = FALSE;
rasDesc.ScissorEnable = FALSE;
rasDesc.MultisampleEnable = FALSE;
rasDesc.AntialiasedLineEnable = FALSE;
device->CreateRasterizerState(&rasDesc, &_rasterizerState);
assert(_rasterizerState);
// constant buffer
D3D11_BUFFER_DESC cbDesc;
cbDesc.Usage = D3D11_USAGE_DYNAMIC;
cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
cbDesc.MiscFlags = 0;
cbDesc.ByteWidth = sizeof(CB_CONTROL_MESH_DISPLAY);
device->CreateBuffer(&cbDesc, NULL, &_constantBuffer);
assert(_constantBuffer);
return true;
}
void
D3D11ControlMeshDisplay::Draw(ID3D11Buffer *buffer, int stride,
const float *modelViewProjectionMatrix) {
if (_displayEdges == false && _displayVertices == false) return;
if (_vertexShader == NULL) createProgram();
if (_vertexShader == NULL) return;
UINT hStrides = stride*sizeof(float);
UINT hOffsets = 0;
_deviceContext->IASetVertexBuffers(0, 1, &buffer, &hStrides, &hOffsets);
D3D11_MAPPED_SUBRESOURCE MappedResource;
_deviceContext->Map(_constantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedResource);
CB_CONTROL_MESH_DISPLAY * pData = (CB_CONTROL_MESH_DISPLAY *)MappedResource.pData;
memcpy(pData->mViewProjection, modelViewProjectionMatrix, sizeof(float) * 16);
_deviceContext->Unmap(_constantBuffer, 0);
_deviceContext->IASetInputLayout(_inputLayout);
_deviceContext->VSSetShader(_vertexShader, NULL, 0);
_deviceContext->HSSetShader(NULL, NULL, 0);
_deviceContext->DSSetShader(NULL, NULL, 0);
_deviceContext->GSSetShader(NULL, NULL, 0);
_deviceContext->PSSetShaderResources(0, 1, &_edgeSharpnessSRV);
_deviceContext->PSSetShader(_pixelShader, NULL, 0);
_deviceContext->RSSetState(_rasterizerState);
_deviceContext->VSSetConstantBuffers(0, 1, &_constantBuffer);
if (_displayEdges) {
_deviceContext->IASetIndexBuffer(_edgeIndices, DXGI_FORMAT_R32_UINT, 0);
_deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
_deviceContext->DrawIndexed(_numEdges * 2, 0, 0);
}
if (_displayVertices) {
// TODO: need geometry shader to draw bigger points
_deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
_deviceContext->Draw(_numPoints, 0);
}
}
void
D3D11ControlMeshDisplay::SetTopology(
OpenSubdiv::Far::TopologyLevel const &level) {
int nEdges = level.GetNumEdges();
int nVerts = level.GetNumVertices();
std::vector<int> edgeIndices;
std::vector<float> edgeSharpnesses;
std::vector<float> vertSharpnesses;
edgeIndices.reserve(nEdges * 2);
edgeSharpnesses.reserve(nEdges);
vertSharpnesses.reserve(nVerts);
for (int i = 0; i < nEdges; ++i) {
OpenSubdiv::Far::ConstIndexArray verts = level.GetEdgeVertices(i);
edgeIndices.push_back(verts[0]);
edgeIndices.push_back(verts[1]);
edgeSharpnesses.push_back(level.GetEdgeSharpness(i));
}
for (int i = 0; i < nVerts; ++i) {
vertSharpnesses.push_back(level.GetVertexSharpness(i));
}
_numEdges = nEdges;
_numPoints = nVerts;
ID3D11Device *device = NULL;
_deviceContext->GetDevice(&device);
SAFE_RELEASE(_edgeIndices);
// create edge index buffer
D3D11_BUFFER_DESC bufferDesc;
ZeroMemory(&bufferDesc, sizeof(bufferDesc));
bufferDesc.ByteWidth = (int)edgeIndices.size() * sizeof(int);
bufferDesc.Usage = D3D11_USAGE_DEFAULT;
bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
bufferDesc.CPUAccessFlags = 0;
bufferDesc.MiscFlags = 0;
bufferDesc.StructureByteStride = sizeof(int);
D3D11_SUBRESOURCE_DATA subData;
ZeroMemory(&subData, sizeof(subData));
subData.pSysMem = &edgeIndices[0];
subData.SysMemPitch = 0;
subData.SysMemSlicePitch = 0;
HRESULT hr = device->CreateBuffer(&bufferDesc, &subData, &_edgeIndices);
assert(_edgeIndices);
// edge sharpness
SAFE_RELEASE(_edgeSharpness);
SAFE_RELEASE(_edgeSharpnessSRV);
ZeroMemory(&bufferDesc, sizeof(bufferDesc));
bufferDesc.ByteWidth = (int)edgeSharpnesses.size() * sizeof(float);
bufferDesc.Usage = D3D11_USAGE_DEFAULT;
bufferDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
bufferDesc.CPUAccessFlags = 0;
bufferDesc.MiscFlags = 0;
bufferDesc.StructureByteStride = sizeof(float);
ZeroMemory(&subData, sizeof(subData));
subData.pSysMem = &edgeSharpnesses[0];
subData.SysMemPitch = 0;
subData.SysMemSlicePitch = 0;
hr = device->CreateBuffer(&bufferDesc, &subData, &_edgeSharpness);
assert(_edgeSharpness);
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
ZeroMemory(&srvDesc, sizeof(srvDesc));
srvDesc.Format = DXGI_FORMAT_R32_FLOAT;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
srvDesc.Buffer.NumElements = _numEdges;
hr = device->CreateShaderResourceView(_edgeSharpness, &srvDesc, &_edgeSharpnessSRV);
assert(_edgeSharpnessSRV);
}

View File

@@ -0,0 +1,48 @@
//
// Copyright 2015 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#ifndef OPENSUBDIV_EXAMPLES_D3D11_CONTROL_MESH_DISPLAY_H
#define OPENSUBDIV_EXAMPLES_D3D11_CONTROL_MESH_DISPLAY_H
#include <d3d11.h>
#include <opensubdiv/far/topologyLevel.h>
class D3D11ControlMeshDisplay {
public:
D3D11ControlMeshDisplay(ID3D11DeviceContext *deviceContext);
~D3D11ControlMeshDisplay();
void Draw(ID3D11Buffer *buffer, int stride,
const float *modelViewProjectionMatrix);
void SetTopology(OpenSubdiv::Far::TopologyLevel const &level);
bool GetEdgesDisplay() const { return _displayEdges; }
void SetEdgesDisplay(bool display) { _displayEdges = display; }
bool GetVerticesDisplay() const { return _displayVertices; }
void SetVerticesDisplay(bool display) { _displayVertices = display; }
private:
bool createProgram();
bool _displayEdges;
bool _displayVertices;
ID3D11DeviceContext *_deviceContext;
ID3D11InputLayout *_inputLayout;
ID3D11VertexShader *_vertexShader;
ID3D11PixelShader *_pixelShader;
ID3D11RasterizerState *_rasterizerState;
ID3D11Buffer *_constantBuffer;
ID3D11ShaderResourceView *_edgeSharpnessSRV;
ID3D11Buffer *_edgeSharpness;
ID3D11Buffer *_edgeIndices;
int _numEdges, _numPoints;
};
#endif // OPENSUBDIV_EXAMPLES_D3D11_CONTROL_MESH_DISPLAY_H

View File

@@ -0,0 +1,266 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#include <D3D11.h>
#include <string.h>
#include <stdio.h>
#include <cassert>
#include "d3d11Hud.h"
#include "d3d11Utils.h"
#include "font_image.h"
#include "../common/simple_math.h"
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
static const char *s_VS =
"cbuffer cbPerFrame : register( b0 )\n"
"{\n"
" matrix g_mViewProjection;\n"
"};\n"
"struct vertexIn { float2 pos : POSITION0; float3 color : COLOR0; float2 uv : TEXCOORD0; };\n"
"struct vertexOut { float4 pos : SV_POSITION; float4 color : COLOR0; float2 uv : TEXCOORD0; };\n"
"vertexOut vs_main(vertexIn IN) {\n"
" vertexOut vout;\n"
" vout.pos = mul(float4(IN.pos.x, IN.pos.y, 0, 1), g_mViewProjection);\n"
" vout.color = float4(IN.color, 1);\n"
" vout.uv = IN.uv;\n"
" return vout;\n"
"}";
static const char *s_PS =
"struct pixelIn { float4 pos : SV_POSITION; float4 color : COLOR0; float2 uv : TEXCOORD0; };\n"
"Texture2D tx : register(t0); \n"
"SamplerState sm : register(s0); \n"
"float4 ps_main(pixelIn IN) : SV_Target {\n"
" float4 c = tx.Sample(sm, IN.uv);\n"
" if( c.a == 0.0 ) \n"
" discard;\n"
" return IN.color * c;\n"
"}";
struct CB_HUD_PROJECTION
{
float mViewProjection[16];
};
D3D11hud::D3D11hud(ID3D11DeviceContext *deviceContext)
: _deviceContext(deviceContext),
_vbo(0), _staticVbo(0), _fontTexture(0), _inputLayout(0),
_shaderResourceView(0), _samplerState(0), _vertexShader(0),
_pixelShader(0), _rasterizerState(0)
{
}
D3D11hud::~D3D11hud()
{
SAFE_RELEASE(_vbo);
SAFE_RELEASE(_staticVbo);
SAFE_RELEASE(_fontTexture);
SAFE_RELEASE(_inputLayout);
SAFE_RELEASE(_shaderResourceView);
SAFE_RELEASE(_samplerState);
SAFE_RELEASE(_vertexShader);
SAFE_RELEASE(_pixelShader);
SAFE_RELEASE(_rasterizerState);
}
void
D3D11hud::Init(int width, int height, int frameBufferWidth, int frameBufferHeight)
{
Hud::Init(width, height, frameBufferWidth, frameBufferHeight);
ID3D11Device *device = NULL;
_deviceContext->GetDevice(&device);
// define font texture
D3D11_TEXTURE2D_DESC texDesc;
texDesc.Width = FONT_TEXTURE_WIDTH;
texDesc.Height = FONT_TEXTURE_HEIGHT;
texDesc.MipLevels = 1;
texDesc.ArraySize = 1;
texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
texDesc.SampleDesc.Count = 1;
texDesc.SampleDesc.Quality = 0;
texDesc.Usage = D3D11_USAGE_DEFAULT;
texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
texDesc.CPUAccessFlags = 0;
texDesc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA subData;
subData.pSysMem = font_image;
subData.SysMemPitch = FONT_TEXTURE_WIDTH*4;
subData.SysMemSlicePitch = FONT_TEXTURE_WIDTH*FONT_TEXTURE_HEIGHT*4;
HRESULT hr = device->CreateTexture2D(&texDesc, &subData, &_fontTexture);
assert(_fontTexture);
// shader resource view
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
ZeroMemory(&srvDesc, sizeof(srvDesc));
srvDesc.Format = texDesc.Format;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MostDetailedMip = 0;
srvDesc.Texture2D.MipLevels = texDesc.MipLevels;
device->CreateShaderResourceView(_fontTexture, &srvDesc, &_shaderResourceView);
assert(_shaderResourceView);
D3D11_SAMPLER_DESC samplerDesc;
ZeroMemory(&samplerDesc, sizeof(samplerDesc));
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
samplerDesc.AddressU = samplerDesc.AddressV = samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.MaxAnisotropy = 1;
samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
device->CreateSamplerState(&samplerDesc, &_samplerState);
assert(_samplerState);
ID3DBlob* pVSBlob;
ID3DBlob* pPSBlob;
pVSBlob = D3D11Utils::CompileShader(s_VS, "vs_main", "vs_4_0");
pPSBlob = D3D11Utils::CompileShader(s_PS, "ps_main", "ps_4_0");
assert(pVSBlob);
assert(pPSBlob);
D3D11_INPUT_ELEMENT_DESC inputElementDesc[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, sizeof(float)*2, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, sizeof(float)*5, D3D11_INPUT_PER_VERTEX_DATA, 0 }
};
device->CreateInputLayout(inputElementDesc, ARRAYSIZE(inputElementDesc),
pVSBlob->GetBufferPointer(),
pVSBlob->GetBufferSize(),
&_inputLayout);
assert(_inputLayout);
device->CreateVertexShader(pVSBlob->GetBufferPointer(),
pVSBlob->GetBufferSize(),
NULL, &_vertexShader);
assert(_vertexShader);
device->CreatePixelShader(pPSBlob->GetBufferPointer(),
pPSBlob->GetBufferSize(),
NULL, &_pixelShader);
assert(_pixelShader);
D3D11_RASTERIZER_DESC rasDesc;
rasDesc.FillMode = D3D11_FILL_SOLID;
rasDesc.CullMode = D3D11_CULL_NONE;
rasDesc.FrontCounterClockwise = FALSE;
rasDesc.DepthBias = 0;
rasDesc.DepthBiasClamp = 0;
rasDesc.SlopeScaledDepthBias = 0.0f;
rasDesc.DepthClipEnable = FALSE;
rasDesc.ScissorEnable = FALSE;
rasDesc.MultisampleEnable = FALSE;
rasDesc.AntialiasedLineEnable = FALSE;
device->CreateRasterizerState(&rasDesc, &_rasterizerState);
assert(_rasterizerState);
// constant buffer
D3D11_BUFFER_DESC cbDesc;
cbDesc.Usage = D3D11_USAGE_DYNAMIC;
cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
cbDesc.MiscFlags = 0;
cbDesc.ByteWidth = sizeof(CB_HUD_PROJECTION);
device->CreateBuffer(&cbDesc, NULL, &_constantBuffer);
assert(_constantBuffer);
}
void
D3D11hud::Rebuild(int width, int height, int framebufferWidth, int framebufferHeight)
{
Hud::Rebuild(width, height, framebufferWidth, framebufferHeight);
SAFE_RELEASE(_staticVbo);
int size = (int)getStaticVboSource().size();
if (size) {
D3D11_BUFFER_DESC bufferDesc;
bufferDesc.ByteWidth = size * sizeof(float);
bufferDesc.Usage = D3D11_USAGE_DEFAULT;
bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bufferDesc.CPUAccessFlags = 0;
bufferDesc.MiscFlags = 0;
bufferDesc.StructureByteStride = 4*sizeof(float);
D3D11_SUBRESOURCE_DATA subData;
subData.pSysMem = &getStaticVboSource()[0];
subData.SysMemPitch = 0;
subData.SysMemSlicePitch = 0;
ID3D11Device *device = NULL;
_deviceContext->GetDevice(&device);
HRESULT hr = device->CreateBuffer(&bufferDesc, &subData, &_staticVbo);
assert(_staticVbo);
_staticVboCount = size / 7;
}
}
bool
D3D11hud::Flush()
{
if (!Hud::Flush())
return false;
// update dynamic text
D3D11_BUFFER_DESC bufferDesc;
bufferDesc.ByteWidth = (int)getVboSource().size() * sizeof(float);
bufferDesc.Usage = D3D11_USAGE_DEFAULT;
bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bufferDesc.CPUAccessFlags = 0;
bufferDesc.MiscFlags = 0;
bufferDesc.StructureByteStride = 4*sizeof(float);
D3D11_SUBRESOURCE_DATA subData;
subData.pSysMem = &getVboSource()[0];
subData.SysMemPitch = 0;
subData.SysMemSlicePitch = 0;
SAFE_RELEASE(_vbo);
ID3D11Device *device = NULL;
_deviceContext->GetDevice(&device);
HRESULT hr = device->CreateBuffer(&bufferDesc, &subData, &_vbo);
assert(_vbo);
int numVertices = (int)getVboSource().size()/7; /* (x, y, r, g, b, u, v) = 7*/
// reserved space of the vector remains for the next frame.
getVboSource().clear();
D3D11_MAPPED_SUBRESOURCE MappedResource;
_deviceContext->Map(_constantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedResource);
CB_HUD_PROJECTION * pData = (CB_HUD_PROJECTION *)MappedResource.pData;
ortho(pData->mViewProjection, 0, 0, (float)GetWidth(), (float)GetHeight());
transpose(pData->mViewProjection);
_deviceContext->Unmap( _constantBuffer, 0 );
// setup graphics pipeline
_deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
_deviceContext->IASetInputLayout(_inputLayout);
_deviceContext->VSSetShader(_vertexShader, NULL, 0);
_deviceContext->HSSetShader(NULL, NULL, 0);
_deviceContext->DSSetShader(NULL, NULL, 0);
_deviceContext->GSSetShader(NULL, NULL, 0);
_deviceContext->PSSetShader(_pixelShader, NULL, 0);
_deviceContext->PSSetShaderResources(0, 1, &_shaderResourceView);
_deviceContext->PSSetSamplers(0, 1, &_samplerState);
_deviceContext->RSSetState(_rasterizerState);
_deviceContext->VSSetConstantBuffers(0, 1, &_constantBuffer);
UINT strides = 7*sizeof(float);
UINT offsets = 0;
_deviceContext->IASetVertexBuffers(0, 1, &_vbo, &strides, &offsets);
_deviceContext->Draw(numVertices, 0);
_deviceContext->IASetVertexBuffers(0, 1, &_staticVbo, &strides, &offsets);
_deviceContext->Draw(_staticVboCount, 0);
return true;
}

View File

@@ -0,0 +1,50 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#ifndef OPENSUBDIV_EXAMPLES_D3D11_HUD_H
#define OPENSUBDIV_EXAMPLES_D3D11_HUD_H
#include <D3D11.h>
#include "hud.h"
class D3D11hud : public Hud
{
public:
D3D11hud(ID3D11DeviceContext *deviceContext);
~D3D11hud();
void Init(int width, int height) {
Init(width, height, width, height);
}
void Rebuild(int width, int height) {
Rebuild(width, height, width, height);
}
virtual void Init(int width, int height, int framebufferWidth, int framebufferHeight);
virtual void Rebuild(int width, int height,
int framebufferWidth, int framebufferHeight);
virtual bool Flush();
private:
ID3D11DeviceContext *_deviceContext;
ID3D11Buffer *_vbo;
ID3D11Buffer *_staticVbo;
ID3D11Texture2D *_fontTexture;
ID3D11InputLayout *_inputLayout;
ID3D11ShaderResourceView *_shaderResourceView;
ID3D11SamplerState *_samplerState;
ID3D11VertexShader *_vertexShader;
ID3D11PixelShader *_pixelShader;
ID3D11RasterizerState *_rasterizerState;
ID3D11Buffer* _constantBuffer;
int _staticVboCount;
};
#endif // OPENSUBDIV_EXAMPLES_D3D11_HUD_H

View File

@@ -0,0 +1,215 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#include "d3d11PtexMipmapTexture.h"
#include "ptexMipmapTextureLoader.h"
#include <opensubdiv/far/error.h> // XXX: to be replaced
#include <D3D11.h>
#include <cassert>
D3D11PtexMipmapTexture::D3D11PtexMipmapTexture()
: _width(0), _height(0), _depth(0),
_layout(0), _texels(0),
_layoutSRV(0), _texelsSRV(0),
_memoryUsage(0)
{
}
D3D11PtexMipmapTexture::~D3D11PtexMipmapTexture()
{
if (_layout) _layout->Release();
if (_layoutSRV) _layoutSRV->Release();
if (_texels) _texels->Release();
if (_texelsSRV) _texelsSRV->Release();
}
/*static*/
const char *
D3D11PtexMipmapTexture::GetShaderSource()
{
static const char *ptexShaderSource =
#include "hlslPtexCommon.gen.h"
;
return ptexShaderSource;
}
static ID3D11Buffer *
genTextureBuffer(ID3D11DeviceContext *deviceContext, int size, void const * data) {
D3D11_BUFFER_DESC hBufferDesc;
hBufferDesc.ByteWidth = size;
hBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
hBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_SHADER_RESOURCE;
hBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
hBufferDesc.MiscFlags = 0;
hBufferDesc.StructureByteStride = sizeof(float);
HRESULT hr;
ID3D11Buffer *buffer;
ID3D11Device *device;
deviceContext->GetDevice(&device);
hr = device->CreateBuffer(&hBufferDesc, NULL, &buffer);
if (FAILED(hr)) {
OpenSubdiv::Far::Error(OpenSubdiv::Far::FAR_RUNTIME_ERROR,
"Fail in CreateBuffer\n");
return 0;
}
D3D11_MAPPED_SUBRESOURCE resource;
hr = deviceContext->Map(buffer, 0,
D3D11_MAP_WRITE_DISCARD, 0, &resource);
if (FAILED(hr)) {
OpenSubdiv::Far::Error(OpenSubdiv::Far::FAR_RUNTIME_ERROR,
"Fail in Map buffer\n");
buffer->Release();
return 0;
}
memcpy(resource.pData, data, size);
deviceContext->Unmap(buffer, 0);
return buffer;
}
D3D11PtexMipmapTexture *
D3D11PtexMipmapTexture::Create(ID3D11DeviceContext *deviceContext,
PtexTexture * reader,
int maxLevels,
size_t targetMemory) {
D3D11PtexMipmapTexture * result = NULL;
int maxNumPages = D3D10_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION;
// Read the ptex data and pack the texels
bool padAlpha = reader->numChannels()==3 && reader->dataType()!=Ptex::dt_float;
PtexMipmapTextureLoader loader(reader,
maxNumPages,
maxLevels,
targetMemory,
true, // seamlessMipmap
padAlpha);
int numChannels = reader->numChannels() + padAlpha,
numFaces = loader.GetNumFaces();
ID3D11Buffer *layout = genTextureBuffer(deviceContext,
numFaces * 6 * sizeof(short),
loader.GetLayoutBuffer());
if (!layout) return NULL;
DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
int bpp = 0;
switch (reader->dataType()) {
case Ptex::dt_uint16:
switch (numChannels) {
case 1: format = DXGI_FORMAT_R16_UINT; break;
case 2: format = DXGI_FORMAT_R16G16_UINT; break;
case 3: assert(false); break;
case 4: format = DXGI_FORMAT_R16G16B16A16_UINT; break;
}
bpp = numChannels * 2;
break;
case Ptex::dt_float:
switch (numChannels) {
case 1: format = DXGI_FORMAT_R32_FLOAT; break;
case 2: format = DXGI_FORMAT_R32G32_FLOAT; break;
case 3: format = DXGI_FORMAT_R32G32B32_FLOAT; break;
case 4: format = DXGI_FORMAT_R32G32B32A32_FLOAT; break;
}
bpp = numChannels * 4;
break;
case Ptex::dt_half:
switch (numChannels) {
case 1: format = DXGI_FORMAT_R16_FLOAT; break;
case 2: format = DXGI_FORMAT_R16G16_FLOAT; break;
case 3: assert(false); break;
case 4: format = DXGI_FORMAT_R16G16B16A16_FLOAT; break;
}
bpp = numChannels * 2;
break;
default:
switch (numChannels) {
case 1: format = DXGI_FORMAT_R8_UNORM; break;
case 2: format = DXGI_FORMAT_R8G8_UNORM; break;
case 3: assert(false); break;
case 4: format = DXGI_FORMAT_R8G8B8A8_UNORM; break;
}
bpp = numChannels;
break;
}
// actual texels texture array
D3D11_TEXTURE2D_DESC desc;
desc.Width = loader.GetPageWidth();
desc.Height = loader.GetPageHeight();
desc.MipLevels = 1;
desc.ArraySize = loader.GetNumPages();
desc.Format = format;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
desc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA *initData = new D3D11_SUBRESOURCE_DATA[desc.ArraySize];
int pageStride = loader.GetPageWidth()*loader.GetPageHeight() * bpp;
for (unsigned int i = 0; i < desc.ArraySize; ++i) {
initData[i].pSysMem = loader.GetTexelBuffer() + i * pageStride;
initData[i].SysMemPitch = loader.GetPageWidth() * bpp;
initData[i].SysMemSlicePitch = pageStride;
}
ID3D11Device *device;
ID3D11Texture2D *texels;
deviceContext->GetDevice(&device);
HRESULT hr = device->CreateTexture2D(&desc, initData, &texels);
if (FAILED(hr)) return NULL;
delete[] initData;
// create SRV
ID3D11ShaderResourceView *layoutSRV;
D3D11_SHADER_RESOURCE_VIEW_DESC srvd;
ZeroMemory(&srvd, sizeof(srvd));
srvd.Format = DXGI_FORMAT_R16_UINT;
srvd.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
srvd.Buffer.FirstElement = 0;
srvd.Buffer.NumElements = numFaces * 6;
hr = device->CreateShaderResourceView(layout, &srvd, &layoutSRV);
if (FAILED(hr)) return NULL;
ID3D11ShaderResourceView *texelsSRV;
ZeroMemory(&srvd, sizeof(srvd));
srvd.Format = format;
srvd.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
srvd.Texture2DArray.MipLevels = 1;
srvd.Texture2DArray.ArraySize = desc.ArraySize;
hr = device->CreateShaderResourceView(texels, &srvd, &texelsSRV);
if (FAILED(hr)) return NULL;
result = new D3D11PtexMipmapTexture;
result->_width = loader.GetPageWidth();
result->_height = loader.GetPageHeight();
result->_depth = loader.GetNumPages();
result->_format = format;
result->_layout = layout;
result->_texels = texels;
result->_layoutSRV = layoutSRV;
result->_texelsSRV = texelsSRV;
result->_memoryUsage = loader.GetMemoryUsage();
return result;
}

View File

@@ -0,0 +1,63 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#ifndef OPENSUBDIV_EXAMPLES_D3D11_PTEX_MIPMAP_TEXTURE_H
#define OPENSUBDIV_EXAMPLES_D3D11_PTEX_MIPMAP_TEXTURE_H
#include <opensubdiv/osd/nonCopyable.h>
#include <Ptexture.h>
struct ID3D11Buffer;
struct ID3D11Texture2D;
struct ID3D11DeviceContext;
struct ID3D11ShaderResourceView;
class D3D11PtexMipmapTexture : OpenSubdiv::Osd::NonCopyable<D3D11PtexMipmapTexture> {
public:
static D3D11PtexMipmapTexture * Create(ID3D11DeviceContext *deviceContext,
PtexTexture * reader,
int maxLevels=10,
size_t targetMemory=0);
/// Returns GLSL shader snippet to fetch ptex
static const char *GetShaderSource();
/// Returns the texture buffer containing the layout of the ptex faces
/// in the texels texture array.
ID3D11Buffer *GetLayoutTextureBuffer() const { return _layout; }
ID3D11ShaderResourceView **GetLayoutSRV() { return &_layoutSRV; }
/// Returns the texels texture array.
ID3D11Texture2D *GetTexelsTexture() const { return _texels; }
ID3D11ShaderResourceView **GetTexelsSRV() { return &_texelsSRV; }
/// Returns the amount of allocated memory (in byte)
size_t GetMemoryUsage() const { return _memoryUsage; }
~D3D11PtexMipmapTexture();
private:
D3D11PtexMipmapTexture();
int _width, // width / height / depth of the 3D texel buffer
_height,
_depth;
int _format; // texel color format
ID3D11Buffer *_layout; // per-face lookup table
ID3D11Texture2D *_texels; // texel data
ID3D11ShaderResourceView *_layoutSRV;
ID3D11ShaderResourceView *_texelsSRV;
size_t _memoryUsage; // total amount of memory used (estimate)
};
#endif // OPENSUBDIV_EXAMPLES_D3D11_PTEX_TEXTURE_H

View File

@@ -0,0 +1,169 @@
//
// Copyright 2015 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#include "d3d11ShaderCache.h"
#include <D3D11.h>
#include <D3Dcompiler.h>
#include <opensubdiv/far/error.h>
D3D11DrawConfig::D3D11DrawConfig()
: _vertexShader(NULL), _hullShader(NULL), _domainShader(NULL),
_geometryShader(NULL), _pixelShader(NULL) {
}
D3D11DrawConfig::~D3D11DrawConfig() {
if (_vertexShader) _vertexShader->Release();
if (_hullShader) _hullShader->Release();
if (_domainShader) _domainShader->Release();
if (_geometryShader) _geometryShader->Release();
if (_pixelShader) _pixelShader->Release();
}
static ID3DBlob *
_CompileShader(std::string const &target,
std::string const &entry,
std::string const &shaderSource) {
DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
#ifdef _DEBUG
dwShaderFlags |= D3DCOMPILE_DEBUG;
#endif
ID3DBlob* pBlob = NULL;
ID3DBlob* pBlobError = NULL;
HRESULT hr = D3DCompile(shaderSource.c_str(), shaderSource.size(),
NULL, NULL, NULL,
entry.c_str(), target.c_str(),
dwShaderFlags, 0, &pBlob, &pBlobError);
if (FAILED(hr)) {
if ( pBlobError != NULL ) {
OpenSubdiv::Far::Error(OpenSubdiv::Far::FAR_RUNTIME_ERROR,
"Error compiling HLSL shader: %s\n",
(CHAR*)pBlobError->GetBufferPointer());
pBlobError->Release();
return NULL;
}
}
return pBlob;
}
bool
D3D11DrawConfig::CompileVertexShader(const std::string &target,
const std::string &entry,
const std::string &source,
ID3D11InputLayout ** ppInputLayout,
D3D11_INPUT_ELEMENT_DESC const * pInputElementDescs,
int numInputElements,
ID3D11Device * pd3dDevice) {
ID3DBlob * pBlob = NULL;
pBlob = _CompileShader(target, entry, source);
HRESULT hr = pd3dDevice->CreateVertexShader(pBlob->GetBufferPointer(),
pBlob->GetBufferSize(),
NULL,
&_vertexShader);
if (FAILED(hr)) {
return false;
}
if (ppInputLayout && !*ppInputLayout) {
hr = pd3dDevice->CreateInputLayout(
pInputElementDescs, numInputElements,
pBlob->GetBufferPointer(),
pBlob->GetBufferSize(), ppInputLayout);
if (FAILED(hr)) {
return false;
}
}
if (pBlob) pBlob->Release();
return true;
}
bool
D3D11DrawConfig::CompileHullShader(const std::string &target,
const std::string &entry,
const std::string &source,
ID3D11Device * pd3dDevice) {
ID3DBlob * pBlob = NULL;
pBlob = _CompileShader(target, entry, source);
HRESULT hr = pd3dDevice->CreateHullShader(pBlob->GetBufferPointer(),
pBlob->GetBufferSize(),
NULL,
&_hullShader);
if (FAILED(hr)) {
return false;
}
if (pBlob) pBlob->Release();
return true;
}
bool
D3D11DrawConfig::CompileDomainShader(const std::string &target,
const std::string &entry,
const std::string &source,
ID3D11Device * pd3dDevice) {
ID3DBlob * pBlob = NULL;
pBlob = _CompileShader(target, entry, source);
HRESULT hr = pd3dDevice->CreateDomainShader(pBlob->GetBufferPointer(),
pBlob->GetBufferSize(),
NULL,
&_domainShader);
if (FAILED(hr)) {
return false;
}
if (pBlob) pBlob->Release();
return true;
}
bool
D3D11DrawConfig::CompileGeometryShader(const std::string &target,
const std::string &entry,
const std::string &source,
ID3D11Device * pd3dDevice) {
ID3DBlob * pBlob = NULL;
pBlob = _CompileShader(target, entry, source);
HRESULT hr = pd3dDevice->CreateGeometryShader(pBlob->GetBufferPointer(),
pBlob->GetBufferSize(),
NULL,
&_geometryShader);
if (FAILED(hr)) {
return false;
}
if (pBlob) pBlob->Release();
return true;
}
bool
D3D11DrawConfig::CompilePixelShader(const std::string &target,
const std::string &entry,
const std::string &source,
ID3D11Device * pd3dDevice) {
ID3DBlob * pBlob = NULL;
pBlob = _CompileShader(target, entry, source);
HRESULT hr = pd3dDevice->CreatePixelShader(pBlob->GetBufferPointer(),
pBlob->GetBufferSize(),
NULL,
&_pixelShader);
if (FAILED(hr)) {
return false;
}
if (pBlob) pBlob->Release();
return true;
}

View File

@@ -0,0 +1,76 @@
//
// Copyright 2015 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#ifndef OPENSUBDIV_EXAMPLES_D3D11_SHADER_CACHE_H
#define OPENSUBDIV_EXAMPLES_D3D11_SHADER_CACHE_H
#include <string>
#include "./shaderCache.h"
struct ID3D11VertexShader;
struct ID3D11HullShader;
struct ID3D11DomainShader;
struct ID3D11GeometryShader;
struct ID3D11PixelShader;
struct ID3D11Device;
struct ID3D11InputLayout;
struct D3D11_INPUT_ELEMENT_DESC;
class D3D11DrawConfig {
public:
D3D11DrawConfig();
~D3D11DrawConfig();
bool CompileVertexShader(const std::string &target,
const std::string &entry,
const std::string &source,
ID3D11InputLayout ** ppInputLayout,
D3D11_INPUT_ELEMENT_DESC const *pInputElementDescs,
int numInputElements,
ID3D11Device * pd3dDevice);
bool CompileHullShader(const std::string &target,
const std::string &entry,
const std::string &source,
ID3D11Device * pd3dDevice);
bool CompileDomainShader(const std::string &target,
const std::string &entry,
const std::string &source,
ID3D11Device * pd3dDevice);
bool CompileGeometryShader(const std::string &target,
const std::string &entry,
const std::string &source,
ID3D11Device * pd3dDevice);
bool CompilePixelShader(const std::string &target,
const std::string &entry,
const std::string &source,
ID3D11Device * pd3dDevice);
ID3D11VertexShader *GetVertexShader() const { return _vertexShader; }
ID3D11HullShader *GetHullShader() const { return _hullShader; }
ID3D11DomainShader *GetDomainShader() const { return _domainShader; }
ID3D11GeometryShader *GetGeometryShader() const { return _geometryShader; }
ID3D11PixelShader *GetPixelShader() const { return _pixelShader; }
private:
ID3D11VertexShader *_vertexShader;
ID3D11HullShader *_hullShader;
ID3D11DomainShader *_domainShader;
ID3D11GeometryShader *_geometryShader;
ID3D11PixelShader *_pixelShader;
};
// workaround for template alias
#if 0
template <typename DESC_TYPE>
using D3D11ShaderCache = ShaderCacheT<DESC_TYPE, D3D11DrawConfig>;
#else
template <typename DESC_TYPE>
class D3D11ShaderCache : public ShaderCacheT<DESC_TYPE, D3D11DrawConfig> {
};
#endif
#endif // OPENSUBDIV_EXAMPLES_D3D11_SHADER_CACHE_H

View File

@@ -0,0 +1,37 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#include "d3d11Utils.h"
#include <D3DCompiler.h>
namespace D3D11Utils {
ID3DBlob *
CompileShader(const char *src, const char *entry, const char *spec) {
DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
#if defined(DEBUG) || defined(_DEBUG)
dwShaderFlags |= D3DCOMPILE_DEBUG;
#endif
ID3DBlob *pErrorBlob;
ID3DBlob *pBlob;
HRESULT hr = D3DCompile(src, strlen(src),
NULL,NULL,NULL, entry, spec,
dwShaderFlags, 0, &pBlob, &pErrorBlob);
if (FAILED(hr)) {
if (pErrorBlob) {
OutputDebugStringA((char*)pErrorBlob->GetBufferPointer());
pErrorBlob->Release();
}
return NULL;
}
if (pErrorBlob)
pErrorBlob->Release();
return pBlob;
}
} // D3D11Utils

View File

@@ -0,0 +1,19 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#ifndef OPENSUBDIV_EXAMPLES_D3D11_COMPILE_H
#define OPENSUBDIV_EXAMPLES_D3D11_COMPILE_H
#include <D3DCompiler.h>
namespace D3D11Utils {
ID3DBlob *CompileShader(const char *src, const char *entry, const char *spec);
}
#endif // OPENSUBDIV_EXAMPLES_D3D11_COMPILE_H

View File

@@ -0,0 +1,91 @@
#
# Copyright 2013 Pixar
#
Licensed under the terms set forth in the LICENSE.txt file available at
https://opensubdiv.org/license.
#
import maya.OpenMaya as OpenMaya
selectionList = OpenMaya.MSelectionList()
OpenMaya.MGlobal.getActiveSelectionList(selectionList)
path = OpenMaya.MDagPath()
selectionList.getDagPath(0, path)
meshFn = OpenMaya.MFnMesh(path)
points = OpenMaya.MPointArray()
normals = OpenMaya.MFloatVectorArray()
u = OpenMaya.MFloatArray()
v = OpenMaya.MFloatArray()
meshFn.getPoints(points)
meshFn.getVertexNormals(True, normals);
meshFn.getUVs(u, v, "map1")
vertexCount = OpenMaya.MIntArray()
vertexList = OpenMaya.MIntArray()
meshFn.getVertices(vertexCount, vertexList)
edgeIds = OpenMaya.MUintArray()
edgeCreaseData = OpenMaya.MDoubleArray()
vtxIds = OpenMaya.MUintArray()
vtxCreaseData = OpenMaya.MDoubleArray()
try:
meshFn.getCreaseEdges(edgeIds, edgeCreaseData)
except:
pass
try:
meshFn.getCreaseVertices(vtxIds, vtxCreaseData)
except:
pass
f = open('out.obj', 'w')
for i in range(0,points.length()):
f.write('v %f %f %f\n' % (points[i].x, points[i].y, points[i].z))
for i in range(0,u.length()):
f.write('vt %f %f \n' % (u[i], v[i]))
for i in range(0,normals.length()):
f.write('vn %f %f %f\n' % (normals[i].x, normals[i].y, normals[i].z))
f.write('s off\n')
vindex = 0
for i in range(0,vertexCount.length()):
f.write('f')
for j in range(0, vertexCount[i]):
v = vertexList[vindex] + 1
sutil = OpenMaya.MScriptUtil()
sutil.createFromInt(0)
uvptr = sutil.asIntPtr()
meshFn.getPolygonUVid(i, j, uvptr, 'map1')
uv = sutil.getInt(uvptr) + 1
f.write(' %d/%d/%d' % (v, uv, v))
vindex = vindex+1
f.write('\n')
if vtxIds.length() > 0:
f.write('t corner %d/%d/0' % (vtxIds.length(), vtxIds.length()))
for i in range(0,vtxIds.length()):
f.write(' %d' % vtxIds[i])
for i in range(0,vtxCreaseData.length()):
f.write(' %f' % vtxCreaseData[i])
f.write('\n')
for i in range(0, edgeIds.length()):
edgeIt = OpenMaya.MItMeshEdge(path)
dummy = OpenMaya.MScriptUtil().asIntPtr()
edgeIt.setIndex(edgeIds[i], dummy)
faceList = OpenMaya.MIntArray()
edgeIt.getConnectedFaces(faceList)
vid0 = edgeIt.index(0)
vid1 = edgeIt.index(1)
f.write('t crease 2/1/0 %d %d %f\n' % (vid0, vid1, edgeCreaseData[i]))
f.close()

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,30 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#ifndef FONT_IMAGE_H
#define FONT_IMAGE_H
#define FONT_TEXTURE_WIDTH 128
#define FONT_TEXTURE_HEIGHT 128
#define FONT_TEXTURE_COLUMNS 16
#define FONT_TEXTURE_ROWS 8
#define FONT_CHAR_WIDTH (FONT_TEXTURE_WIDTH/FONT_TEXTURE_COLUMNS)
#define FONT_CHAR_HEIGHT (FONT_TEXTURE_HEIGHT/FONT_TEXTURE_ROWS)
#define FONT_CHECK_BOX_OFF 0x2
#define FONT_CHECK_BOX_ON 0x3
#define FONT_RADIO_BUTTON_OFF 0x4
#define FONT_RADIO_BUTTON_ON 0x5
#define FONT_SLIDER_LEFT 0x10
#define FONT_SLIDER_MIDDLE 0x11
#define FONT_SLIDER_RIGHT 0x12
#define FONT_SLIDER_CURSOR 0x13
#define FONT_ARROW_RIGHT 0x14
#define FONT_ARROW_DOWN 0x15
extern unsigned char font_image[];
#endif // FONT_IMAGE_H

View File

@@ -0,0 +1,213 @@
//
// Copyright 2015 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#include "glLoader.h"
#include "glControlMeshDisplay.h"
#include "glUtils.h"
#include <vector>
GLControlMeshDisplay::GLControlMeshDisplay() :
_displayEdges(true), _displayVertices(false),
_program(0), _vao(0),
_vertSharpness(0), _edgeSharpnessTexture(0), _edgeIndices(0),
_numEdges(0), _numPoints(0) {
}
GLControlMeshDisplay::~GLControlMeshDisplay() {
if (_program) glDeleteProgram(_program);
if (_vertSharpness) glDeleteBuffers(1, &_vertSharpness);
if (_edgeSharpnessTexture) glDeleteTextures(1, &_edgeSharpnessTexture);
if (_edgeIndices) glDeleteBuffers(1, &_edgeIndices);
if (_vao) glDeleteVertexArrays(1, &_vao);
}
bool
GLControlMeshDisplay::createProgram() {
if (_program != 0) glDeleteProgram(_program);
const std::string glsl_version = GLUtils::GetShaderVersionInclude();
static const std::string vsSrc =
glsl_version +
"in vec3 position; \n"
"in float vertSharpness; \n"
"out float sharpness; \n"
"uniform mat4 mvpMatrix; \n"
"void main() { \n"
" sharpness = vertSharpness; \n"
" gl_Position = mvpMatrix * vec4(position, 1); \n"
"} \n";
static const std::string fsSrc =
glsl_version +
"in float sharpness; \n"
"out vec4 color; \n"
"uniform int drawMode = 0; \n"
"uniform samplerBuffer edgeSharpness; \n"
"vec4 sharpnessToColor(float s) { \n"
" // 0.0 2.0 4.0 \n"
" // green --- yellow --- red \n"
" return vec4(min(1, s * 0.5), \n"
" min(1, 2 - s * 0.5), \n"
" 0, 1); \n"
"} \n"
"void main() { \n"
" float sharp = sharpness; \n"
" if (drawMode == 1) { \n"
" sharp = texelFetch(edgeSharpness, gl_PrimitiveID).x; \n"
" } \n"
" color = sharpnessToColor(sharp); \n"
"} \n";
GLuint vertexShader =
GLUtils::CompileShader(GL_VERTEX_SHADER, vsSrc.c_str());
GLuint fragmentShader =
GLUtils::CompileShader(GL_FRAGMENT_SHADER, fsSrc.c_str());
_program = glCreateProgram();
glAttachShader(_program, vertexShader);
glAttachShader(_program, fragmentShader);
glLinkProgram(_program);
GLint status;
glGetProgramiv(_program, GL_LINK_STATUS, &status);
if (status == GL_FALSE) {
GLint infoLogLength;
glGetProgramiv(_program, GL_INFO_LOG_LENGTH, &infoLogLength);
char *infoLog = new char[infoLogLength];
glGetProgramInfoLog(_program, infoLogLength, NULL, infoLog);
printf("%s\n", infoLog);
delete[] infoLog;
exit(1);
return false;
}
_uniformMvpMatrix =
glGetUniformLocation(_program, "mvpMatrix");
_uniformDrawMode =
glGetUniformLocation(_program, "drawMode");
_uniformEdgeSharpness =
glGetUniformLocation(_program, "edgeSharpness");
_attrPosition = glGetAttribLocation(_program, "position");
_attrVertSharpness = glGetAttribLocation(_program, "vertSharpness");
return true;
}
void
GLControlMeshDisplay::Draw(GLuint vbo, GLint stride,
const float *modelViewProjectionMatrix) {
if (_program == 0) {
createProgram();
if (_program == 0) return;
}
if (_vao == 0) {
glGenVertexArrays(1, &_vao);
}
glBindVertexArray(_vao);
glUseProgram(_program);
glUniformMatrix4fv(_uniformMvpMatrix,
1, GL_FALSE, modelViewProjectionMatrix);
glUniform1i(_uniformEdgeSharpness, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_BUFFER, _edgeSharpnessTexture);
// bind vbo to points
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(_attrPosition, 3, GL_FLOAT, GL_FALSE, stride, 0);
glBindBuffer(GL_ARRAY_BUFFER, _vertSharpness);
glVertexAttribPointer(_attrVertSharpness, 1, GL_FLOAT, GL_FALSE, 0, 0);
glPointSize(10.0);
// draw edges
if (_displayEdges) {
glUniform1i(_uniformDrawMode, 1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _edgeIndices);
glDrawElements(GL_LINES, _numEdges*2, GL_UNSIGNED_INT, 0);
}
// draw vertices
if (_displayVertices) {
glUniform1i(_uniformDrawMode, 0);
glDrawArrays(GL_POINTS, 0, _numPoints);
}
glPointSize(1.0f);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glUseProgram(0);
}
void
GLControlMeshDisplay::SetTopology(OpenSubdiv::Far::TopologyLevel const &level) {
int nEdges = level.GetNumEdges();
int nVerts = level.GetNumVertices();
std::vector<int> edgeIndices;
std::vector<float> edgeSharpnesses;
std::vector<float> vertSharpnesses;
edgeIndices.reserve(nEdges * 2);
edgeSharpnesses.reserve(nEdges);
vertSharpnesses.reserve(nVerts);
for (int i = 0; i < nEdges; ++i) {
OpenSubdiv::Far::ConstIndexArray verts = level.GetEdgeVertices(i);
edgeIndices.push_back(verts[0]);
edgeIndices.push_back(verts[1]);
edgeSharpnesses.push_back(level.GetEdgeSharpness(i));
}
for (int i = 0; i < nVerts; ++i) {
vertSharpnesses.push_back(level.GetVertexSharpness(i));
}
if (_vertSharpness == 0) glGenBuffers(1, &_vertSharpness);
if (_edgeIndices == 0) glGenBuffers(1, &_edgeIndices);
if (_edgeSharpnessTexture == 0) glGenTextures(1, &_edgeSharpnessTexture);
GLuint buffer = 0;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertSharpness);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*nVerts,
&vertSharpnesses[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, _edgeIndices);
glBufferData(GL_ARRAY_BUFFER, sizeof(int)*nEdges*2,
&edgeIndices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*nEdges,
&edgeSharpnesses[0], GL_STATIC_DRAW);
glBindTexture(GL_TEXTURE_BUFFER, _edgeSharpnessTexture);
glTexBuffer(GL_TEXTURE_BUFFER, GL_R32F, buffer);
glBindTexture(GL_TEXTURE_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDeleteBuffers(1, &buffer);
_numEdges = nEdges;
_numPoints = nVerts;
}

View File

@@ -0,0 +1,51 @@
//
// Copyright 2015 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#ifndef OPENSUBDIV_EXAMPLES_GL_CONTROL_MESH_DISPLAY_H
#define OPENSUBDIV_EXAMPLES_GL_CONTROL_MESH_DISPLAY_H
#include "glLoader.h"
#include <opensubdiv/far/topologyLevel.h>
class GLControlMeshDisplay {
public:
GLControlMeshDisplay();
~GLControlMeshDisplay();
void Draw(GLuint pointsVBO, GLint stride,
const float *modelViewProjectionMatrix);
void SetTopology(OpenSubdiv::Far::TopologyLevel const &level);
bool GetEdgesDisplay() const { return _displayEdges; }
void SetEdgesDisplay(bool display) { _displayEdges = display; }
bool GetVerticesDisplay() const { return _displayVertices; }
void SetVerticesDisplay(bool display) { _displayVertices = display; }
private:
bool createProgram();
bool _displayEdges;
bool _displayVertices;
GLuint _program;
GLuint _uniformMvpMatrix;
GLuint _uniformDrawMode;
GLuint _uniformEdgeSharpness;
GLuint _attrPosition;
GLuint _attrVertSharpness;
GLuint _vao;
GLuint _vertSharpness;
GLuint _edgeSharpnessTexture;
GLuint _edgeIndices;
int _numEdges, _numPoints;
};
#endif // OPENSUBDIV_EXAMPLES_GL_CONTROL_MESH_DISPLAY_H

View File

@@ -0,0 +1,295 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#include "glLoader.h"
#include "glHud.h"
#include "glUtils.h"
#include "font_image.h"
#include "simple_math.h"
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cassert>
#include <iostream>
static const char *s_VS =
#if defined(GL_VERSION_3_1)
"#version 150\n"
"in vec2 position;\n"
"in vec3 color;\n"
"in vec2 uv;\n"
"out vec4 fragColor;\n"
"out vec2 fragUV;\n"
"uniform mat4 ModelViewProjectionMatrix;\n"
"void main() {\n"
" fragColor = vec4(color, 1);\n"
" fragUV = uv;\n"
" gl_Position = ModelViewProjectionMatrix * "
" vec4(position.x, position.y, 0, 1);\n"
"}\n";
#else
"attribute vec2 position;\n"
"attribute vec3 color;\n"
"attribute vec2 uv;\n"
"varying vec4 fragColor;\n"
"varying vec2 fragUV;\n"
"uniform mat4 ModelViewProjectionMatrix;\n"
"void main() {\n"
" fragColor = vec4(color, 1);\n"
" fragUV = uv;\n"
" gl_Position = ModelViewProjectionMatrix * "
" vec4(position.x, position.y, 0, 1);\n"
"}\n";
#endif
static const char *s_FS =
#if defined(GL_VERSION_3_1)
"#version 150\n"
"in vec4 fragColor;\n"
"in vec2 fragUV;\n"
"out vec4 color;\n"
"uniform sampler2D fontTexture;\n"
"void main() {\n"
" vec4 c = texture(fontTexture, fragUV);\n"
" if (c.a == 0.0) discard;\n"
" color = c*fragColor;\n"
"}\n";
#else
"varying vec4 fragColor;\n"
"varying vec2 fragUV;\n"
"uniform sampler2D fontTexture;\n"
"void main()\n"
"{\n"
" vec4 c = texture2D(fontTexture, fragUV);\n"
" if (c.a == 0.0) discard;\n"
" gl_FragColor = c*fragColor;\n"
"}\n";
#endif
static const char *s_BG_VS =
#if defined(GL_VERSION_3_1)
"#version 150\n"
"out vec2 uv;\n"
"void main() {\n"
" vec4 pos[4] = vec4[] (vec4(-1,-1,0,1), vec4(1,-1,0,1), \n"
" vec4(-1,1,0,1), vec4(1,1,0,1)); \n"
" uv = pos[gl_VertexID].xy;\n"
" gl_Position = pos[gl_VertexID];\n"
"}\n";
#else
"varying vec2 uv;\n"
"void main() {\n"
" vec4 pos[4] = vec4[] (vec4(-1,-1,0,1), vec4(1,-1,0,1), \n"
" vec4(-1,1,0,1), vec4(1,1,0,1)); \n"
" uv = pos[gl_VertexID].xy;\n"
" gl_Position = pos[gl_VertexID];\n"
"}\n";
#endif
static const char *s_BG_FS =
#if defined(GL_VERSION_3_1)
"#version 150\n"
"in vec2 uv;\n"
"out vec4 color;\n"
"void main() {\n"
" color = vec4(mix(0.1, 0.5, sin((uv.y*0.5+0.5)*3.14159)));\n"
" color.a = 1.0;\n"
"}\n";
#else
"varying vec2 uv;\n"
"void main() {\n"
" gl_FragColor = vec4(mix(0.1, 0.5, sin((uv.y*0.5+0.5)*3.14159)));\n"
" gl_FragColor.a = 1.0;\n"
"}\n";
#endif
GLhud::GLhud() : _fontTexture(0), _vbo(0), _staticVbo(0),
_vao(0), _staticVao(0), _program(0),
_aPosition(0), _aColor(0), _aUV(0), _bgProgram(0) {
}
GLhud::~GLhud() {
if (_program)
glDeleteProgram(_program);
if (_fontTexture)
glDeleteTextures(1, &_fontTexture);
if (_vbo)
glDeleteBuffers(1, &_vbo);
if (_staticVbo)
glDeleteBuffers(1, &_staticVbo);
if (_vao)
glDeleteVertexArrays(1, &_vao);
if (_staticVao)
glDeleteVertexArrays(1, &_staticVao);
if (_bgVao)
glDeleteVertexArrays(1, &_bgVao);
if (_bgProgram)
glDeleteProgram(_bgProgram);
}
void
GLhud::Init(int width, int height, int frameBufferWidth, int frameBufferHeight) {
Hud::Init(width, height, frameBufferWidth, frameBufferHeight);
glGenTextures(1, &_fontTexture);
glBindTexture(GL_TEXTURE_2D, _fontTexture);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
FONT_TEXTURE_WIDTH, FONT_TEXTURE_HEIGHT,
0, GL_RGBA, GL_UNSIGNED_BYTE, font_image);
glGenBuffers(1, &_vbo);
glGenBuffers(1, &_staticVbo);
glGenVertexArrays(1, &_vao);
glGenVertexArrays(1, &_staticVao);
glGenVertexArrays(1, &_bgVao);
GLuint vertexShader = GLUtils::CompileShader(GL_VERTEX_SHADER, s_VS);
GLuint fragmentShader = GLUtils::CompileShader(GL_FRAGMENT_SHADER, s_FS);
_program = glCreateProgram();
glAttachShader(_program, vertexShader);
glAttachShader(_program, fragmentShader);
glLinkProgram(_program);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
GLint status;
glGetProgramiv(_program, GL_LINK_STATUS, &status);
if (status == GL_FALSE) {
GLint infoLogLength;
glGetProgramiv(_program, GL_INFO_LOG_LENGTH, &infoLogLength);
char *infoLog = new char[infoLogLength];
glGetProgramInfoLog(_program, infoLogLength, NULL, infoLog);
printf("%s\n", infoLog);
delete[] infoLog;
}
_mvpMatrix = glGetUniformLocation(_program, "ModelViewProjectionMatrix");
_aPosition = glGetAttribLocation(_program, "position");
_aColor = glGetAttribLocation(_program, "color");
_aUV = glGetAttribLocation(_program, "uv");
glBindVertexArray(_vao);
glEnableVertexAttribArray(_aPosition);
glEnableVertexAttribArray(_aColor);
glEnableVertexAttribArray(_aUV);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glVertexAttribPointer(_aPosition, 2, GL_FLOAT, GL_FALSE,
sizeof(GLfloat)*7, (void*)0);
glVertexAttribPointer(_aColor, 3, GL_FLOAT, GL_FALSE,
sizeof(GLfloat)*7, (void*)(sizeof(GLfloat)*2));
glVertexAttribPointer(_aUV, 2, GL_FLOAT, GL_FALSE,
sizeof(GLfloat)*7, (void*)(sizeof(GLfloat)*5));
glBindVertexArray(_staticVao);
glEnableVertexAttribArray(_aPosition);
glEnableVertexAttribArray(_aColor);
glEnableVertexAttribArray(_aUV);
glBindBuffer(GL_ARRAY_BUFFER, _staticVbo);
glVertexAttribPointer(_aPosition, 2, GL_FLOAT, GL_FALSE,
sizeof(GLfloat)*7, (void*)0);
glVertexAttribPointer(_aColor, 3, GL_FLOAT, GL_FALSE,
sizeof(GLfloat)*7, (void*)(sizeof(GLfloat)*2));
glVertexAttribPointer(_aUV, 2, GL_FLOAT, GL_FALSE,
sizeof(GLfloat)*7, (void*)(sizeof(GLfloat)*5));
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// ------ create bg program
vertexShader = GLUtils::CompileShader(GL_VERTEX_SHADER, s_BG_VS);
fragmentShader = GLUtils::CompileShader(GL_FRAGMENT_SHADER, s_BG_FS);
_bgProgram = glCreateProgram();
glAttachShader(_bgProgram, vertexShader);
glAttachShader(_bgProgram, fragmentShader);
glLinkProgram(_bgProgram);
GLUtils::CheckGLErrors("GLhud::Init");
}
void
GLhud::Rebuild(int width, int height,
int framebufferWidth, int framebufferHeight) {
Hud::Rebuild(width, height, framebufferWidth, framebufferHeight);
if (! _staticVbo)
return;
_staticVboSize = (int)getStaticVboSource().size();
glBindBuffer(GL_ARRAY_BUFFER, _staticVbo);
glBufferData(GL_ARRAY_BUFFER, _staticVboSize * sizeof(float),
&getStaticVboSource()[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
bool
GLhud::Flush() {
if (!Hud::Flush())
return false;
// update dynamic text
glBindVertexArray(_vao);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, getVboSource().size() * sizeof(float),
&getVboSource()[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// (x, y, r, g, b, u, v) = 7
int numVertices = (int)getVboSource().size()/7;
// reserved space of the vector remains for the next frame.
getVboSource().clear();
glUseProgram(_program);
float proj[16];
ortho(proj, 0, 0, float(GetWidth()), float(GetHeight()));
glUniformMatrix4fv(_mvpMatrix, 1, GL_FALSE, proj);
glDisable(GL_DEPTH_TEST);
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _fontTexture);
glBindVertexArray(_vao);
glDrawArrays(GL_TRIANGLES, 0, numVertices);
glBindVertexArray(_staticVao);
glDrawArrays(GL_TRIANGLES, 0, _staticVboSize/7);
glBindTexture(GL_TEXTURE_2D, 0);
}
glEnable(GL_DEPTH_TEST);
return true;
}
void
GLhud::FillBackground() {
glUseProgram(_bgProgram);
glBindVertexArray(_bgVao);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glUseProgram(0);
glBindVertexArray(0);
}

View File

@@ -0,0 +1,46 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#ifndef OPENSUBDIV_EXAMPLES_GL_HUD_H
#define OPENSUBDIV_EXAMPLES_GL_HUD_H
#include "glLoader.h"
#include "hud.h"
class GLhud : public Hud {
public:
GLhud();
~GLhud();
virtual void Init(int width, int height, int framebufferWidth, int framebufferHeight);
virtual void Rebuild(int width, int height,
int framebufferWidth, int framebufferHeight);
virtual bool Flush();
GLuint GetFontTexture() const {
return _fontTexture;
}
void FillBackground();
private:
GLuint _fontTexture;
GLuint _vbo, _staticVbo;
GLuint _vao, _staticVao, _bgVao;
int _staticVboSize;
GLint _program;
GLint _mvpMatrix;
GLint _aPosition, _aColor, _aUV;
GLint _bgProgram;
};
#endif // OPENSUBDIV_EXAMPLES_GL_HUD_H

View File

@@ -0,0 +1,143 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#include "glLoader.h"
#include "glPtexMipmapTexture.h"
#include "ptexMipmapTextureLoader.h"
GLPtexMipmapTexture::GLPtexMipmapTexture()
: _width(0), _height(0), _depth(0), _layout(0), _texels(0), _memoryUsage(0)
{
}
GLPtexMipmapTexture::~GLPtexMipmapTexture()
{
if (glIsTexture(_layout))
glDeleteTextures(1, &_layout);
if (glIsTexture(_texels))
glDeleteTextures(1, &_texels);
}
/*static*/
const char *
GLPtexMipmapTexture::GetShaderSource()
{
static const char *ptexShaderSource =
#include "glslPtexCommon.gen.h"
;
return ptexShaderSource;
}
static GLuint
genTextureBuffer(GLenum format, GLsizeiptr size, GLvoid const * data)
{
GLuint buffer = 0;
GLuint result = 0;
#if defined(GL_ARB_direct_state_access)
if (OSD_OPENGL_HAS(ARB_direct_state_access)) {
glCreateBuffers(1, &buffer);
glNamedBufferData(buffer, size, data, GL_STATIC_DRAW);
glCreateTextures(GL_TEXTURE_BUFFER, 1, &result);
glTextureBuffer(result, format, buffer);
} else
#endif
{
glGenBuffers(1, &buffer);
glBindBuffer(GL_TEXTURE_BUFFER, buffer);
glBufferData(GL_TEXTURE_BUFFER, size, data, GL_STATIC_DRAW);
glGenTextures(1, & result);
glBindTexture(GL_TEXTURE_BUFFER, result);
glTexBuffer(GL_TEXTURE_BUFFER, format, buffer);
// need to reset texture binding before deleting the source buffer.
glBindTexture(GL_TEXTURE_BUFFER, 0);
glBindBuffer(GL_TEXTURE_BUFFER, 0);
}
glDeleteBuffers(1, &buffer);
return result;
}
GLPtexMipmapTexture *
GLPtexMipmapTexture::Create(PtexTexture * reader,
int maxLevels,
size_t targetMemory)
{
GLPtexMipmapTexture * result = NULL;
GLint maxNumPages = 0;
glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &maxNumPages);
// Read the ptexture data and pack the texels
PtexMipmapTextureLoader loader(reader,
maxNumPages,
maxLevels,
targetMemory);
// Setup GPU memory
int numFaces = loader.GetNumFaces();
GLuint layout = genTextureBuffer(GL_R16I,
numFaces * 6 * sizeof(GLshort),
loader.GetLayoutBuffer());
GLenum format, type;
switch (reader->dataType()) {
case Ptex::dt_uint16 : type = GL_UNSIGNED_SHORT; break;
case Ptex::dt_float : type = GL_FLOAT; break;
case Ptex::dt_half : type = GL_HALF_FLOAT; break;
default : type = GL_UNSIGNED_BYTE; break;
}
switch (reader->numChannels()) {
case 1 : format = GL_RED; break;
case 2 : format = GL_RG; break;
case 3 : format = GL_RGB; break;
case 4 : format = GL_RGBA; break;
default: format = GL_RED; break;
}
// actual texels texture array
GLuint texels;
glGenTextures(1, &texels);
glBindTexture(GL_TEXTURE_2D_ARRAY, texels);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0,
(type == GL_FLOAT) ? GL_RGBA32F : GL_RGBA,
loader.GetPageWidth(),
loader.GetPageHeight(),
loader.GetNumPages(),
0, format, type,
loader.GetTexelBuffer());
// loader.ClearBuffers();
// Return the Osd Ptexture object
result = new GLPtexMipmapTexture;
result->_width = loader.GetPageWidth();
result->_height = loader.GetPageHeight();
result->_depth = loader.GetNumPages();
result->_format = format;
result->_layout = layout;
result->_texels = texels;
result->_memoryUsage = loader.GetMemoryUsage();
return result;
}

View File

@@ -0,0 +1,54 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#ifndef OPENSUBDIV_EXAMPLES_GL_PTEX_MIPMAP_TEXTURE_H
#define OPENSUBDIV_EXAMPLES_GL_PTEX_MIPMAP_TEXTURE_H
#include "glLoader.h"
#include <opensubdiv/osd/nonCopyable.h>
#include <Ptexture.h>
#include <stdlib.h>
class GLPtexMipmapTexture : OpenSubdiv::Osd::NonCopyable<GLPtexMipmapTexture> {
public:
static GLPtexMipmapTexture * Create(PtexTexture * reader,
int maxLevels=-1,
size_t targetMemory=0);
/// Returns GLSL shader snippet to fetch ptex
static const char *GetShaderSource();
/// Returns the texture buffer containing the layout of the ptex faces
/// in the texels texture array.
GLuint GetLayoutTextureBuffer() const { return _layout; }
/// Returns the texels texture array.
GLuint GetTexelsTexture() const { return _texels; }
/// Returns the amount of allocated memory (in bytes)
size_t GetMemoryUsage() const { return _memoryUsage; }
~GLPtexMipmapTexture();
private:
GLPtexMipmapTexture();
GLsizei _width, // width / height / depth of the 3D texel buffer
_height,
_depth;
GLint _format; // texel color format
GLuint _layout, // per-face lookup table
_texels; // texel data
size_t _memoryUsage; // total amount of memory used (estimate)
};
#endif // OPENSUBDIV_EXAMPLES_GL_PTEX_MIPMAP_TEXTURE_H

View File

@@ -0,0 +1,91 @@
//
// Copyright 2015 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#include "glLoader.h"
#include "glShaderCache.h"
#include "glUtils.h"
#include <vector>
#include <opensubdiv/far/error.h>
GLDrawConfig::GLDrawConfig(const std::string &version)
: _version(version), _numShaders(0) {
_program = glCreateProgram();
}
GLDrawConfig::~GLDrawConfig() {
if (_program)
glDeleteProgram(_program);
}
bool
GLDrawConfig::CompileAndAttachShader(GLenum shaderType,
const std::string &source) {
GLuint shader = glCreateShader(shaderType);
#if 0
const char *sources[2];
sources[0] = _version.c_str();
sources[1] = source.c_str();
#endif
std::string sources = _version + source;
const char *src = sources.c_str();
glShaderSource(shader, 1, &src, NULL);
glCompileShader(shader);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE) {
GLint infoLogLength;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
char * infoLog = new char[infoLogLength];
glGetShaderInfoLog(shader, infoLogLength, NULL, infoLog);
OpenSubdiv::Far::Error(OpenSubdiv::Far::FAR_RUNTIME_ERROR,
"Error compiling GLSL shader: %s\n",
infoLog);
delete[] infoLog;
return false;
}
glAttachShader(_program, shader);
++_numShaders;
return true;
}
bool
GLDrawConfig::Link() {
glLinkProgram(_program);
std::vector<GLuint> shaders(_numShaders);
GLsizei count = 0;
glGetAttachedShaders(_program, _numShaders, &count, &shaders[0]);
for (int i = 0; i < (int)count; ++i) {
glDeleteShader(shaders[i]);
}
GLint status;
glGetProgramiv(_program, GL_LINK_STATUS, &status );
if (status == GL_FALSE) {
GLint infoLogLength;
glGetProgramiv(_program, GL_INFO_LOG_LENGTH, &infoLogLength);
char * infoLog = new char[infoLogLength];
glGetProgramInfoLog(_program, infoLogLength, NULL, infoLog);
OpenSubdiv::Far::Error(OpenSubdiv::Far::FAR_RUNTIME_ERROR,
"Error linking GLSL program: %s\n", infoLog);
delete[] infoLog;
return false;
}
return true;
}

View File

@@ -0,0 +1,46 @@
//
// Copyright 2015 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#ifndef OPENSUBDIV_EXAMPLES_GL_SHADER_CACHE_H
#define OPENSUBDIV_EXAMPLES_GL_SHADER_CACHE_H
#include "glLoader.h"
#include <map>
#include <string>
#include "./shaderCache.h"
class GLDrawConfig {
public:
explicit GLDrawConfig(const std::string &version);
~GLDrawConfig();
bool CompileAndAttachShader(GLenum shaderType, const std::string &source);
bool Link();
GLuint GetProgram() const {
return _program;
}
private:
GLuint _program;
std::string _version;
int _numShaders;
};
// workaround for template alias
#if 0
template <typename DESC_TYPE>
using GLShaderCache = ShaderCacheT<DESC_TYPE, GLDrawConfig>;
#else
template <typename DESC_TYPE>
class GLShaderCache : public ShaderCacheT<DESC_TYPE, GLDrawConfig> {
};
#endif
#endif // OPENSUBDIV_EXAMPLES_GL_SHADER_CACHE_H

View File

@@ -0,0 +1,282 @@
//
// Copyright 2015 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#include "glLoader.h"
#include <sstream>
#include <string>
#include <cstring>
#include <vector>
#include "glUtils.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION 1
#include "stb_image_write.h"
#include <GLFW/glfw3.h>
#if _MSC_VER
#define snprintf _snprintf
#endif
namespace GLUtils {
void InitializeGL()
{
OpenSubdiv::internal::GLLoader::applicationInitializeGL();
}
static void
_argParseBool(bool *ret, const char *lbl, int i, int argc, char **argv)
{
if (i < argc-1) {
if (!strcmp(argv[i+1], "on")) {
*ret = true;
} else if (!strcmp(argv[i+1], "off")) {
*ret = false;
} else {
fprintf(stderr, "Unknown setting for %s: %s\n", lbl, argv[i+1]);
exit(1);
}
} else {
fprintf(stderr,
"Please specify \"on\" or \"off\" for %s.\n", lbl);
exit(1);
}
}
void
SetMinimumGLVersion(int argc, char ** argv) {
#if defined(__APPLE__)
// Here 3.2 is the minimum GL version supported, GLFW will allocate a
// higher version if possible. This works on OS X, but instead limits
// the version to 3.2 on Linux. On Linux & Windows, specifying no
// version hint should use the highest version available.
//
// http://www.glfw.org/faq.html#how-do-i-create-an-opengl-30-context
// http://www.glfw.org/faq.html#what-versions-of-opengl-are-supported-by-glfw
bool coreProfile = true;
bool forwardCompat = true;
bool versionSet = true;
int major = 3;
int minor = 2;
#else
bool coreProfile = false;
bool forwardCompat = false;
bool versionSet = false;
int major = 4;
int minor = 2;
#endif
for (int i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "-glCoreProfile")) {
_argParseBool(&coreProfile, argv[i], i, argc, argv);
}
if (!strcmp(argv[i], "-glForwardCompat")) {
_argParseBool(&forwardCompat, argv[i], i, argc, argv);
}
if (!strcmp(argv[i], "-glVersion")) {
if (i < argc-1) {
char *versionStr = argv[i+1];
size_t len = strlen(versionStr);
if (len == 3 && versionStr[1] == '.' &&
versionStr[0] >= '0' && versionStr[0] <= '9' &&
versionStr[2] >= '0' && versionStr[2] <= '9') {
major = versionStr[0] - '0';
minor = versionStr[2] - '0';
versionSet = true;
} else {
fprintf(stderr,
"Invalid version number: %s, please specify a number "
"in the format M.n, e.g., -glVersion 4.2.\n",
versionStr);
exit(1);
}
} else {
fprintf(stderr,
"Please specify a version number for glVersion "
"in the form M.n, e.g., -glVersion 4.2.\n");
exit(1);
}
}
}
if (coreProfile) {
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
}
if (forwardCompat) {
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
}
if (versionSet) {
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, major);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, minor);
}
}
void
PrintGLVersion() {
std::cout << glGetString(GL_VENDOR) << "\n";
std::cout << glGetString(GL_RENDERER) << "\n";
std::cout << glGetString(GL_VERSION) << "\n";
int i = -1;
std::cout << "Init OpenGL ";
glGetIntegerv(GL_MAJOR_VERSION, &i);
std::cout << i << ".";
glGetIntegerv(GL_MINOR_VERSION, &i);
std::cout << i << "\n";
CheckGLErrors("PrintGLVersion");
}
void
CheckGLErrors(std::string const & where) {
GLuint err;
while ((err = glGetError()) != GL_NO_ERROR) {
std::cerr << "GL error: "
<< (where.empty() ? "" : where + " ")
<< err << "\n";
}
}
GLuint
CompileShader(GLenum shaderType, const char *source) {
GLuint shader = glCreateShader(shaderType);
glShaderSource(shader, 1, &source, NULL);
glCompileShader(shader);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE) {
GLchar emsg[40960];
glGetShaderInfoLog(shader, sizeof(emsg), 0, emsg);
fprintf(stderr, "Error compiling GLSL shader: %s\n", emsg);
return 0;
}
return shader;
}
void
WriteScreenshot(int width, int height) {
std::vector<unsigned char> data(width*height*4 /*RGBA*/);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
static int counter=0;
char fname[64];
snprintf(fname, 64, "screenshot.%d.png", counter++);
// flip vertical
stbi_write_png(fname, width, height, 4, &data[width*4*(height-1)], -width*4);
fprintf(stdout, "Saved %s\n", fname);
}
void GetMajorMinorVersion(int *major, int *minor){
const GLubyte *ver = glGetString(GL_SHADING_LANGUAGE_VERSION);
if (!ver){
*major = -1;
*minor = -1;
}
else{
std::stringstream ss;
ss << std::string(ver, ver + 1) << " " << std::string(ver + 2, ver + 3);
ss >> *major;
ss >> *minor;
}
}
std::string
GetShaderVersion(){
std::string shader_version;
int major, minor;
GetMajorMinorVersion(&major, &minor);
int version_number = major * 10 + minor;
switch (version_number){
case 20:
shader_version = "110";
break;
case 21:
shader_version = "120";
break;
case 30:
shader_version = "130";
break;
case 31:
shader_version = "140";
break;
case 32:
shader_version = "150";
break;
default:
std::stringstream ss;
ss << version_number;
shader_version = ss.str() + "0";
break;
}
return shader_version;
}
// Generates the version definition needed by the glsl shaders based on the
// opengl string
std::string GetShaderVersionInclude(){
return "#version " + GetShaderVersion() + "\n";
}
bool SupportsAdaptiveTessellation() {
#if defined(GL_VERSION_4_0)
if (OSD_OPENGL_HAS(VERSION_4_0)) {
return true;
}
#endif
#if defined(GL_ARB_tessellation_shader)
if (OSD_OPENGL_HAS(ARB_tessellation_shader)) {
return true;
}
#endif
return false;
}
bool GL_ARBSeparateShaderObjectsOrGL_VERSION_4_1() {
#if defined(GL_VERSION_4_1)
if (OSD_OPENGL_HAS(VERSION_4_1)) {
return true;
}
#endif
#if defined(GL_ARB_separate_shader_objects)
if (OSD_OPENGL_HAS(ARB_separate_shader_objects)) {
return true;
}
#endif
return false;
}
bool GL_ARBComputeShaderOrGL_VERSION_4_3() {
#if defined(GL_VERSION_4_3)
if (OSD_OPENGL_HAS(VERSION_4_3)) {
return true;
}
#endif
#if defined(GL_ARB_compute_shader)
if (OSD_OPENGL_HAS(ARB_compute_shader)) {
return true;
}
#endif
return false;
}
#undef IS_SUPPORTED
} // namespace GLUtils

View File

@@ -0,0 +1,51 @@
//
// Copyright 2015 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#ifndef OPENSUBDIV_EXAMPLES_GL_UTILS_H
#define OPENSUBDIV_EXAMPLES_GL_UTILS_H
#include "glLoader.h"
#include <cstdio>
#include <string>
#include <iostream>
namespace GLUtils {
void InitializeGL();
void SetMinimumGLVersion(int argc=0, char **argv=NULL);
void PrintGLVersion();
void CheckGLErrors(std::string const & where = "");
GLuint CompileShader(GLenum shaderType, const char *source);
void WriteScreenshot(int width, int height);
bool SupportsAdaptiveTessellation();
// Helper function that parses the opengl version string, retrieving the
// major and minor version from it.
void GetMajorMinorVersion(int *major, int *minor);
// Gets the shader version based on the current opengl version and returns
// it in a string form.
std::string GetShaderVersion();
std::string GetShaderVersionInclude();
bool GL_ARBSeparateShaderObjectsOrGL_VERSION_4_1();
bool GL_ARBComputeShaderOrGL_VERSION_4_3();
};
#endif // OPENSUBDIV_EXAMPLES_GL_UTILS_H

View File

@@ -0,0 +1,337 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
//----------------------------------------------------------
// Ptex.Common
//----------------------------------------------------------
struct PtexPacking {
int page;
int nMipmap;
int uOffset;
int vOffset;
int adjSizeDiffs[4];
int width;
int height;
};
PtexPacking getPtexPacking(isamplerBuffer packings, int faceID)
{
PtexPacking packing;
packing.page = texelFetch(packings, faceID*6).x;
packing.nMipmap = texelFetch(packings, faceID*6+1).x;
packing.uOffset = texelFetch(packings, faceID*6+2).x;
packing.vOffset = texelFetch(packings, faceID*6+3).x;
int wh = texelFetch(packings, faceID*6+5).x;
packing.width = 1 << (wh >> 8);
packing.height = 1 << (wh & 0xff);
int adjSizeDiffs = texelFetch(packings, faceID*6+4).x;
packing.adjSizeDiffs[0] = (adjSizeDiffs >> 12) & 0xf;
packing.adjSizeDiffs[1] = (adjSizeDiffs >> 8) & 0xf;
packing.adjSizeDiffs[2] = (adjSizeDiffs >> 4) & 0xf;
packing.adjSizeDiffs[3] = (adjSizeDiffs >> 0) & 0xf;
return packing;
}
int computeMipmapOffsetU(int w, int level)
{
int width = 1 << w;
int m = (0x55555555 & (width | (width-1))) << (w&1);
int x = ~((1 << (w -((level-1)&~1))) - 1);
return (m & x) + ((level+1)&~1);
}
int computeMipmapOffsetV(int h, int level)
{
int height = 1 << h;
int m = (0x55555555 & (height-1)) << ((h+1)&1);;
int x = ~((1 << (h - (level&~1))) - 1 );
return (m & x) + (level&~1);
}
PtexPacking getPtexPacking(isamplerBuffer packings, int faceID, int level)
{
PtexPacking packing;
packing.page = texelFetch(packings, faceID*6).x;
packing.nMipmap = texelFetch(packings, faceID*6+1).x;
packing.uOffset = texelFetch(packings, faceID*6+2).x;
packing.vOffset = texelFetch(packings, faceID*6+3).x;
int sizeDiffs = texelFetch(packings, faceID*6+4).x;
int wh = texelFetch(packings, faceID*6+5).x;
int w = wh >> 8;
int h = wh & 0xff;
// clamp max level
level = min(level, packing.nMipmap);
packing.uOffset += computeMipmapOffsetU(w, level);
packing.vOffset += computeMipmapOffsetV(h, level);
packing.width = 1 << (w-level);
packing.height = 1 << (h-level);
return packing;
}
void evalQuadraticBSpline(float u, out float B[3], out float BU[3])
{
B[0] = 0.5 * (u*u - 2.0*u + 1);
B[1] = 0.5 + u - u*u;
B[2] = 0.5 * u*u;
BU[0] = u - 1.0;
BU[1] = 1 - 2 * u;
BU[2] = u;
}
// ----------------------------------------------------------------------------
// Non-Mipmap Lookups
// ----------------------------------------------------------------------------
vec4 PtexLookupNearest(vec4 patchCoord,
sampler2DArray data,
isamplerBuffer packings)
{
vec2 uv = clamp(patchCoord.xy, vec2(0), vec2(1));
int faceID = int(patchCoord.w);
PtexPacking ppack = getPtexPacking(packings, faceID);
vec2 coords = vec2(uv.x * ppack.width + ppack.uOffset,
uv.y * ppack.height + ppack.vOffset);
return texelFetch(data, ivec3(int(coords.x), int(coords.y), ppack.page), 0);
}
vec4 PtexLookupNearest(vec4 patchCoord,
int level,
sampler2DArray data,
isamplerBuffer packings)
{
vec2 uv = clamp(patchCoord.xy, vec2(0), vec2(1));
int faceID = int(patchCoord.w);
PtexPacking ppack = getPtexPacking(packings, faceID, level);
vec2 coords = vec2(uv.x * ppack.width + ppack.uOffset,
uv.y * ppack.height + ppack.vOffset);
return texelFetch(data, ivec3(int(coords.x), int(coords.y), ppack.page), 0);
}
vec4 PtexLookupFast(vec4 patchCoord,
sampler2DArray data,
isamplerBuffer packings)
{
vec2 uv = clamp(patchCoord.xy, vec2(0), vec2(1));
int faceID = int(patchCoord.w);
PtexPacking ppack = getPtexPacking(packings, faceID);
ivec3 size = textureSize(data, 0);
vec2 coords = vec2((uv.x * ppack.width + ppack.uOffset)/size.x,
(uv.y * ppack.height + ppack.vOffset)/size.y);
return texture(data, vec3(coords.x, coords.y, ppack.page));
}
vec4 PtexLookupFast(vec4 patchCoord,
int level,
sampler2DArray data,
isamplerBuffer packings)
{
vec2 uv = clamp(patchCoord.xy, vec2(0), vec2(1));
int faceID = int(patchCoord.w);
PtexPacking ppack = getPtexPacking(packings, faceID, level);
ivec3 size = textureSize(data, 0);
vec2 coords = vec2((uv.x * ppack.width + ppack.uOffset)/size.x,
(uv.y * ppack.height + ppack.vOffset)/size.y);
return texture(data, vec3(coords.x, coords.y, ppack.page));
}
vec4 PtexLookup(vec4 patchCoord,
int level,
sampler2DArray data,
isamplerBuffer packings)
{
vec2 uv = clamp(patchCoord.xy, vec2(0), vec2(1));
int faceID = int(patchCoord.w);
PtexPacking ppack = getPtexPacking(packings, faceID, level);
vec2 coords = vec2(uv.x * ppack.width + ppack.uOffset,
uv.y * ppack.height + ppack.vOffset);
coords -= vec2(0.5, 0.5);
int c0X = int(floor(coords.x));
int c1X = int(ceil(coords.x));
int c0Y = int(floor(coords.y));
int c1Y = int(ceil(coords.y));
float t = coords.x - float(c0X);
float s = coords.y - float(c0Y);
vec4 d0 = texelFetch(data, ivec3(c0X, c0Y, ppack.page), 0);
vec4 d1 = texelFetch(data, ivec3(c0X, c1Y, ppack.page), 0);
vec4 d2 = texelFetch(data, ivec3(c1X, c0Y, ppack.page), 0);
vec4 d3 = texelFetch(data, ivec3(c1X, c1Y, ppack.page), 0);
vec4 result = (1-t) * ((1-s)*d0 + s*d1) + t * ((1-s)*d2 + s*d3);
return result;
}
vec4 PtexLookupQuadratic(out vec4 du,
out vec4 dv,
vec4 patchCoord,
int level,
sampler2DArray data,
isamplerBuffer packings)
{
vec2 uv = clamp(patchCoord.xy, vec2(0), vec2(1));
int faceID = int(patchCoord.w);
PtexPacking ppack = getPtexPacking(packings, faceID, level);
vec2 coords = vec2(uv.x * ppack.width + ppack.uOffset,
uv.y * ppack.height + ppack.vOffset);
coords -= vec2(0.5, 0.5);
int cX = int(round(coords.x));
int cY = int(round(coords.y));
float x = 0.5 - (float(cX) - coords.x);
float y = 0.5 - (float(cY) - coords.y);
vec4 d[9];
d[0] = texelFetch(data, ivec3(cX-1, cY-1, ppack.page), 0);
d[1] = texelFetch(data, ivec3(cX-1, cY-0, ppack.page), 0);
d[2] = texelFetch(data, ivec3(cX-1, cY+1, ppack.page), 0);
d[3] = texelFetch(data, ivec3(cX-0, cY-1, ppack.page), 0);
d[4] = texelFetch(data, ivec3(cX-0, cY-0, ppack.page), 0);
d[5] = texelFetch(data, ivec3(cX-0, cY+1, ppack.page), 0);
d[6] = texelFetch(data, ivec3(cX+1, cY-1, ppack.page), 0);
d[7] = texelFetch(data, ivec3(cX+1, cY-0, ppack.page), 0);
d[8] = texelFetch(data, ivec3(cX+1, cY+1, ppack.page), 0);
float B[3], D[3];
vec4 BUCP[3] = vec4[3](vec4(0,0,0,0), vec4(0,0,0,0), vec4(0,0,0,0)),
DUCP[3] = vec4[3](vec4(0,0,0,0), vec4(0,0,0,0), vec4(0,0,0,0));
evalQuadraticBSpline(y, B, D);
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; j++) {
vec4 A = d[i*3+j];
BUCP[i] += A * B[j];
DUCP[i] += A * D[j];
}
}
evalQuadraticBSpline(x, B, D);
vec4 result = vec4(0);
du = vec4(0);
dv = vec4(0);
for (int i = 0; i < 3; ++i) {
result += B[i] * BUCP[i];
du += D[i] * BUCP[i];
dv += B[i] * DUCP[i];
}
du *= ppack.width;
dv *= ppack.height;
return result;
}
// ----------------------------------------------------------------------------
// MipMap Lookups
// ----------------------------------------------------------------------------
vec4 PtexMipmapLookupNearest(vec4 patchCoord,
float level,
sampler2DArray data,
isamplerBuffer packings)
{
#if defined(SEAMLESS_MIPMAP)
// diff level
int faceID = int(patchCoord.w);
vec2 uv = patchCoord.xy;
PtexPacking packing = getPtexPacking(packings, faceID);
level += mix(mix(packing.adjSizeDiffs[0], packing.adjSizeDiffs[1], uv.x),
mix(packing.adjSizeDiffs[3], packing.adjSizeDiffs[2], uv.x),
uv.y);
#endif
int levelm = int(floor(level));
int levelp = int(ceil(level));
float t = level - float(levelm);
vec4 result = (1-t) * PtexLookupNearest(patchCoord, levelm, data, packings)
+ t * PtexLookupNearest(patchCoord, levelp, data, packings);
return result;
}
vec4 PtexMipmapLookup(vec4 patchCoord,
float level,
sampler2DArray data,
isamplerBuffer packings)
{
#if defined(SEAMLESS_MIPMAP)
// diff level
int faceID = int(patchCoord.w);
vec2 uv = patchCoord.xy;
PtexPacking packing = getPtexPacking(packings, faceID);
level += mix(mix(packing.adjSizeDiffs[0], packing.adjSizeDiffs[1], uv.x),
mix(packing.adjSizeDiffs[3], packing.adjSizeDiffs[2], uv.x),
uv.y);
#endif
int levelm = int(floor(level));
int levelp = int(ceil(level));
float t = level - float(levelm);
vec4 result = (1-t) * PtexLookup(patchCoord, levelm, data, packings)
+ t * PtexLookup(patchCoord, levelp, data, packings);
return result;
}
vec4 PtexMipmapLookupQuadratic(out vec4 du,
out vec4 dv,
vec4 patchCoord,
float level,
sampler2DArray data,
isamplerBuffer packings)
{
#if defined(SEAMLESS_MIPMAP)
// diff level
int faceID = int(patchCoord.w);
vec2 uv = patchCoord.xy;
PtexPacking packing = getPtexPacking(packings, faceID);
level += mix(mix(packing.adjSizeDiffs[0], packing.adjSizeDiffs[1], uv.x),
mix(packing.adjSizeDiffs[3], packing.adjSizeDiffs[2], uv.x),
uv.y);
#endif
int levelm = int(floor(level));
int levelp = int(ceil(level));
float t = level - float(levelm);
vec4 du0, du1, dv0, dv1;
vec4 r0 = PtexLookupQuadratic(du0, dv0, patchCoord, levelm, data, packings);
vec4 r1 = PtexLookupQuadratic(du1, dv1, patchCoord, levelp, data, packings);
vec4 result = mix(r0, r1, t);
du = mix(du0, du1, t);
dv = mix(dv0, dv1, t);
return result;
}
vec4 PtexMipmapLookupQuadratic(vec4 patchCoord,
float level,
sampler2DArray data,
isamplerBuffer packings)
{
vec4 du, dv;
return PtexMipmapLookupQuadratic(du, dv, patchCoord, level, data, packings);
}

View File

@@ -0,0 +1,148 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "hdr_reader.h"
static bool
readLine(unsigned char *line, int length, FILE *fp)
{
// 2, 2, width (this reader only reads newer format)
if (getc(fp) != 2) return false;
if (getc(fp) != 2) return false;
int w0 = getc(fp);
int w1 = getc(fp);
if ((w0 << 8 | w1) != length) return false;
for (int i = 0; i < 4; ++i) {
for (int x = 0; x < length;) {
int c = getc(fp);
if (c > 128) {
// runlength
c &= 127;
unsigned char value = (unsigned char)getc(fp);
while (c--) {
line[x*4+i] = value;
x++;
}
} else {
// non- runlength
while (c--) {
unsigned char value = (unsigned char)getc(fp);
line[x*4+i] = value;
x++;
}
}
}
}
return true;
}
unsigned char *loadHdr(const char *filename, HdrInfo *info, bool convertToFloat)
{
FILE *fp = fopen(filename, "rb");
if (fp == NULL) return NULL;
memset(info, 0, sizeof(HdrInfo));
info->exposure = 1.0;
unsigned char *dst=NULL, *line=NULL, *d=NULL;
float *fd=NULL;
const int MAXLINE = 1024;
char buffer[MAXLINE];
// read header
while(true) {
if (! fgets(buffer, MAXLINE, fp)) goto error;
if (buffer[0] == '\n') break;
if (buffer[0] == '\r' && buffer[0] == '\n') break;
if (strncmp(buffer, "#?", 2) == 0) {
strncpy(info->magic, buffer+2, 64);
} else if (strncmp(buffer, "FORMAT=", 7) == 0) {
strncpy(info->format, buffer+7, 64);
}
}
// if (strncmp(info->magic, "RADIANCE", 8)) goto error;
if (strncmp(info->format, "32-bit_rle_rgbe", 15)) goto error;
// resolution
if (! fgets(buffer, MAXLINE, fp)) goto error;
{
int n = (int)strlen(buffer);
for (int i = 1; i < n; ++i) {
if (buffer[i] == 'X') {
if (! (info->flag & HDR_Y_MAJOR)) info->flag |= HDR_X_MAJOR;
info->flag |= (char)((buffer[i-1] == '-') ? HDR_X_DEC : 0);
info->width = atoi(&buffer[i+1]);
} else if (buffer[i] == 'Y') {
if (! (info->flag & HDR_X_MAJOR)) info->flag |= HDR_Y_MAJOR;
info->flag |= (char)((buffer[i-1] == '-') ? HDR_Y_DEC : 0);
info->height = atoi(&buffer[i+1]);
}
}
}
if (info->width <= 0 || info->height <= 0) goto error;
if (info->flag & HDR_Y_MAJOR) {
info->scanLength = info->width;
info->scanWidth = info->height;
} else {
info->scanLength = info->height;
info->scanWidth = info->width;
}
// read body
if (convertToFloat) {
dst = (unsigned char *)malloc(info->width * info->height * 4 * sizeof(float));
fd = (float*)dst;
} else {
dst = (unsigned char *)malloc(info->width * info->height * 4);
d = dst;
}
line = (unsigned char *)malloc(info->scanLength*4);
for (int y = info->scanWidth-1; y >= 0; --y) {
if (! readLine(line, info->scanLength, fp)) goto error;
for (int x = 0; x < info->scanLength; ++x) {
if (convertToFloat) {
float scale = powf(2.0f, float(line[x*4+3] - 128))/255.0f;
*fd++ = line[x*4 ]*scale;
*fd++ = line[x*4+1]*scale;
*fd++ = line[x*4+2]*scale;
*fd++ = 1.0;
} else {
*d++ = line[x*4 ];
*d++ = line[x*4+1];
*d++ = line[x*4+2];
*d++ = line[x*4+3];
}
}
}
free(line);
fclose(fp);
return dst;
error:
printf("Error in reading %s\n", filename);
if(dst) free(dst);
if(line) free(line);
fclose(fp);
return NULL;
}
/*
int main(int argc, char *argv[]) {
HdrInfo info;
loadHdr(argv[1], &info);
}
*/

View File

@@ -0,0 +1,25 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#define HDR_X_MAJOR (1 << 0)
#define HDR_Y_MAJOR (1 << 1)
#define HDR_X_DEC (1 << 2)
#define HDR_Y_DEC (1 << 3)
struct HdrInfo
{
char magic[64];
char format[64];
double exposure;
int width;
int height;
char flag;
int scanLength;
int scanWidth;
};
extern unsigned char *loadHdr(const char *filename, HdrInfo *info, bool convertToFloat);

View File

@@ -0,0 +1,309 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
//----------------------------------------------------------
// Ptex.Common
//----------------------------------------------------------
struct PtexPacking {
int page;
int nMipmap;
int uOffset;
int vOffset;
int adjSizeDiffs[4];
int width;
int height;
};
PtexPacking getPtexPacking(Buffer<uint> packings, int faceID)
{
PtexPacking packing;
packing.page = packings[faceID*6+0].x;
packing.nMipmap = packings[faceID*6+1].x;
packing.uOffset = packings[faceID*6+2].x;
packing.vOffset = packings[faceID*6+3].x;
int wh = packings[faceID*6+5].x;
packing.width = 1 << (wh >> 8);
packing.height = 1 << (wh & 0xff);
int adjSizeDiffs = packings[faceID*6+4].x;
packing.adjSizeDiffs[0] = (adjSizeDiffs >> 12) & 0xf;
packing.adjSizeDiffs[1] = (adjSizeDiffs >> 8) & 0xf;
packing.adjSizeDiffs[2] = (adjSizeDiffs >> 4) & 0xf;
packing.adjSizeDiffs[3] = (adjSizeDiffs >> 0) & 0xf;
return packing;
}
int computeMipmapOffsetU(int w, int level)
{
int width = 1 << w;
int m = (0x55555555 & (width | (width-1))) << (w&1);
int x = ~((1 << (w -((level-1)&~1))) - 1);
return (m & x) + ((level+1)&~1);
}
int computeMipmapOffsetV(int h, int level)
{
int height = 1 << h;
int m = (0x55555555 & (height-1)) << ((h+1)&1);;
int x = ~((1 << (h - (level&~1))) - 1 );
return (m & x) + (level&~1);
}
PtexPacking getPtexPacking(Buffer<uint> packings, int faceID, int level)
{
PtexPacking packing;
packing.page = packings[faceID*6+0].x;
packing.nMipmap = packings[faceID*6+1].x;
packing.uOffset = packings[faceID*6+2].x;
packing.vOffset = packings[faceID*6+3].x;
//int sizeDiffs = packings[faceID*6+4].x;
int wh = packings[faceID*6+5].x;
int w = wh >> 8;
int h = wh & 0xff;
// clamp max level
level = min(level, packing.nMipmap);
packing.uOffset += computeMipmapOffsetU(w, level);
packing.vOffset += computeMipmapOffsetV(h, level);
packing.width = 1 << (w-level);
packing.height = 1 << (h-level);
return packing;
}
void evalQuadraticBSpline(float u, out float B[3], out float BU[3])
{
B[0] = 0.5 * (u*u - 2.0*u + 1);
B[1] = 0.5 + u - u*u;
B[2] = 0.5 * u*u;
BU[0] = u - 1.0;
BU[1] = 1 - 2 * u;
BU[2] = u;
}
// ----------------------------------------------------------------------------
// Non-Mipmap Lookups
// ----------------------------------------------------------------------------
float4 PtexLookupNearest(float4 patchCoord,
Texture2DArray data,
Buffer<uint> packings)
{
float2 uv = clamp(patchCoord.xy, float2(0,0), float2(1,1));
int faceID = int(patchCoord.w);
PtexPacking ppack = getPtexPacking(packings, faceID);
float2 coords = float2(uv.x * ppack.width + ppack.uOffset,
uv.y * ppack.height + ppack.vOffset);
return data[int3(int(coords.x), int(coords.y), ppack.page)];
}
float4 PtexLookupNearest(float4 patchCoord,
int level,
Texture2DArray data,
Buffer<uint> packings)
{
float2 uv = clamp(patchCoord.xy, float2(0,0), float2(1,1));
int faceID = int(patchCoord.w);
PtexPacking ppack = getPtexPacking(packings, faceID, level);
float2 coords = float2(uv.x * ppack.width + ppack.uOffset,
uv.y * ppack.height + ppack.vOffset);
return data[int3(int(coords.x), int(coords.y), ppack.page)];
}
float4 PtexLookup(float4 patchCoord,
int level,
Texture2DArray data,
Buffer<uint> packings)
{
float2 uv = clamp(patchCoord.xy, float2(0,0), float2(1,1));
int faceID = int(patchCoord.w);
PtexPacking ppack = getPtexPacking(packings, faceID, level);
float2 coords = float2(uv.x * ppack.width + ppack.uOffset,
uv.y * ppack.height + ppack.vOffset);
coords -= float2(0.5, 0.5);
int c0X = int(floor(coords.x));
int c1X = int(ceil(coords.x));
int c0Y = int(floor(coords.y));
int c1Y = int(ceil(coords.y));
float t = coords.x - float(c0X);
float s = coords.y - float(c0Y);
float4 d0 = data[int3(c0X, c0Y, ppack.page)];
float4 d1 = data[int3(c0X, c1Y, ppack.page)];
float4 d2 = data[int3(c1X, c0Y, ppack.page)];
float4 d3 = data[int3(c1X, c1Y, ppack.page)];
float4 result = (1-t) * ((1-s)*d0 + s*d1) + t * ((1-s)*d2 + s*d3);
return result;
}
float4 PtexLookupQuadratic(out float4 du,
out float4 dv,
float4 patchCoord,
int level,
Texture2DArray data,
Buffer<uint> packings)
{
float2 uv = clamp(patchCoord.xy, float2(0,0), float2(1,1));
int faceID = int(patchCoord.w);
PtexPacking ppack = getPtexPacking(packings, faceID, level);
float2 coords = float2(uv.x * ppack.width + ppack.uOffset,
uv.y * ppack.height + ppack.vOffset);
coords -= float2(0.5, 0.5);
int cX = int(round(coords.x));
int cY = int(round(coords.y));
float x = 0.5 - (float(cX) - coords.x);
float y = 0.5 - (float(cY) - coords.y);
float4 d[9];
d[0] = data[int3(cX-1, cY-1, ppack.page)];
d[1] = data[int3(cX-1, cY-0, ppack.page)];
d[2] = data[int3(cX-1, cY+1, ppack.page)];
d[3] = data[int3(cX-0, cY-1, ppack.page)];
d[4] = data[int3(cX-0, cY-0, ppack.page)];
d[5] = data[int3(cX-0, cY+1, ppack.page)];
d[6] = data[int3(cX+1, cY-1, ppack.page)];
d[7] = data[int3(cX+1, cY-0, ppack.page)];
d[8] = data[int3(cX+1, cY+1, ppack.page)];
float B[3], D[3];
float4 BUCP[3] = {float4(0,0,0,0), float4(0,0,0,0), float4(0,0,0,0)},
DUCP[3] = {float4(0,0,0,0), float4(0,0,0,0), float4(0,0,0,0)};
evalQuadraticBSpline(y, B, D);
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; j++) {
float4 A = d[i*3+j];
BUCP[i] += A * B[j];
DUCP[i] += A * D[j];
}
}
evalQuadraticBSpline(x, B, D);
float4 result = float4(0, 0, 0, 0);
du = float4(0, 0, 0, 0);
dv = float4(0, 0, 0, 0);
for (int i = 0; i < 3; ++i) {
result += B[i] * BUCP[i];
du += D[i] * BUCP[i];
dv += B[i] * DUCP[i];
}
du *= ppack.width;
dv *= ppack.height;
return result;
}
// ----------------------------------------------------------------------------
// MipMap Lookups
// ----------------------------------------------------------------------------
float4 PtexMipmapLookupNearest(float4 patchCoord,
int level,
Texture2DArray data,
Buffer<uint> packings)
{
#if defined(SEAMLESS_MIPMAP)
// diff level
int faceID = int(patchCoord.w);
float2 uv = patchCoord.xy;
PtexPacking packing = getPtexPacking(packings, faceID);
level += lerp(lerp(packing.adjSizeDiffs[0], packing.adjSizeDiffs[1], uv.x),
lerp(packing.adjSizeDiffs[3], packing.adjSizeDiffs[2], uv.x),
uv.y);
#endif
int levelm = int(floor(level));
int levelp = int(ceil(level));
float t = level - float(levelm);
float4 result = (1-t) * PtexLookupNearest(patchCoord, levelm, data, packings)
+ t * PtexLookupNearest(patchCoord, levelp, data, packings);
return result;
}
float4 PtexMipmapLookup(float4 patchCoord,
float level,
Texture2DArray data,
Buffer<uint> packings)
{
#if defined(SEAMLESS_MIPMAP)
// diff level
int faceID = int(patchCoord.w);
float2 uv = patchCoord.xy;
PtexPacking packing = getPtexPacking(packings, faceID);
level += lerp(lerp(packing.adjSizeDiffs[0], packing.adjSizeDiffs[1], uv.x),
lerp(packing.adjSizeDiffs[3], packing.adjSizeDiffs[2], uv.x),
uv.y);
#endif
int levelm = int(floor(level));
int levelp = int(ceil(level));
float t = level - float(levelm);
float4 result = (1-t) * PtexLookup(patchCoord, levelm, data, packings)
+ t * PtexLookup(patchCoord, levelp, data, packings);
return result;
}
float4 PtexMipmapLookupQuadratic(out float4 du,
out float4 dv,
float4 patchCoord,
float level,
Texture2DArray data,
Buffer<uint> packings)
{
#if defined(SEAMLESS_MIPMAP)
// diff level
int faceID = int(patchCoord.w);
float2 uv = patchCoord.xy;
PtexPacking packing = getPtexPacking(packings, faceID);
level += lerp(lerp(packing.adjSizeDiffs[0], packing.adjSizeDiffs[1], uv.x),
lerp(packing.adjSizeDiffs[3], packing.adjSizeDiffs[2], uv.x),
uv.y);
#endif
int levelm = int(floor(level));
int levelp = int(ceil(level));
float t = level - float(levelm);
float4 du0, du1, dv0, dv1;
float4 r0 = PtexLookupQuadratic(du0, dv0, patchCoord, levelm, data, packings);
float4 r1 = PtexLookupQuadratic(du1, dv1, patchCoord, levelp, data, packings);
float4 result = lerp(r0, r1, t);
du = lerp(du0, du1, t);
dv = lerp(dv0, dv1, t);
return result;
}
float4 PtexMipmapLookupQuadratic(float4 patchCoord,
float level,
Texture2DArray data,
Buffer<uint> packings)
{
float4 du, dv;
return PtexMipmapLookupQuadratic(du, dv, patchCoord, level, data, packings);
}

View File

@@ -0,0 +1,589 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#include <algorithm>
#include <vector>
#include <cstring>
#include <cstdio>
#include <cassert>
#include "hud.h"
#include "font_image.h"
#if _MSC_VER
#define snprintf _snprintf
#endif
Hud::Hud() : _visible(true), _windowWidth(0), _windowHeight(0),
_framebufferWidth(0), _framebufferHeight(0),
_requiresRebuildStatic(true)
{
_capturedSlider = -1;
}
Hud::~Hud()
{
}
void
Hud::Init(int width, int height, int framebufferWidth, int framebufferHeight)
{
_windowWidth = width;
_windowHeight = height;
_framebufferWidth = framebufferWidth;
_framebufferHeight = framebufferHeight;
}
int
Hud::GetWidth() const
{
return _windowWidth;
}
int
Hud::GetHeight() const
{
return _windowHeight;
}
void
Hud::Clear()
{
_radioButtons.clear();
_checkBoxes.clear();
_sliders.clear();
_vboSource.clear();
_requiresRebuildStatic = true;
}
bool
Hud::KeyDown(int key)
{
for (std::vector<RadioButton>::iterator it = _radioButtons.begin();
it != _radioButtons.end(); ++it) {
if (key == it->shortcut) {
int nextLocalIndex = it->localIndex;
if (it->sharedShortcut) {
// find checked radio button in this group
int maxLocalIndex = 0;
for (std::vector<RadioButton>::iterator it2 = _radioButtons.begin();
it2 != _radioButtons.end(); ++it2) {
if (it2->group == it->group) {
maxLocalIndex = std::max(maxLocalIndex, it2->localIndex);
if (it2->checked) {
nextLocalIndex = it2->localIndex+1;
}
}
}
if (nextLocalIndex > maxLocalIndex) nextLocalIndex = 0;
}
for (std::vector<RadioButton>::iterator it2 = _radioButtons.begin();
it2 != _radioButtons.end(); ++it2) {
if (it2->group == it->group) {
if (it2->localIndex == nextLocalIndex) {
it2->checked = true;
it2->callback(it2->callbackData);
} else {
it2->checked = false;
}
}
}
_requiresRebuildStatic = true;
return true;
}
}
for (std::vector<CheckBox>::iterator it = _checkBoxes.begin();
it != _checkBoxes.end(); ++it) {
if (key == it->shortcut) {
it->checked = !it->checked;
it->callback(it->checked, it->callbackData);
_requiresRebuildStatic = true;
return true;
}
}
for (std::vector<PullDown>::iterator it = _pulldowns.begin();
it != _pulldowns.end(); ++it) {
if (key==it->shortcut) {
// cycle through selections
++it->selected;
if (it->selected>=(int)it->labels.size()) {
it->selected=0;
}
it->callback(it->values[it->selected]);
_requiresRebuildStatic = true;
return true;
}
}
return false;
}
bool
Hud::MouseClick(int x, int y)
{
if (!IsVisible()) {
return false;
}
for (std::vector<RadioButton>::iterator it = _radioButtons.begin();
it != _radioButtons.end(); ++it) {
if (hitTest(*it, x, y)) {
for (std::vector<RadioButton>::iterator it2 = _radioButtons.begin();
it2 != _radioButtons.end(); ++it2) {
if (it2->group == it->group && it != it2) it2->checked = false;
}
it->checked = true;
it->callback(it->callbackData);
_requiresRebuildStatic = true;
return true;
}
}
for (std::vector<CheckBox>::iterator it = _checkBoxes.begin();
it != _checkBoxes.end(); ++it) {
if (hitTest(*it, x, y)) {
it->checked = !it->checked;
it->callback(it->checked, it->callbackData);
_requiresRebuildStatic = true;
return true;
}
}
for (std::vector<Slider>::iterator it = _sliders.begin();
it != _sliders.end(); ++it) {
if (hitTest(*it, x, y)) {
int bx = 0, by = 0;
getWindowPos(*it, &bx, &by);
it->SetValue(((x-bx-FONT_CHAR_WIDTH/2)/float(it->w))*(it->max - it->min) + it->min);
it->callback(it->value, it->callbackData);
_capturedSlider = (int)(it - _sliders.begin());
_requiresRebuildStatic = true;
return true;
}
}
for (std::vector<PullDown>::iterator it = _pulldowns.begin();
it != _pulldowns.end(); ++it) {
if (hitTest(*it, x, y)) {
if (! it->open) {
it->h = FONT_CHAR_HEIGHT;
it->h *= (int)it->labels.size();
it->open=true;
} else {
int label_width = (3+(int)it->label.size()) * FONT_CHAR_WIDTH;
int bx = 0, by = 0;
getWindowPos(*it, &bx, &by);
if (x > (bx+label_width)) {
int sel = it->selected;
it->SetSelected((y-by)/FONT_CHAR_HEIGHT);
if (it->selected!=sel) {
it->callback(it->values[it->selected]);
}
} else {
it->open=! it->open;
}
}
_requiresRebuildStatic = true;
return true;
}
}
return false;
}
void
Hud::MouseMotion(int x, int /* y */)
{
if (_capturedSlider != -1) {
std::vector<Slider>::iterator it = _sliders.begin() + _capturedSlider;
int bx = it->x > 0 ? it->x : _windowWidth + it->x;
it->SetValue(((x-bx-FONT_CHAR_WIDTH/2)/float(it->w))*(it->max - it->min) + it->min);
it->callback(it->value, it->callbackData);
_requiresRebuildStatic = true;
}
}
bool
Hud::MouseCapture() const
{
return _capturedSlider != -1;
}
void
Hud::MouseRelease()
{
_capturedSlider = -1;
}
void
Hud::AddLabel(const char *label, int x, int y)
{
Item l;
l.label = label;
l.x = x;
l.y = y;
_labels.push_back(l);
_requiresRebuildStatic = true;
}
void
Hud::AddCheckBox(const char *label, bool checked, int x, int y,
CheckBoxCallback callback, int data, int shortcut)
{
CheckBox cb;
cb.label = label;
cb.checked = checked;
cb.x = x;
cb.y = y;
cb.w = (int)(strlen(label)+1) * FONT_CHAR_WIDTH;
cb.h = FONT_CHAR_HEIGHT;
cb.callback = callback;
cb.callbackData = data;
cb.shortcut = shortcut;
_checkBoxes.push_back(cb);
_requiresRebuildStatic = true;
}
void
Hud::AddRadioButton(int group, const char *label, bool checked, int x, int y,
RadioButtonCallback callback, int data, int shortcut)
{
RadioButton rb;
rb.group = group;
rb.label = label;
rb.checked = checked;
rb.x = x;
rb.y = y;
rb.w = (int)(strlen(label)+1) * FONT_CHAR_WIDTH;
rb.h = FONT_CHAR_HEIGHT;
rb.callback = callback;
rb.callbackData = data;
rb.shortcut = shortcut;
rb.sharedShortcut = false;
rb.localIndex = 0;
for (std::vector<RadioButton>::iterator it = _radioButtons.begin();
it != _radioButtons.end(); ++it) {
if (it->group == group) {
rb.localIndex = it->localIndex+1;
if (it->shortcut == shortcut) {
it->sharedShortcut = true;
rb.sharedShortcut = true;
}
}
}
_radioButtons.push_back(rb);
_requiresRebuildStatic = true;
}
void
Hud::AddSlider(const char *label, float min, float max, float value,
int x, int y, int width, bool intStep, SliderCallback callback, int data)
{
Slider slider;
slider.label = label;
slider.x = x;
slider.y = y;
slider.w = width * FONT_CHAR_WIDTH;
slider.h = FONT_CHAR_HEIGHT * 2;
slider.min = min;
slider.max = max;
slider.value = value;
slider.callback = callback;
slider.callbackData = data;
slider.intStep = intStep;
_sliders.push_back(slider);
_requiresRebuildStatic = true;
}
int
Hud::AddPullDown(const char *label, int x, int y, int width,
PullDownCallback callback, int shortcut)
{
PullDown pd;
pd.label = label;
pd.x = x;
pd.y = y;
pd.w = width;
pd.h = FONT_CHAR_HEIGHT;
pd.open = false;
pd.selected = 0;
pd.callback = callback;
pd.shortcut = shortcut;
_pulldowns.push_back(pd);
_requiresRebuildStatic = true;
return (int)_pulldowns.size()-1;
}
void
Hud::AddPullDownButton(int handle, const char *label, int value, bool checked)
{
if (handle < (int)_pulldowns.size()) {
PullDown & pulldown = _pulldowns[handle];
pulldown.labels.push_back(label);
pulldown.values.push_back(value);
if (checked) {
pulldown.selected = (int)pulldown.labels.size()-1;
}
}
}
int
Hud::drawChar(std::vector<float> &vboSource,
int x, int y, float r, float g, float b, char ch)
{
const float w = 1.0f/FONT_TEXTURE_COLUMNS;
const float h = 1.0f/FONT_TEXTURE_ROWS;
float u = (ch%FONT_TEXTURE_COLUMNS)/(float)FONT_TEXTURE_COLUMNS;
float v = (ch/FONT_TEXTURE_COLUMNS)/(float)FONT_TEXTURE_ROWS;
vboSource.push_back(float(x));
vboSource.push_back(float(y));
vboSource.push_back(r);
vboSource.push_back(g);
vboSource.push_back(b);
vboSource.push_back(u);
vboSource.push_back(v);
vboSource.push_back(float(x));
vboSource.push_back(float(y+FONT_CHAR_HEIGHT));
vboSource.push_back(r);
vboSource.push_back(g);
vboSource.push_back(b);
vboSource.push_back(u);
vboSource.push_back(v+h);
vboSource.push_back(float(x+FONT_CHAR_WIDTH));
vboSource.push_back(float(y));
vboSource.push_back(r);
vboSource.push_back(g);
vboSource.push_back(b);
vboSource.push_back(u+w);
vboSource.push_back(v);
vboSource.push_back(float(x+FONT_CHAR_WIDTH));
vboSource.push_back(float(y));
vboSource.push_back(r);
vboSource.push_back(g);
vboSource.push_back(b);
vboSource.push_back(u+w);
vboSource.push_back(v);
vboSource.push_back(float(x));
vboSource.push_back(float(y+FONT_CHAR_HEIGHT));
vboSource.push_back(r);
vboSource.push_back(g);
vboSource.push_back(b);
vboSource.push_back(u);
vboSource.push_back(v+h);
vboSource.push_back(float(x+FONT_CHAR_WIDTH));
vboSource.push_back(float(y+FONT_CHAR_HEIGHT));
vboSource.push_back(r);
vboSource.push_back(g);
vboSource.push_back(b);
vboSource.push_back(u+w);
vboSource.push_back(v+h);
return x + FONT_CHAR_WIDTH;
}
int
Hud::drawString(std::vector<float> &vboSource,
int x, int y, float r, float g, float b, const char *c)
{
while (*c) {
char ch = (char)((*c) & 0x7f);
x = drawChar(vboSource, x, y, r, g, b, ch);
c++;
}
return x;
}
void
Hud::DrawString(int x, int y, const char *fmt, ...)
{
char buf[1024];
va_list args;
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
x = x > 0 ? x : _windowWidth + x;
y = y > 0 ? y : _windowHeight + y;
drawString(_vboSource, x, y, 1, 1, 1, buf);
}
void
Hud::DrawString(int x, int y, float r, float g, float b, const char *fmt, ...)
{
char buf[1024];
va_list args;
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
x = x > 0 ? x : _windowWidth + x;
y = y > 0 ? y : _windowHeight + y;
drawString(_vboSource, x, y, r, g, b, buf);
}
void
Hud::Rebuild(int width, int height, int framebufferWidth, int framebufferHeight)
{
_requiresRebuildStatic = false;
_windowWidth = width;
_windowHeight = height;
_framebufferWidth = framebufferWidth;
_framebufferHeight = framebufferHeight;
_staticVboSource.clear();
int x, y;
// add UI elements
for (std::vector<Item>::const_iterator it = _labels.begin();
it != _labels.end(); ++it) {
getWindowPos(*it, &x, &y);
drawString(_staticVboSource, x, y, 1, 1, 1, it->label.c_str());
}
// draw radio buttons
for (std::vector<RadioButton>::const_iterator it = _radioButtons.begin();
it != _radioButtons.end(); ++it) {
getWindowPos(*it, &x, &y);
if (it->checked) {
x = drawChar(_staticVboSource, x, y, 1, 1, 1, FONT_RADIO_BUTTON_ON);
drawString(_staticVboSource, x, y, 1, 1, 0, it->label.c_str());
} else {
x = drawChar(_staticVboSource, x, y, 1, 1, 1, FONT_RADIO_BUTTON_OFF);
drawString(_staticVboSource, x, y, .5f, .5f, .5f, it->label.c_str());
}
}
// draw checkboxes
for (std::vector<CheckBox>::const_iterator it = _checkBoxes.begin();
it != _checkBoxes.end(); ++it) {
getWindowPos(*it, &x, &y);
if (it->checked) {
x = drawChar(_staticVboSource, x, y, 1, 1, 1, FONT_CHECK_BOX_ON);
drawString(_staticVboSource, x, y, 1, 1, 0, it->label.c_str());
} else {
x = drawChar(_staticVboSource, x, y, 1, 1, 1, FONT_CHECK_BOX_OFF);
drawString(_staticVboSource, x, y, .5f, .5f, .5f, it->label.c_str());
}
}
// draw sliders
for (std::vector<Slider>::const_iterator it = _sliders.begin();
it != _sliders.end(); ++it) {
getWindowPos(*it, &x, &y);
int sx = x;
x = drawString(_staticVboSource, x, y, 1, 1, 1, it->label.c_str());
char value[16];
if (it->intStep) {
snprintf(value, 16, " : %d", (int)it->value);
} else {
snprintf(value, 16, " : %.2f", it->value);
}
drawString(_staticVboSource, x, y, 1, 1, 1, value);
// new line
y += FONT_CHAR_HEIGHT;
x = sx;
x = drawChar(_staticVboSource, x, y, 1, 1, 1, FONT_SLIDER_LEFT);
int nw = it->w / FONT_CHAR_WIDTH;
for (int i = 1; i < nw; ++i) {
x = drawChar(_staticVboSource, x, y, 1, 1, 1, FONT_SLIDER_MIDDLE);
}
drawChar(_staticVboSource, x, y, 1, 1, 1, FONT_SLIDER_RIGHT);
int pos = int(((it->value-it->min)/(it->max-it->min))*float(it->w));
drawChar(_staticVboSource, sx+pos, y, 1, 1, 0, FONT_SLIDER_CURSOR);
}
// draw pulldowns
for (std::vector<PullDown>::const_iterator it = _pulldowns.begin();
it != _pulldowns.end(); ++it) {
getWindowPos(*it, &x, &y);
x = drawString(_staticVboSource, x, y, .5f, .5f, .5f, it->label.c_str());
x += FONT_CHAR_WIDTH;
if (it->open) {
x = drawChar(_staticVboSource, x, y, 1, 1, 0, FONT_ARROW_DOWN);
x += FONT_CHAR_WIDTH;
for (int i=0; i<(int)it->labels.size(); ++i, y+=FONT_CHAR_HEIGHT) {
if (i==it->selected) {
drawString(_staticVboSource, x, y, 1, 1, 0, it->labels[i]);
} else {
drawString(_staticVboSource, x, y, 0.5f, 0.5f, 0.5f, it->labels[i]);
}
}
} else {
x = drawChar(_staticVboSource, x, y, .5f, .5f, .5f, FONT_ARROW_RIGHT);
x += FONT_CHAR_WIDTH;
drawString(_staticVboSource, x, y, 1, 1, 0, it->labels[it->selected]);
}
}
// draw the character cells corresponding to the logo
drawString(_staticVboSource, _windowWidth-128, _windowHeight-44, .5, .5, .5,
"\x06\x07\x08\x09");
drawString(_staticVboSource, _windowWidth-128, _windowHeight-28, .5, .5, .5,
"\x16\x17\x18\x19");
drawString(_staticVboSource, _windowWidth-92, _windowHeight-36, .5, .5, .5,
"\x0a\x0b\x0c\x0d");
drawString(_staticVboSource, _windowWidth-58, _windowHeight-36, .5, .5, .5,
"\x1a\x1b\x1c\x1d\x1e\x1f");
}
bool
Hud::Flush()
{
if (!_visible) {
_vboSource.clear();
return false;
}
if (_requiresRebuildStatic)
this->Rebuild(_windowWidth, _windowHeight, _framebufferWidth, _framebufferHeight);
return true;
}
bool
Hud::IsVisible() const
{
return _visible;
}
void
Hud::SetVisible(bool visible)
{
_visible = visible;
}
std::vector<float> &
Hud::getVboSource()
{
return _vboSource;
}
std::vector<float> &
Hud::getStaticVboSource()
{
return _staticVboSource;
}

View File

@@ -0,0 +1,189 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#ifndef HUD_H
#define HUD_H
#include <algorithm>
#include <cstdarg>
#include <math.h>
#include <string>
#include <vector>
#define OSD_HUD_USE_FUNCTION_POINTERS (__cplusplus <= 199711L)
#if !OSD_HUD_USE_FUNCTION_POINTERS
#include <functional>
#endif
#include "hud.h"
class Hud
{
public:
#if OSD_HUD_USE_FUNCTION_POINTERS
typedef void (*RadioButtonCallback)(int c);
typedef void (*CheckBoxCallback)(bool checked, int data);
typedef void (*SliderCallback)(float value, int data);
typedef void (*PullDownCallback)(int value);
#else
typedef std::function<void(int)> RadioButtonCallback;
typedef std::function<void(bool,int)> CheckBoxCallback;
typedef std::function<void(float, int)> SliderCallback;
typedef std::function<void(int)> PullDownCallback;
#endif
Hud();
virtual ~Hud();
virtual void Init(int width, int height, int framebufferWidth, int framebufferHeight);
virtual void Rebuild(int width, int height,
int framebufferWidth, int framebufferHeight);
virtual bool Flush();
bool IsVisible() const;
void SetVisible(bool visible);
void DrawString(int x, int y, const char *fmt, ...);
void DrawString(int x, int y, float r, float g, float b, const char *fmt, ...);
void Clear();
void AddLabel(const char *label, int x, int y);
void AddRadioButton(int group, const char *label, bool checked, int x, int y,
RadioButtonCallback callback=0, int data=0, int shortcut=0);
void AddCheckBox(const char *label, bool checked, int x, int y,
CheckBoxCallback callback=0, int data=0, int shortcut=0);
void AddSlider(const char *label, float min, float max, float value,
int x, int y, int width, bool intStep,
SliderCallback callback=0, int data=0);
int AddPullDown(const char *label, int x, int y, int width,
PullDownCallback callback=0, int shortcut=0);
void AddPullDownButton(int handle, const char *label, int value, bool checked=false);
bool KeyDown(int key);
bool MouseClick(int x, int y);
bool MouseCapture() const;
void MouseRelease();
void MouseMotion(int x, int y);
int GetWidth() const;
int GetHeight() const;
protected:
struct Item {
int x, y, w, h;
std::string label;
};
struct RadioButton : public Item {
int group;
int localIndex;
bool checked;
int shortcut;
bool sharedShortcut;
RadioButtonCallback callback;
int callbackData;
};
struct CheckBox : public Item {
bool checked;
CheckBoxCallback callback;
int callbackData;
int shortcut;
};
struct Slider : public Item {
float min, max;
float value;
SliderCallback callback;
int callbackData;
bool intStep;
void SetValue(float v) {
v = std::max(std::min(v, max), min);
if (intStep) {
// MSVC 2010 does not have std::round() or roundf()
v = v>0.0f ? floorf(v+0.5f) : ceilf(v-0.5f);
}
value = v;
}
};
struct PullDown : public Item {
bool open;
int selected;
std::vector<char const *> labels;
std::vector<int> values;
int shortcut;
PullDownCallback callback;
void SetSelected(int idx) {
if (idx>=0 && idx<(int)labels.size()) {
selected=idx;
}
}
};
static int drawString(std::vector<float> &vboSource, int x, int y,
float r, float g, float b, const char *c);
static int drawChar(std::vector<float> &vboSource, int x, int y,
float r, float g, float b, char ch);
bool hitTest(Item const &item, int x, int y) const {
int ix = item.x > 0 ? item.x : _windowWidth + item.x;
int iy = item.y > 0 ? item.y : _windowHeight + item.y;
return (x >= ix &&
y >= iy &&
x <= (ix + item.w) &&
y <= (iy + item.h));
}
void getWindowPos(Item const &item, int *x, int *y) const {
*x = item.x > 0 ? item.x : _windowWidth + item.x;
*y = item.y > 0 ? item.y : _windowHeight + item.y;
}
std::vector<float> & getVboSource();
std::vector<float> & getStaticVboSource();
private:
bool _visible;
std::vector<float> _vboSource, _staticVboSource;
int _windowWidth, _windowHeight;
int _framebufferWidth, _framebufferHeight;
bool _requiresRebuildStatic;
std::vector<Item> _labels;
std::vector<RadioButton> _radioButtons;
std::vector<CheckBox> _checkBoxes;
std::vector<Slider> _sliders;
std::vector<PullDown> _pulldowns;
int _capturedSlider;
};
#endif // HUD_H

View File

@@ -0,0 +1,45 @@
//
// Copyright 2015 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#ifndef OPENSUBDIV_EXAMPLES_MTL_CONTROL_MESH_DISPLAY_H
#define OPENSUBDIV_EXAMPLES_MTL_CONTROL_MESH_DISPLAY_H
#include <Metal/Metal.h>
#include <opensubdiv/far/topologyLevel.h>
class MTLControlMeshDisplay {
public:
MTLControlMeshDisplay(id<MTLDevice> device, MTLRenderPipelineDescriptor* pipelineDescriptor);
~MTLControlMeshDisplay() = default;
void Draw(id<MTLRenderCommandEncoder> encoder,
id<MTLBuffer> vertexBuffer,
const float *modelViewProjectionMatrix);
void SetTopology(OpenSubdiv::Far::TopologyLevel const &level);
bool GetEdgesDisplay() const { return _displayEdges; }
void SetEdgesDisplay(bool display) { _displayEdges = display; }
bool GetVerticesDisplay() const { return _displayVertices; }
void SetVerticesDisplay(bool display) { _displayVertices = display; }
private:
bool createProgram(MTLRenderPipelineDescriptor* pipelineDescriptor);
id<MTLDevice> _device;
bool _displayEdges;
bool _displayVertices;
int _numEdges, _numPoints;
id<MTLRenderPipelineState> _renderPipelineState;
id<MTLBuffer> _vertexSharpnessBuffer;
id<MTLBuffer> _edgeSharpnessBuffer;
id<MTLBuffer> _edgeIndicesBuffer;
};
#endif // OPENSUBDIV_EXAMPLES_MTL_CONTROL_MESH_DISPLAY_H

View File

@@ -0,0 +1,150 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#include "mtlControlMeshDisplay.h"
#include <cassert>
#include "mtlUtils.h"
static const char* s_Shader = R"(
#include <metal_stdlib>
using namespace metal;
float4 sharpnessToColor(float s) {
// 0.0 2.0 4.0
// green --- yellow --- red
return float4(min(1.0, s * 0.5),
min(1.0, 2.0 - s * 0.5),
0.0, 1.0);
}
struct DrawData
{
float4x4 ModelViewProjectionMatrix;
};
struct VertexData
{
float3 position [[attribute(0)]];
float sharpness [[attribute(1)]];
};
struct FragmentData
{
float4 position [[position]];
float4 color;
};
vertex FragmentData vs_main(VertexData in [[stage_in]],
const constant DrawData& drawData [[buffer(2)]]
)
{
FragmentData out;
out.position = drawData.ModelViewProjectionMatrix * float4(in.position, 1.0);
out.color = sharpnessToColor(in.sharpness);
return out;
}
fragment float4 fs_main(FragmentData in [[stage_in]])
{
return in.color;
}
)";
MTLControlMeshDisplay::MTLControlMeshDisplay(id<MTLDevice> device, MTLRenderPipelineDescriptor* pipelineDescriptor)
: _device(device), _displayEdges(false), _displayVertices(false), _numEdges(0), _numPoints(0) {
const auto result = createProgram(pipelineDescriptor);
assert(result && "Failed to create program for MTLControlMeshDisplay");
}
void MTLControlMeshDisplay::SetTopology(OpenSubdiv::Far::TopologyLevel const &level) {
using namespace OpenSubdiv;
_numEdges = level.GetNumEdges();
_numPoints = level.GetNumVertices();
std::vector<int> edgeIndices;
std::vector<float> edgeSharpness;
std::vector<float> vertSharpness;
edgeIndices.reserve(_numEdges * 2);
edgeSharpness.reserve(_numEdges);
vertSharpness.reserve(_numPoints);
for(int i = 0; i < _numEdges; i++) {
const auto verts = level.GetEdgeVertices(i);
edgeIndices.emplace_back(verts[0]);
edgeIndices.emplace_back(verts[1]);
edgeSharpness.emplace_back(level.GetEdgeSharpness(i));
}
for(int i = 0; i < _numPoints; i++) {
vertSharpness.emplace_back(level.GetVertexSharpness(i));
}
_edgeIndicesBuffer = Osd::MTLNewBufferFromVector(_device, edgeIndices);
_edgeSharpnessBuffer = Osd::MTLNewBufferFromVector(_device, edgeSharpness);
_vertexSharpnessBuffer = Osd::MTLNewBufferFromVector(_device, vertSharpness);
}
bool MTLControlMeshDisplay::createProgram(MTLRenderPipelineDescriptor* _pipelineDescriptor) {
const auto options = [MTLCompileOptions new];
NSError* error = nil;
const auto library = [_device newLibraryWithSource:@(s_Shader) options:options error:&error];
if(!library) {
printf("Failed to create library for MTLControlMeshDisplay\n%s\n", error ? [[error localizedDescription] UTF8String] : "");
return false;
}
const auto vertexFunction = [library newFunctionWithName:@"vs_main"];
const auto fragmentFunction = [library newFunctionWithName:@"fs_main"];
MTLRenderPipelineDescriptor* pipelineDescriptor = [_pipelineDescriptor copy];
pipelineDescriptor.vertexFunction = vertexFunction;
pipelineDescriptor.fragmentFunction = fragmentFunction;
const auto vertexDescriptor = pipelineDescriptor.vertexDescriptor;
vertexDescriptor.layouts[1].stride = sizeof(float) * 6;
vertexDescriptor.layouts[1].stepFunction = MTLVertexStepFunctionPerVertex;
vertexDescriptor.layouts[1].stepRate = 1;
vertexDescriptor.attributes[1].bufferIndex = 1;
vertexDescriptor.attributes[1].offset = 0;
vertexDescriptor.attributes[1].format = MTLVertexFormatFloat3;
_renderPipelineState = [_device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error];
if(!_renderPipelineState) {
printf("Failed to create render pipeline state for MTLControlMeshDisplay\n%s\n", error ? [[error localizedDescription] UTF8String] : "");
}
return true;
}
void MTLControlMeshDisplay::Draw(id<MTLRenderCommandEncoder> encoder,
id<MTLBuffer> vertexBuffer,
const float *modelViewProjectionMatrix) {
[encoder setRenderPipelineState: _renderPipelineState];
[encoder setVertexBuffer:vertexBuffer offset:0 atIndex:0];
[encoder setVertexBytes:modelViewProjectionMatrix length: sizeof(float) * 16 atIndex:2];
if(_displayEdges) {
[encoder setVertexBuffer:_edgeSharpnessBuffer offset:0 atIndex:1];
[encoder drawIndexedPrimitives:MTLPrimitiveTypeLine
indexCount:_numEdges * 2
indexType:MTLIndexTypeUInt32
indexBuffer:_edgeIndicesBuffer
indexBufferOffset:0
instanceCount:1
baseVertex:0
baseInstance:0];
}
if(_displayVertices) {
[encoder setVertexBuffer:_vertexSharpnessBuffer offset:0 atIndex:1];
[encoder drawPrimitives:MTLPrimitiveTypePoint
vertexStart:0
vertexCount:_numPoints];
}
}

View File

@@ -0,0 +1,55 @@
//
// Copyright 2016 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#ifndef OPENSUBDIV_EXAMPLES_MTL_HUD_H
#define OPENSUBDIV_EXAMPLES_MTL_HUD_H
@protocol MTLTexture;
@protocol MTLBuffer;
@protocol MTLRenderCommandEncoder;
@protocol MTLRenderPipelineState;
@protocol MTLDevice;
@class MTLRenderPipelineDescriptor;
@class MTLDepthStencilDescriptor;
#include "hud.h"
#include "mtlUtils.h"
class MTLhud : public Hud {
public:
MTLhud();
~MTLhud();
virtual void Init(id<MTLDevice> device, MTLRenderPipelineDescriptor* parentPipelineDescriptor, MTLDepthStencilDescriptor* depthStencilStateDescriptor,
int width, int height, int framebufferWidth, int framebufferHeight);
virtual void Rebuild(int width, int height,
int framebufferWidth, int framebufferHeight);
virtual bool Flush(id<MTLRenderCommandEncoder> encoder);
id<MTLTexture> GetFontTexture() const {
return _fontTexture;
}
void FillBackground(id<MTLRenderCommandEncoder> encoder);
float UIScale = 1.0f;
private:
id<MTLDevice> _device;
id<MTLTexture> _fontTexture;
OpenSubdiv::OPENSUBDIV_VERSION::Osd::MTLRingBuffer<float, 1> _staticBuffer;
OpenSubdiv::OPENSUBDIV_VERSION::Osd::MTLRingBuffer<float, 3> _dynamicBuffer;
id<MTLRenderPipelineState> _fgPipelineState, _bgPipelineState;
id<MTLDepthStencilState> _depthStencilState;
};
#endif //OPENSUBDIV_EXAMPLES_MTL_HUD_H

View File

@@ -0,0 +1,191 @@
//
// Copyright 2016 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#include "mtlHud.h"
#include "font_image.h"
#include "simple_math.h"
#include <Metal/Metal.h>
static const char* shaderSource = R"(
#include <metal_stdlib>
using namespace metal;
struct VertexInput {
float2 position [[attribute(0)]];
float3 color [[attribute(1)]];
float2 uv [[attribute(2)]];
};
struct VertexOutput {
float4 position [[position]];
float4 color;
float2 uv;
};
vertex VertexOutput fg_vertex(
VertexInput in [[stage_in]],
constant const float4x4& ModelViewProjectionMatrix [[buffer(1)]],
constant const float& UIScale [[buffer(2)]]
) {
VertexOutput out;
out.position = ModelViewProjectionMatrix * float4(in.position * UIScale, 0, 1);
out.color = float4(in.color, 1);
out.uv = in.uv;
return out;
}
fragment float4 fg_fragment(
VertexOutput in [[stage_in]],
texture2d<float, access::sample> fontTexture [[texture(0)]]
) {
constexpr sampler s = sampler(coord::normalized, address::clamp_to_zero, filter::nearest);
auto c = fontTexture.sample(s, in.uv);
if(c.a == 0)
discard_fragment();
return c * in.color;
}
constant float4 bgVertices[] = {
{-1, 1, 0, 1},
{1, 1, 0, 1},
{-1, -1, 0, 1},
{1, -1, 0, 1}
};
vertex VertexOutput bg_vertex(uint vertex_id [[vertex_id]]) {
VertexOutput out;
out.position = bgVertices[vertex_id];
out.uv = bgVertices[vertex_id].xy * 0.5 + 0.5 * 3.14159;
return out;
}
fragment float4 bg_fragment(VertexOutput in [[stage_in]]) {
return float4(float3(mix(0.1, 0.5, sin(in.uv.y))), 1);
}
)";
MTLhud::MTLhud() {
}
MTLhud::~MTLhud() {
}
void
MTLhud::Init(id<MTLDevice> device, MTLRenderPipelineDescriptor* parentPipelineDescriptor, MTLDepthStencilDescriptor* depthStencilStateDescriptor, int width, int height, int framebufferWidth, int framebufferHeight) {
Hud::Init(width, height, framebufferWidth, framebufferHeight);
@autoreleasepool {
_device = device;
const auto textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm width:FONT_TEXTURE_WIDTH height:FONT_TEXTURE_HEIGHT mipmapped:false];
_fontTexture = [_device newTextureWithDescriptor:textureDescriptor];
[_fontTexture replaceRegion: { {0, 0, 0}, {FONT_TEXTURE_WIDTH, FONT_TEXTURE_HEIGHT, 1} } mipmapLevel:0 withBytes:font_image bytesPerRow:4 * FONT_TEXTURE_WIDTH];
NSError* err = nil;
const auto library = [_device newLibraryWithSource:@(shaderSource) options:nil error:&err];
assert(err == nil);
const auto renderPipelineDescriptor = (MTLRenderPipelineDescriptor*)[parentPipelineDescriptor copy];
renderPipelineDescriptor.vertexFunction = [library newFunctionWithName:@"bg_vertex"];
renderPipelineDescriptor.fragmentFunction = [library newFunctionWithName:@"bg_fragment"];
_bgPipelineState = [_device newRenderPipelineStateWithDescriptor:renderPipelineDescriptor error:&err];
renderPipelineDescriptor.vertexFunction = [library newFunctionWithName:@"fg_vertex"];
renderPipelineDescriptor.fragmentFunction = [library newFunctionWithName:@"fg_fragment"];
const auto vertexDescriptor = renderPipelineDescriptor.vertexDescriptor;
vertexDescriptor.layouts[0].stride = sizeof(float) * 7;
vertexDescriptor.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;
vertexDescriptor.layouts[0].stepRate = 1;
vertexDescriptor.attributes[0].offset = 0;
vertexDescriptor.attributes[0].format = MTLVertexFormatFloat2;
vertexDescriptor.attributes[0].bufferIndex = 0;
vertexDescriptor.attributes[1].offset = sizeof(float) * 2;
vertexDescriptor.attributes[1].format = MTLVertexFormatFloat3;
vertexDescriptor.attributes[1].bufferIndex = 0;
vertexDescriptor.attributes[2].offset = sizeof(float) * 5;
vertexDescriptor.attributes[2].format = MTLVertexFormatFloat2;
vertexDescriptor.attributes[2].bufferIndex = 0;
_fgPipelineState = [_device newRenderPipelineStateWithDescriptor:renderPipelineDescriptor error:&err];
_depthStencilState = [_device newDepthStencilStateWithDescriptor:depthStencilStateDescriptor];
}
}
void
MTLhud::Rebuild(int width, int height, int framebufferWidth, int framebufferHeight) {
Hud::Rebuild(width, height, framebufferWidth, framebufferHeight);
_staticBuffer.alloc(_device, getStaticVboSource().size(), @"MTLhud static buffer");
std::copy(getStaticVboSource().begin(), getStaticVboSource().end(), _staticBuffer.data());
_staticBuffer.markModified();
}
bool
MTLhud::Flush(id<MTLRenderCommandEncoder> encoder) {
if(!Hud::Flush())
return false;
if(_dynamicBuffer.buffer().length < sizeof(float) * getVboSource().size()) {
_dynamicBuffer.alloc(_device, getVboSource().size(), @"MTLhud dynamic buffer");
} else {
_dynamicBuffer.next();
}
std::copy(getVboSource().begin(), getVboSource().end(), _dynamicBuffer.data());
_dynamicBuffer.markModified();
const auto numVertices = getVboSource().size() / 7;
getVboSource().clear();
float proj[16];
ortho(proj, 0, 0, float(GetWidth()), float(GetHeight()));
[encoder setVertexBuffer: _dynamicBuffer.buffer() offset:0 atIndex:0];
[encoder setRenderPipelineState: _fgPipelineState];
[encoder setDepthStencilState: _depthStencilState];
[encoder setVertexBytes: proj length: sizeof(proj) atIndex:1];
[encoder setVertexBytes: &UIScale length:sizeof(UIScale) atIndex:2];
[encoder setFragmentTexture: _fontTexture atIndex:0];
if(numVertices > 0) {
[encoder setVertexBuffer:_dynamicBuffer.buffer() offset:0 atIndex:0];
[encoder drawPrimitives: MTLPrimitiveTypeTriangle vertexStart:0 vertexCount: numVertices];
}
auto numStaticVertices = [_staticBuffer.buffer() length] / (7 * sizeof(float));
if(numStaticVertices > 0) {
[encoder setVertexBuffer:_staticBuffer.buffer() offset:0 atIndex:0];
[encoder drawPrimitives: MTLPrimitiveTypeTriangle vertexStart:0 vertexCount: numStaticVertices];
}
return true;
}
void
MTLhud::FillBackground(id<MTLRenderCommandEncoder> encoder) {
[encoder setRenderPipelineState: _bgPipelineState];
[encoder setDepthStencilState: _depthStencilState];
[encoder drawPrimitives: MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount: 4];
}

View File

@@ -0,0 +1,366 @@
#line 0 "examples/common/mtlPtexCommon.metal"
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
//----------------------------------------------------------
// Ptex.Common
//----------------------------------------------------------
template<typename T>
T lerp(T x, T y, float a)
{
return x + (y - x) * a;
}
template<>
int lerp<int>(int x, int y, float a)
{
return x + (y - x) * a;
}
struct PtexPacking {
int page;
int nMipmap;
int uOffset;
int vOffset;
int adjSizeDiffs[4];
int width;
int height;
};
PtexPacking getPtexPacking(device ushort* packings, int faceID)
{
PtexPacking packing;
packing.page = packings[faceID*6+0];
packing.nMipmap = packings[faceID*6+1];
packing.uOffset = packings[faceID*6+2];
packing.vOffset = packings[faceID*6+3];
int wh = packings[faceID*6+5];
packing.width = 1 << (wh >> 8);
packing.height = 1 << (wh & 0xff);
int adjSizeDiffs = packings[faceID*6+4];
packing.adjSizeDiffs[0] = (adjSizeDiffs >> 12) & 0xf;
packing.adjSizeDiffs[1] = (adjSizeDiffs >> 8) & 0xf;
packing.adjSizeDiffs[2] = (adjSizeDiffs >> 4) & 0xf;
packing.adjSizeDiffs[3] = (adjSizeDiffs >> 0) & 0xf;
return packing;
}
int computeMipmapOffsetU(int w, int level)
{
int width = 1 << w;
int m = (0x55555555 & (width | (width-1))) << (w&1);
int x = ~((1 << (w -((level-1)&~1))) - 1);
return (m & x) + ((level+1)&~1);
}
int computeMipmapOffsetV(int h, int level)
{
int height = 1 << h;
int m = (0x55555555 & (height-1)) << ((h+1)&1);;
int x = ~((1 << (h - (level&~1))) - 1 );
return (m & x) + (level&~1);
}
PtexPacking getPtexPacking(device ushort* packings, int faceID, int level)
{
PtexPacking packing;
packing.page = packings[faceID*6+0];
packing.nMipmap = packings[faceID*6+1];
packing.uOffset = packings[faceID*6+2];
packing.vOffset = packings[faceID*6+3];
//int sizeDiffs = packings[faceID*6+4];
int wh = packings[faceID*6+5];
int w = wh >> 8;
int h = wh & 0xff;
// clamp max level
level = min(level, packing.nMipmap);
packing.uOffset += computeMipmapOffsetU(w, level);
packing.vOffset += computeMipmapOffsetV(h, level);
packing.width = 1 << (w-level);
packing.height = 1 << (h-level);
return packing;
}
void evalQuadraticBSpline(float u, thread float3& B, thread float3& BU)
{
B[0] = 0.5 * (u*u - 2.0*u + 1);
B[1] = 0.5 + u - u*u;
B[2] = 0.5 * u*u;
BU[0] = u - 1.0;
BU[1] = 1 - 2 * u;
BU[2] = u;
}
// ----------------------------------------------------------------------------
// Non-Mipmap Lookups
// ----------------------------------------------------------------------------
template<typename Texture>
auto PtexLookupNearest(float4 patchCoord,
Texture data,
device ushort* packings) -> decltype(data.read(uint2(), int()))
{
float2 uv = clamp(patchCoord.xy, float2(0,0), float2(1,1));
int faceID = int(patchCoord.w);
PtexPacking ppack = getPtexPacking(packings, faceID);
float2 coords = float2(uv.x * ppack.width + ppack.uOffset,
uv.y * ppack.height + ppack.vOffset);
return float4(data.read(uint2(coords.x, coords.y), ppack.page));
}
template<typename Texture>
auto PtexLookupNearest(float4 patchCoord,
int level,
Texture data,
device ushort* packings) -> decltype(data.read(uint2(), int()))
{
float2 uv = clamp(patchCoord.xy, float2(0,0), float2(1,1));
int faceID = int(patchCoord.w);
PtexPacking ppack = getPtexPacking(packings, faceID, level);
float2 coords = float2(uv.x * ppack.width + ppack.uOffset,
uv.y * ppack.height + ppack.vOffset);
return float4(data.read(uint2(coords.x, coords.y), ppack.page));
}
template<typename Texture>
auto PtexLookupFast(float4 patchCoord,
Texture data,
device ushort* packings) -> decltype(data.sample(sampler(), float2(), int()))
{
constexpr sampler smp(coord::normalized, address::clamp_to_edge, filter::linear);
float2 uv = clamp(patchCoord.xy, float2(0), float2(1));
int faceID = int(patchCoord.w);
PtexPacking ppack = getPtexPacking(packings, faceID);
float2 coords = float2((uv.x * ppack.width + ppack.uOffset),
(uv.y * ppack.height + ppack.vOffset)) / float2(data.get_width(), data.get_height());
return data.sample(smp, coords, ppack.page);
}
template<typename Texture>
auto PtexLookupFast(float4 patchCoord,
float level,
Texture data,
device ushort* packings) -> decltype(data.sample(sampler(), float2(), int(), bias(level)))
{
constexpr sampler smp(coord::normalized, address::clamp_to_edge, filter::linear);
float2 uv = clamp(patchCoord.xy, float2(0), float2(1));
int faceID = int(patchCoord.w);
PtexPacking ppack = getPtexPacking(packings, faceID, level);
float2 coords = float2((uv.x * ppack.width + ppack.uOffset),
(uv.y * ppack.height + ppack.vOffset)) / float2(data.get_width(), data.get_height());
return data.sample(smp, coords, ppack.page, bias(level));
}
template<typename Texture>
auto PtexLookup(float4 patchCoord,
int level,
Texture data,
device ushort* packings) -> decltype(data.read(uint2(), int()))
{
float2 uv = clamp(patchCoord.xy, float2(0,0), float2(1,1));
int faceID = int(patchCoord.w);
PtexPacking ppack = getPtexPacking(packings, faceID, level);
float2 coords = float2(uv.x * ppack.width + ppack.uOffset,
uv.y * ppack.height + ppack.vOffset);
coords -= float2(0.5, 0.5);
int c0X = int(floor(coords.x));
int c1X = int(ceil(coords.x));
int c0Y = int(floor(coords.y));
int c1Y = int(ceil(coords.y));
float t = coords.x - float(c0X);
float s = coords.y - float(c0Y);
const auto d0 = float4(data.read(uint2(c0X, c0Y), ppack.page));
const auto d1 = float4(data.read(uint2(c0X, c1Y), ppack.page));
const auto d2 = float4(data.read(uint2(c1X, c0Y), ppack.page));
const auto d3 = float4(data.read(uint2(c1X, c1Y), ppack.page));
const auto result = (1.0f-t) * ((1.0f-s)*d0 + s*d1) + t * ((1.0f-s)*d2 + s*d3);
return result;
}
template<typename Texture>
auto PtexLookupQuadratic(thread float4& du,
thread float4& dv,
float4 patchCoord,
int level,
Texture data,
device ushort* packings) -> decltype(data.read(uint2(), int()))
{
using dataType = decltype(data.read(uint2(), int()));
float2 uv = clamp(patchCoord.xy, float2(0,0), float2(1,1));
int faceID = int(patchCoord.w);
PtexPacking ppack = getPtexPacking(packings, faceID, level);
float2 coords = float2(uv.x * ppack.width + ppack.uOffset,
uv.y * ppack.height + ppack.vOffset);
coords -= float2(0.5, 0.5);
int cX = int(round(coords.x));
int cY = int(round(coords.y));
float x = 0.5 - (float(cX) - coords.x);
float y = 0.5 - (float(cY) - coords.y);
dataType d[9];
d[0] = data.read(uint2(cX-1, cY-1), ppack.page);
d[1] = data.read(uint2(cX-1, cY-0), ppack.page);
d[2] = data.read(uint2(cX-1, cY+1), ppack.page);
d[3] = data.read(uint2(cX-0, cY-1), ppack.page);
d[4] = data.read(uint2(cX-0, cY-0), ppack.page);
d[5] = data.read(uint2(cX-0, cY+1), ppack.page);
d[6] = data.read(uint2(cX+1, cY-1), ppack.page);
d[7] = data.read(uint2(cX+1, cY-0), ppack.page);
d[8] = data.read(uint2(cX+1, cY+1), ppack.page);
float3 B, D;
dataType BUCP[3] = {dataType(0), dataType(0), dataType(0)},
DUCP[3] = {dataType(0), dataType(0), dataType(0)};
evalQuadraticBSpline(y, B, D);
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; j++) {
float4 A = d[i*3+j];
BUCP[i] += A * B[j];
DUCP[i] += A * D[j];
}
}
evalQuadraticBSpline(x, B, D);
dataType result = dataType(0);
du = dataType(0);
dv = dataType(0);
for (int i = 0; i < 3; ++i) {
result += B[i] * BUCP[i];
du += D[i] * BUCP[i];
dv += B[i] * DUCP[i];
}
du *= ppack.width;
dv *= ppack.height;
return result;
}
// ----------------------------------------------------------------------------
// MipMap Lookups
// ----------------------------------------------------------------------------
template<typename Texture>
auto PtexMipmapLookupNearest(float4 patchCoord,
float level,
Texture data,
device ushort* packings) -> decltype(PtexLookupNearest(patchCoord, int(), data, packings))
{
#if SEAMLESS_MIPMAP
// diff level
int faceID = int(patchCoord.w);
float2 uv = patchCoord.xy;
PtexPacking packing = getPtexPacking(packings, faceID);
level += lerp(lerp(packing.adjSizeDiffs[0], packing.adjSizeDiffs[1], uv.x),
lerp(packing.adjSizeDiffs[3], packing.adjSizeDiffs[2], uv.x),
uv.y);
#endif
int levelm = int(floor(level));
int levelp = int(ceil(level));
float t = level - float(levelm);
const auto result = (1-t) * PtexLookupNearest(patchCoord, levelm, data, packings)
+ t * PtexLookupNearest(patchCoord, levelp, data, packings);
return result;
}
template<typename Texture>
auto PtexMipmapLookup(float4 patchCoord,
float level,
Texture data,
device ushort* packings) -> decltype(PtexLookup(patchCoord, int(), data, packings))
{
#if SEAMLESS_MIPMAP
// diff level
int faceID = int(patchCoord.w);
float2 uv = patchCoord.xy;
PtexPacking packing = getPtexPacking(packings, faceID);
level += lerp(lerp(packing.adjSizeDiffs[0], packing.adjSizeDiffs[1], uv.x),
lerp(packing.adjSizeDiffs[3], packing.adjSizeDiffs[2], uv.x),
uv.y);
#endif
int levelm = int(floor(level));
int levelp = int(ceil(level));
float t = level - float(levelm);
const auto result = (1-t) * PtexLookup(patchCoord, levelm, data, packings)
+ t * PtexLookup(patchCoord, levelp, data, packings);
return result;
}
template<typename Texture>
auto PtexMipmapLookupQuadratic(thread float4& du,
thread float4& dv,
float4 patchCoord,
float level,
Texture data,
device ushort* packings) -> decltype(PtexLookupQuadratic(du, dv, patchCoord, int(), data, packings))
{
using dataType = decltype(PtexLookupQuadratic(du, dv, patchCoord, int(), data, packings));
#if SEAMLESS_MIPMAP
// diff level
int faceID = int(patchCoord.w);
float2 uv = patchCoord.xy;
PtexPacking packing = getPtexPacking(packings, faceID);
level += lerp(lerp(packing.adjSizeDiffs[0], packing.adjSizeDiffs[1], uv.x),
lerp(packing.adjSizeDiffs[3], packing.adjSizeDiffs[2], uv.x),
uv.y);
#endif
int levelm = int(floor(level));
int levelp = int(ceil(level));
float t = level - float(levelm);
float4 du0, du1, dv0, dv1;
const auto r0 = PtexLookupQuadratic(du0, dv0, patchCoord, levelm, data, packings);
const auto r1 = PtexLookupQuadratic(du1, dv1, patchCoord, levelp, data, packings);
const auto result = lerp(r0, r1, t);
du = lerp(du0, du1, t);
dv = lerp(dv0, dv1, t);
return result;
}
template<typename Texture>
auto PtexMipmapLookupQuadratic(float4 patchCoord,
float level,
Texture data,
device ushort* packings) -> decltype(data.read(uint2(), int())) //decltype(PtexMipmapLookupQuadratic(float4(), float4(), patchCoord, level, packings)) //Not using the correct decltpye due to the need for thread& types
{
float4 du, dv;
return PtexMipmapLookupQuadratic(du, dv, patchCoord, level, data, packings);
}

View File

@@ -0,0 +1,41 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#ifndef OPENSUBDIV_EXAMPLES_MTL_PTEX_MIPMAP_TEXTURE_H
#define OPENSUBDIV_EXAMPLES_MTL_PTEX_MIPMAP_TEXTURE_H
#include <opensubdiv/osd/mtlCommon.h>
#include <opensubdiv/osd/nonCopyable.h>
#include <Ptexture.h>
@protocol MTLBuffer;
@protocol MTLTexture;
@class MTLTextureDescriptor;
class MTLPtexMipmapTexture : OpenSubdiv::Osd::NonCopyable<MTLPtexMipmapTexture> {
public:
static MTLPtexMipmapTexture * Create(OpenSubdiv::Osd::MTLContext * deviceContext,
PtexTexture * reader,
int maxLevels = 10);
static const char* GetShaderSource();
id<MTLBuffer> GetLayoutBuffer() const { return _layout; }
id<MTLTexture> GetTexelsTexture() const { return _texels; }
private:
MTLPtexMipmapTexture();
id<MTLBuffer> _layout;
id<MTLTexture> _texels;
MTLTextureDescriptor* _textureDescriptor;
};
#endif // OPENSUBDIV_EXAMPLES_MTL_PTEX_TEXTURE_H

View File

@@ -0,0 +1,114 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#include "mtlPtexMipmapTexture.h"
#include "ptexMipmapTextureLoader.h"
#include <opensubdiv/far/error.h>
#include <Metal/Metal.h>
#include <cassert>
#include "mtlUtils.h"
using namespace OpenSubdiv;
MTLPtexMipmapTexture::MTLPtexMipmapTexture() :
_layout(nil), _texels(nil), _textureDescriptor(nil) {
}
const char* MTLPtexMipmapTexture::GetShaderSource() {
static const char* shaderSource =
#include "mtlPtexCommon.gen.h"
;
return shaderSource;
}
MTLPtexMipmapTexture * MTLPtexMipmapTexture::Create(Osd::MTLContext *deviceContext, PtexTexture *reader, int maxLevels) {
const auto maxNumPages = 2048;
size_t targetMemory = 0;
// Read the ptex data and pack the texels
bool padAlpha = reader->numChannels()==3;
PtexMipmapTextureLoader loader(reader,
maxNumPages,
maxLevels,
targetMemory,
true/*seemlessMipmap*/,
padAlpha);
const auto numFaces = loader.GetNumFaces();
const auto layoutBuffer = [deviceContext->device newBufferWithBytes:loader.GetLayoutBuffer() length:numFaces * 6 * sizeof(short) options:Osd::MTLDefaultStorageMode];
const auto textureDescriptor = [MTLTextureDescriptor new];
int bpp = 0;
textureDescriptor.pixelFormat = [&]() {
const auto numChannels = reader->numChannels() + padAlpha;
switch(reader->dataType()) {
case Ptex::dt_uint16:
bpp = sizeof(short) * numChannels;
switch(numChannels) {
case 1: return MTLPixelFormatR16Unorm;
case 2: return MTLPixelFormatRG16Unorm;
case 3: assert("RGB16Uint not supported"); break;
case 4: return MTLPixelFormatRGBA16Unorm;
}
case Ptex::dt_float:
bpp = sizeof(float) * numChannels;
switch(numChannels) {
case 1: return MTLPixelFormatR32Float;
case 2: return MTLPixelFormatRG32Float;
case 3: assert("RGB32Float not supported"); break;
case 4: return MTLPixelFormatRGBA32Float;
}
case Ptex::dt_half:
bpp = sizeof(short) * numChannels;
switch(numChannels) {
case 1: return MTLPixelFormatR16Float;
case 2: return MTLPixelFormatRG16Float;
case 3: assert("RGB16Float not supported"); break;
case 4: return MTLPixelFormatRGBA16Float;
}
default:
bpp = numChannels;
switch(numChannels) {
case 1: return MTLPixelFormatR8Unorm;
case 2: return MTLPixelFormatRG8Unorm;
case 3: assert("RGB8Unorm not supported"); break;
case 4: return MTLPixelFormatRGBA8Unorm;
}
}
return MTLPixelFormatInvalid;
}();
textureDescriptor.width = loader.GetPageWidth();
textureDescriptor.height = loader.GetPageHeight();
textureDescriptor.arrayLength = loader.GetNumPages();
textureDescriptor.mipmapLevelCount = 1;
textureDescriptor.usage = MTLTextureUsageShaderRead;
textureDescriptor.textureType = MTLTextureType2DArray;
const auto texelsTexture = [deviceContext->device newTextureWithDescriptor:textureDescriptor];
if(!texelsTexture)
return nullptr;
auto result = new MTLPtexMipmapTexture();
result->_textureDescriptor = textureDescriptor;
result->_layout = layoutBuffer;
result->_texels = texelsTexture;
MTLRegion replaceRegion = MTLRegionMake2D(0, 0, loader.GetPageWidth(), loader.GetPageHeight());
const auto bytesPerRow = loader.GetPageWidth() * bpp;
const auto bytesPerImage = bytesPerRow * loader.GetPageHeight();
for(auto i = 0; i < loader.GetNumPages(); i++) {
[texelsTexture replaceRegion:replaceRegion mipmapLevel:0 slice:i
withBytes:loader.GetTexelBuffer() + i * bytesPerImage bytesPerRow:bytesPerRow bytesPerImage:bytesPerImage];
}
return result;
}

View File

@@ -0,0 +1,104 @@
//
// Copyright 2015 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#ifndef OPENSUBDIV_EXAMPLES_MTL_UTILS_H
#define OPENSUBDIV_EXAMPLES_MTL_UTILS_H
#include <Metal/Metal.h>
#include <cstring>
#include <TargetConditionals.h>
#include <vector>
namespace OpenSubdiv { namespace OPENSUBDIV_VERSION { namespace Osd {
#if TARGET_OS_EMBEDDED
constexpr auto MTLDefaultStorageMode = MTLResourceStorageModeShared;
#else
constexpr auto MTLDefaultStorageMode = MTLResourceStorageModeManaged;
#endif
template<typename T>
id<MTLBuffer> MTLNewBufferFromVector(id<MTLDevice> device, const std::vector<T>& vec) {
const auto typeSize = sizeof(T);
const auto bufferSize = typeSize * vec.size();
return [device newBufferWithBytes:vec.data() length:bufferSize options:MTLDefaultStorageMode];
}
template<typename DataType, size_t RingLength>
class MTLRingBuffer {
private:
id<MTLBuffer> _buffers[RingLength];
uint _bufferIndex;
public:
template<typename SizedType = DataType>
MTLRingBuffer(id<MTLDevice> device, size_t count, NSString* label, MTLResourceOptions options = MTLDefaultStorageMode) {
alloc<SizedType>(device, count, options, label);
}
MTLRingBuffer() {
for(uint i = 0; i < RingLength; i++) {
_buffers[i] = nil;
}
_bufferIndex = 0;
}
void markModified() const {
#if !TARGET_OS_EMBEDDED
const auto bufferLength = [buffer() length];
[buffer() didModifyRange: NSMakeRange(0, bufferLength)];
#endif
}
template<typename SizedType = DataType>
void alloc(id<MTLDevice> device, size_t count, NSString* label, MTLResourceOptions options = MTLDefaultStorageMode) {
if(count) {
for(uint i = 0; i < RingLength; i++) {
_buffers[i] = [device newBufferWithLength: count * sizeof(SizedType) options:options];
_buffers[i].label = label;
_bufferIndex = i;
if((options & MTLResourceStorageModePrivate) == 0)
{
memset(data(), 0, count * sizeof(SizedType));
markModified();
}
}
} else {
for(uint i = 0; i < RingLength; i++) {
_buffers[i] = nil;
}
}
_bufferIndex = 0;
}
id<MTLBuffer> buffer() const {
return _buffers[_bufferIndex];
}
DataType* data() const {
return reinterpret_cast<DataType*>([buffer() contents]);
}
void next() {
_bufferIndex = (_bufferIndex + 1) % RingLength;
}
operator id<MTLBuffer>() const {
return buffer();
}
DataType* operator->() const {
return data();
}
DataType& operator[](int idx) const {
return (data())[idx];
}
};
#endif // OPENSUBDIV_EXAMPLES_MTL_UTILS_H
} } using namespace OPENSUBDIV_VERSION; }

View File

@@ -0,0 +1,8 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#include "mtlUtils.h"

View File

@@ -0,0 +1,145 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#include "objAnim.h"
#include "../../regression/common/shape_utils.h"
#include <cassert>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <fstream>
#include <sstream>
#include <sstream>
ObjAnim::ObjAnim() : _shape(0) {
}
ObjAnim::~ObjAnim() {
delete _shape;
}
void
ObjAnim::InterpolatePositions(float time, float * positions, int stride) const {
assert(positions);
if ( _positions.empty() || (! _shape)) {
//printf("Error: InterpolatePositions on unfit ObjAnim instance\n");
return;
}
int nkeys = GetNumKeyframes(),
nverts = GetShape()->GetNumVertices();
assert(nkeys>0);
if (nkeys==1) {
// nothing to interpolate - just copy the coarse verts positions
float const * vert = &_positions[0][0];
for (int i = 0; i <nverts; ++i) {
memcpy( positions, vert, sizeof(float)*3);
positions += stride;
vert += 3;
}
return;
}
const float fps = 24.0f;
float p = fmodf(time * fps, (float)nkeys);
int key = (int)p;
float b = p - key;
for (int i = 0; i <nverts; ++i) {
for (int j=0; j<3; ++j) {
float p0 = _positions[ key ][i*3+j];
float p1 = _positions[(key+1)%nkeys][i*3+j];
positions[i*stride + j] = p0*(1-b) + p1*b;
}
}
}
ObjAnim const *
ObjAnim::Create(std::vector<char const *> objFiles, Scheme scheme, bool isLeftHanded) {
ObjAnim * anim=0;
Shape const * shape = 0;
if (! objFiles.empty()) {
anim = new ObjAnim;
anim->_positions.reserve(objFiles.size());
for (int i = 0; i < (int)objFiles.size(); ++i) {
if (! objFiles[i]) {
continue;
}
std::ifstream ifs(objFiles[i]);
if (ifs) {
std::stringstream ss;
ss << ifs.rdbuf();
ifs.close();
printf("Reading %s\r", objFiles[i]);
fflush(stdout);
std::string str = ss.str();
shape = Shape::parseObj(str.c_str(), scheme, isLeftHanded);
if (i==0) {
anim->_shape = shape;
anim->_positions.push_back(shape->verts);
} else {
if (shape->verts.size() != anim->_shape->verts.size()) {
printf("Error: vertex count doesn't match (%s)\n", objFiles[i]);
goto error;
}
if (shape->nvertsPerFace.size() != anim->_shape->nvertsPerFace.size()) {
printf("Error: face vertex count array doesn't match (%s)\n", objFiles[i]);
goto error;
}
if (shape->faceverts.size() != anim->_shape->faceverts.size()) {
printf("Error: face vertices array doesn't match (%s)\n", objFiles[i]);
goto error;
}
anim->_positions.push_back(shape->verts);
delete shape;
}
} else {
printf("Error in reading %s\n", objFiles[i]);
goto error;
}
}
printf("\n");
}
return anim;
error:
delete shape;
delete anim;
return 0;
}

View File

@@ -0,0 +1,50 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#ifndef OBJ_ANIM_H
#define OBJ_ANIM_H
#include "../../regression/common/shape_utils.h"
#include <vector>
class ObjAnim {
public:
// Factory function
static ObjAnim const * Create(std::vector<char const *> objFiles,
Scheme scheme, bool isLeftHanded=false);
// Destructor
~ObjAnim();
// Populates 'positions' with the interpolated vertex data for a given
// time.
void InterpolatePositions(float time, float * positions, int stride) const;
// Number of key-frames in the animation
int GetNumKeyframes() const {
return (int)_positions.size();
}
// Returns the full 'Shape'
Shape const * GetShape() const {
return _shape;
}
private:
ObjAnim();
Shape const * _shape;
std::vector<std::vector<float> > _positions;
};
#endif // OBJ_ANIM_H

View File

@@ -0,0 +1,25 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#include "patchColors.h"
static float _colors[7][4] = {{1.0f, 1.0f, 1.0f, 1.0f}, // regular
{1.0f, 0.5f, 0.5f, 1.0f}, // single crease
{0.8f, 0.0f, 0.0f, 1.0f}, // boundary
{0.0f, 1.0f, 0.0f, 1.0f}, // corner
{1.0f, 1.0f, 0.0f, 1.0f}, // gregory
{1.0f, 0.5f, 0.0f, 1.0f}, // gregory boundary
{1.0f, 0.7f, 0.3f, 1.0f}}; // gregory basis
typedef OpenSubdiv::Far::PatchDescriptor Descriptor;
float const *
getAdaptivePatchColor(Descriptor const & desc) {
return _colors[(int)(desc.GetType()-Descriptor::REGULAR)];
}

View File

@@ -0,0 +1,17 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#ifndef OPENSUBDIV_EXAMPLES_COMMON_PATCH_COLORS_H
#define OPENSUBDIV_EXAMPLES_COMMON_PATCH_COLORS_H
#include <opensubdiv/far/patchTable.h>
// returns a unique color for each type of feature-adaptive patches
float const * getAdaptivePatchColor(OpenSubdiv::Far::PatchDescriptor const & desc);
#endif /* OPENSUBDIV_EXAMPLES_COMMON_PATCH_COLORS_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,139 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#ifndef OPENSUBDIV_EXAMPLES_PTEX_MIPMAP_TEXTURE_LOADER_H
#define OPENSUBDIV_EXAMPLES_PTEX_MIPMAP_TEXTURE_LOADER_H
#include <Ptexture.h>
#include <stdlib.h>
#include <stdint.h>
#include <vector>
class PtexMipmapTextureLoader {
public:
PtexMipmapTextureLoader(PtexTexture *ptex,
int maxNumPages,
int maxLevels = -1,
size_t targetMemory = 0,
bool seamlessMipmap = true,
bool padAlpha = false);
~PtexMipmapTextureLoader();
const unsigned char * GetLayoutBuffer() const {
return _layoutBuffer;
}
const unsigned char * GetTexelBuffer() const {
return _texelBuffer;
}
int GetNumFaces() const {
return (int)_blocks.size();
}
int GetNumPages() const {
return (int)_pages.size();
}
int GetPageWidth() const {
return _pageWidth;
}
int GetPageHeight() const {
return _pageHeight;
}
size_t GetMemoryUsage() const {
return _memoryUsage;
}
/*
block : atomic texture unit
XXX: face of 128x128 or more (64kb~) texels should be considered separately
using ARB_sparse_texture...?
. : per-face texels for each mipmap level
x : guttering pixel
xxxxxxxxxxxxxx
x........xx..x 2x2
x........xx..x
x........xxxxx
x..8x8...xxxxxxx
x........xx....x
x........xx....x 4x4
x........xx....x
x........xx....x
xxxxxxxxxxxxxxxx
For each face (w*h), texels with guttering and mipmap is stored into
(w+2+w/2+2)*(h+2) area as above.
*/
/*
Ptex loader
Texels buffer : the packed texels
*/
private:
struct Block {
int index; // ptex index
int nMipmaps;
uint16_t u, v; // top-left texel offset
uint16_t width, height; // texel dimension (includes mipmap)
uint16_t adjSizeDiffs; // maximum tile size difference around each vertices
int8_t ulog2, vlog2; // texel dimension log2 (original tile)
void Generate(PtexMipmapTextureLoader *loader, PtexTexture *ptex,
unsigned char *destination,
int bpp, int width, int maxLevels);
void SetSize(unsigned char ulog2_, unsigned char vlog2_, bool mipmap);
int GetNumTexels() const {
return width*height;
}
void guttering(PtexMipmapTextureLoader *loader, PtexTexture *ptex,
int level, int width, int height,
unsigned char *pptr, int bpp, int stride);
static bool sort(const Block *a, const Block *b) {
return (a->height > b->height) ||
((a->height == b->height) && (a->width > b->width));
}
};
struct Page;
class CornerIterator;
void generateBuffers();
void optimizePacking(int maxNumPages, size_t targetMemory);
int getLevelDiff(int face, int edge);
bool getCornerPixel(float *resultPixel, int numchannels,
int face, int edge, int8_t res);
void sampleNeighbor(unsigned char *border,
int face, int edge, int length, int bpp);
int resampleBorder(int face, int edgeId, unsigned char *result,
int dstLength, int bpp,
float srcStart = 0.0f, float srcEnd = 1.0f);
void addAlphaChannel();
std::vector<Block> _blocks;
std::vector<Page *> _pages;
PtexTexture *_ptex;
int _maxLevels;
int _bpp;
int _pageWidth, _pageHeight;
unsigned char *_texelBuffer;
unsigned char *_layoutBuffer;
size_t _memoryUsage;
};
#endif // OPENSUBDIV_EXAMPLES_PTEX_MIPMAP_TEXTURE_LOADER_H

View File

@@ -0,0 +1,53 @@
//
// Copyright 2015 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#ifndef OPENSUBDIV_EXAMPLES_SHADER_CACHE_H
#define OPENSUBDIV_EXAMPLES_SHADER_CACHE_H
#include <map>
template <typename DESC_TYPE, typename CONFIG_TYPE>
class ShaderCacheT {
public:
typedef DESC_TYPE DescType;
typedef CONFIG_TYPE ConfigType;
typedef std::map<DescType, ConfigType *> ConfigMap;
virtual ~ShaderCacheT() {
Reset();
}
void Reset() {
for (typename ConfigMap::iterator it = _configMap.begin();
it != _configMap.end(); ++it) {
delete it->second;
}
_configMap.clear();
}
// fetch shader config
ConfigType * GetDrawConfig(DescType const & desc) {
typename ConfigMap::iterator it = _configMap.find(desc);
if (it != _configMap.end()) {
return it->second;
} else {
ConfigType * config = CreateDrawConfig(desc);
if (config) {
_configMap[desc] = config;
}
return config;
}
}
virtual ConfigType *CreateDrawConfig(DescType const &desc) = 0;
private:
ConfigMap _configMap;
};
#endif // OPENSUBDIV_EXAMPLES_SHADER_CACHE_H

View File

@@ -0,0 +1,269 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#ifndef SIMPLE_MATH_H
#define SIMPLE_MATH_H
#include <cmath>
inline void
cross(float *n, const float *v1, const float *v2) {
n[0] = v1[1]*v2[2]-v1[2]*v2[1];
n[1] = v1[2]*v2[0]-v1[0]*v2[2];
n[2] = v1[0]*v2[1]-v1[1]*v2[0];
}
inline void
cross(float *n, const float *p0, const float *p1, const float *p2) {
float a[3] = { p1[0]-p0[0], p1[1]-p0[1], p1[2]-p0[2] };
float b[3] = { p2[0]-p0[0], p2[1]-p0[1], p2[2]-p0[2] };
n[0] = a[1]*b[2]-a[2]*b[1];
n[1] = a[2]*b[0]-a[0]*b[2];
n[2] = a[0]*b[1]-a[1]*b[0];
float rn = 1.0f/sqrtf(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]);
n[0] *= rn;
n[1] *= rn;
n[2] *= rn;
}
inline void
normalize(float * p) {
float dist = sqrtf( p[0]*p[0] + p[1]*p[1] + p[2]*p[2] );
p[0]/=dist;
p[1]/=dist;
p[2]/=dist;
}
inline void
multMatrix(float *d, const float *a, const float *b) {
for (int i=0; i<4; ++i)
{
for (int j=0; j<4; ++j)
{
d[i*4 + j] =
a[i*4 + 0] * b[0*4 + j] +
a[i*4 + 1] * b[1*4 + j] +
a[i*4 + 2] * b[2*4 + j] +
a[i*4 + 3] * b[3*4 + j];
}
}
}
inline void
inverseMatrix(float *d, const float *m) {
d[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];
d[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];
d[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];
d[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];
d[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];
d[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];
d[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];
d[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];
d[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];
d[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];
d[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];
d[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];
d[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];
d[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];
d[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];
d[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];
float det = m[0] * d[0] + m[1] * d[4] + m[2] * d[8] + m[3] * d[12];
if (det == 0.0f) return;
det = 1.0f / det;
for (int i = 0; i < 16; i++)
d[i] = d[i] * det;
}
inline void
perspective(float *m, float fovy, float aspect, float znear, float zfar)
{
float r = 2 * (float)M_PI * fovy / 360.0F;
float t = 1.0f / tanf(r*0.5f);
m[0] = t/aspect;
m[1] = m[2] = m[3] = 0.0;
m[4] = 0.0;
m[5] = t;
m[6] = m[7] = 0.0;
m[8] = m[9] = 0.0;
m[10] = (zfar + znear) / (znear - zfar);
m[11] = -1;
m[12] = m[13] = 0.0;
m[14] = (2*zfar*znear)/(znear - zfar);
m[15] = 0.0;
}
inline void
identity(float *m)
{
m[0] = 1; m[1] = 0; m[2] = 0; m[3] = 0;
m[4] = 0; m[5] = 1; m[6] = 0; m[7] = 0;
m[8] = 0; m[9] = 0; m[10] = 1; m[11] = 0;
m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1;
}
inline void
translate(float *m, float x, float y, float z)
{
float t[16];
identity(t);
t[12] = x;
t[13] = y;
t[14] = z;
float o[16];
for(int i = 0; i < 16; i++) o[i] = m[i];
multMatrix(m, t, o);
}
inline void
ortho(float *m, float left, float top, float right, float bottom)
{
identity(m);
m[0] = 2.0f / (right - left);
m[5] = 2.0f / (top - bottom);
m[10] = -1;
m[12] = -(right+left)/(right-left);
m[13] = -(top+bottom)/(top-bottom);
}
inline void
rotate(float *m, float angle, float x, float y, float z)
{
float r = 2 * (float) M_PI * angle/360.0f;
float c = cosf(r);
float s = sinf(r);
float t[16];
t[0] = x*x*(1-c)+c;
t[1] = y*x*(1-c)+z*s;
t[2] = x*z*(1-c)-y*s;
t[3] = 0;
t[4] = x*y*(1-c)-z*s;
t[5] = y*y*(1-c)+c;
t[6] = y*z*(1-c)+x*s;
t[7] = 0;
t[8] = x*z*(1-c)+y*s;
t[9] = y*z*(1-c)-x*s;
t[10] = z*z*(1-c)+c;
t[11] = 0;
t[12] = t[13] = t[14] = 0;
t[15] = 1;
float o[16];
for(int i = 0; i < 16; i++) o[i] = m[i];
multMatrix(m, t, o);
}
inline void
scale(float *m, float sx, float sy, float sz)
{
float t[16];
identity(t);
t[0] = sx;
t[5] = sy;
t[10] = sz;
float o[16];
for(int i = 0; i < 16; i++) o[i] = m[i];
multMatrix(m, t, o);
}
inline void
transpose(float *m)
{
std::swap(m[1], m[4]);
std::swap(m[2], m[8]);
std::swap(m[3], m[12]);
std::swap(m[6], m[9]);
std::swap(m[7], m[13]);
std::swap(m[11],m[14]);
}
inline void
apply(float *v, const float *m)
{
float r[4];
r[0] = v[0] * m[0] + v[1] * m[4] + v[2] * m[8] + v[3] * m[12];
r[1] = v[0] * m[1] + v[1] * m[5] + v[2] * m[9] + v[3] * m[13];
r[2] = v[0] * m[2] + v[1] * m[6] + v[2] * m[10] + v[3] * m[14];
r[3] = v[0] * m[3] + v[1] * m[7] + v[2] * m[11] + v[3] * m[15];
v[0] = r[0];
v[1] = r[1];
v[2] = r[2];
v[3] = r[3];
}
inline void
pickMatrix(float *m, float x, float y, float width, float height, const int *viewport)
{
float sx, sy;
float tx, ty;
sx = viewport[2] / width;
sy = viewport[3] / height;
tx = (viewport[2] + 2.0f * (viewport[0] - x)) / width;
ty = (viewport[3] + 2.0f * (viewport[1] - y)) / height;
identity(m);
m[0] = sx;
m[5] = sy;
m[12] = tx;
m[13] = ty;
}
#endif // SIMPLE_MATH_H

View File

@@ -0,0 +1,697 @@
/* stb_image_write - v0.97 - public domain - http://nothings.org/stb/stb_image_write.h
writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010
no warranty implied; use at your own risk
Before #including,
#define STB_IMAGE_WRITE_IMPLEMENTATION
in the file that you want to have the implementation.
Will probably not work correctly with strict-aliasing optimizations.
ABOUT:
This header file is a library for writing images to C stdio. It could be
adapted to write to memory or a general streaming interface; let me know.
The PNG output is not optimal; it is 20-50% larger than the file
written by a decent optimizing implementation. This library is designed
for source code compactness and simplicity, not optimal image file size
or run-time performance.
USAGE:
There are four functions, one for each image file format:
int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_hdr(char const *filename, int w, int h, int comp, const void *data);
Each function returns 0 on failure and non-0 on success.
The functions create an image file defined by the parameters. The image
is a rectangle of pixels stored from left-to-right, top-to-bottom.
Each pixel contains 'comp' channels of data stored interleaved with 8-bits
per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is
monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall.
The *data pointer points to the first byte of the top-left-most pixel.
For PNG, "stride_in_bytes" is the distance in bytes from the first byte of
a row of pixels to the first byte of the next row of pixels.
PNG creates output files with the same number of components as the input.
The BMP format expands Y to RGB in the file format and does not
output alpha.
PNG supports writing rectangles of data even when the bytes storing rows of
data are not consecutive in memory (e.g. sub-rectangles of a larger image),
by supplying the stride between the beginning of adjacent rows. The other
formats do not. (Thus you cannot write a native-format BMP through the BMP
writer, both because it is in BGR order and because it may have padding
at the end of the line.)
HDR expects linear float data. Since the format is always 32-bit rgb(e)
data, alpha (if provided) is discarded, and for monochrome data it is
replicated across all three channels.
CREDITS:
PNG/BMP/TGA
Sean Barrett
HDR
Baldur Karlsson
TGA monochrome:
Jean-Sebastien Guay
Bugfixes:
Chribba@github
*/
#ifndef INCLUDE_STB_IMAGE_WRITE_H
#define INCLUDE_STB_IMAGE_WRITE_H
#ifdef __cplusplus
extern "C" {
#endif
extern int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
extern int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
extern int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
extern int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
#ifdef __cplusplus
}
#endif
#endif//INCLUDE_STB_IMAGE_WRITE_H
#ifdef STB_IMAGE_WRITE_IMPLEMENTATION
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <math.h>
typedef unsigned int stbiw_uint32;
typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
static void writefv(FILE *f, const char *fmt, va_list v)
{
while (*fmt) {
switch (*fmt++) {
case ' ': break;
case '1': { unsigned char x = (unsigned char) va_arg(v, int); fputc(x,f); break; }
case '2': { int x = va_arg(v,int); unsigned char b[2];
b[0] = (unsigned char) x; b[1] = (unsigned char) (x>>8);
fwrite(b,2,1,f); break; }
case '4': { stbiw_uint32 x = va_arg(v,int); unsigned char b[4];
b[0]=(unsigned char)x; b[1]=(unsigned char)(x>>8);
b[2]=(unsigned char)(x>>16); b[3]=(unsigned char)(x>>24);
fwrite(b,4,1,f); break; }
default:
assert(0);
return;
}
}
}
static void write3(FILE *f, unsigned char a, unsigned char b, unsigned char c)
{
unsigned char arr[3];
arr[0] = a, arr[1] = b, arr[2] = c;
fwrite(arr, 3, 1, f);
}
static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono)
{
unsigned char bg[3] = { 255, 0, 255}, px[3];
stbiw_uint32 zero = 0;
int i,j,k, j_end;
if (y <= 0)
return;
if (vdir < 0)
j_end = -1, j = y-1;
else
j_end = y, j = 0;
for (; j != j_end; j += vdir) {
for (i=0; i < x; ++i) {
unsigned char *d = (unsigned char *) data + (j*x+i)*comp;
if (write_alpha < 0)
fwrite(&d[comp-1], 1, 1, f);
switch (comp) {
case 1: fwrite(d, 1, 1, f);
break;
case 2: if (expand_mono)
write3(f, d[0],d[0],d[0]); // monochrome bmp
else
fwrite(d, 1, 1, f); // monochrome TGA
break;
case 4:
if (!write_alpha) {
// composite against pink background
for (k=0; k < 3; ++k)
px[k] = bg[k] + ((d[k] - bg[k]) * d[3])/255;
write3(f, px[1-rgb_dir],px[1],px[1+rgb_dir]);
break;
}
/* FALLTHROUGH */
case 3:
write3(f, d[1-rgb_dir],d[1],d[1+rgb_dir]);
break;
}
if (write_alpha > 0)
fwrite(&d[comp-1], 1, 1, f);
}
fwrite(&zero,scanline_pad,1,f);
}
}
static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...)
{
FILE *f;
if (y < 0 || x < 0) return 0;
f = fopen(filename, "wb");
if (f) {
va_list v;
va_start(v, fmt);
writefv(f, fmt, v);
va_end(v);
write_pixels(f,rgb_dir,vdir,x,y,comp,data,alpha,pad,expand_mono);
fclose(f);
}
return f != NULL;
}
int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
{
int pad = (-x*3) & 3;
return outfile(filename,-1,-1,x,y,comp,1,(void *) data,0,pad,
"11 4 22 4" "4 44 22 444444",
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
}
int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
{
int has_alpha = (comp == 2 || comp == 4);
int colorbytes = has_alpha ? comp-1 : comp;
int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3
return outfile(filename, -1,-1, x, y, comp, 0, (void *) data, has_alpha, 0,
"111 221 2222 11", 0,0,format, 0,0,0, 0,0,x,y, (colorbytes+has_alpha)*8, has_alpha*8);
}
// *************************************************************************************************
// Radiance RGBE HDR writer
// by Baldur Karlsson
#define stbiw__max(a, b) ((a) > (b) ? (a) : (b))
void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
{
int exponent;
float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2]));
if (maxcomp < 1e-32) {
rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
} else {
float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp;
rgbe[0] = (unsigned char)(linear[0] * normalize);
rgbe[1] = (unsigned char)(linear[1] * normalize);
rgbe[2] = (unsigned char)(linear[2] * normalize);
rgbe[3] = (unsigned char)(exponent + 128);
}
}
void stbiw__write_run_data(FILE *f, int length, unsigned char databyte)
{
unsigned char lengthbyte = (unsigned char) (length+128);
assert(length+128 <= 255);
fwrite(&lengthbyte, 1, 1, f);
fwrite(&databyte, 1, 1, f);
}
void stbiw__write_dump_data(FILE *f, int length, unsigned char *data)
{
unsigned char lengthbyte = (unsigned char )(length & 0xff);
assert(length <= 128); // inconsistent with spec but consistent with official code
fwrite(&lengthbyte, 1, 1, f);
fwrite(data, length, 1, f);
}
void stbiw__write_hdr_scanline(FILE *f, int width, int comp, unsigned char *scratch, const float *scanline)
{
unsigned char scanlineheader[4] = { 2, 2, 0, 0 };
unsigned char rgbe[4];
float linear[3] = {0.0, 0.0, 0.0};
int x;
scanlineheader[2] = (width&0xff00)>>8;
scanlineheader[3] = (width&0x00ff);
/* skip RLE for images too small or large */
if (width < 8 || width >= 32768) {
for (x=0; x < width; x++) {
switch (comp) {
case 4: /* fallthrough */
case 3: linear[2] = scanline[x*comp + 2];
linear[1] = scanline[x*comp + 1];
linear[0] = scanline[x*comp + 0];
break;
case 2: /* fallthrough */
case 1: linear[0] = linear[1] = linear[2] = scanline[x*comp + 0];
break;
}
stbiw__linear_to_rgbe(rgbe, linear);
fwrite(rgbe, 4, 1, f);
}
} else {
int c,r;
/* encode into scratch buffer */
for (x=0; x < width; x++) {
switch(comp) {
case 4: /* fallthrough */
case 3: linear[2] = scanline[x*comp + 2];
linear[1] = scanline[x*comp + 1];
linear[0] = scanline[x*comp + 0];
break;
case 2: /* fallthrough */
case 1: linear[0] = linear[1] = linear[2] = scanline[x*comp + 0];
break;
}
stbiw__linear_to_rgbe(rgbe, linear);
scratch[x + width*0] = rgbe[0];
scratch[x + width*1] = rgbe[1];
scratch[x + width*2] = rgbe[2];
scratch[x + width*3] = rgbe[3];
}
fwrite(scanlineheader, 4, 1, f);
/* RLE each component separately */
for (c=0; c < 4; c++) {
unsigned char *comp = &scratch[width*c];
x = 0;
while (x < width) {
// find first run
r = x;
while (r+2 < width) {
if (comp[r] == comp[r+1] && comp[r] == comp[r+2])
break;
++r;
}
if (r+2 >= width)
r = width;
// dump up to first run
while (x < r) {
int len = r-x;
if (len > 128) len = 128;
stbiw__write_dump_data(f, len, &comp[x]);
x += len;
}
// if there's a run, output it
if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd
// find next byte after run
while (r < width && comp[r] == comp[x])
++r;
// output run up to r
while (x < r) {
int len = r-x;
if (len > 127) len = 127;
stbiw__write_run_data(f, len, comp[x]);
x += len;
}
}
}
}
}
}
int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
{
int i;
FILE *f;
if (y <= 0 || x <= 0 || data == NULL) return 0;
f = fopen(filename, "wb");
if (f) {
/* Each component is stored separately. Allocate scratch space for full output scanline. */
unsigned char *scratch = (unsigned char *) malloc(x*4);
fprintf(f, "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n" );
fprintf(f, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n" , y, x);
for(i=0; i < y; i++)
stbiw__write_hdr_scanline(f, x, comp, scratch, data + comp*i*x);
free(scratch);
fclose(f);
}
return f != NULL;
}
/////////////////////////////////////////////////////////
// PNG
// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
#define stbiw__sbraw(a) ((int *) (a) - 2)
#define stbiw__sbm(a) stbiw__sbraw(a)[0]
#define stbiw__sbn(a) stbiw__sbraw(a)[1]
#define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a))
#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0)
#define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a)))
#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))
#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0)
#define stbiw__sbfree(a) ((a) ? free(stbiw__sbraw(a)),0 : 0)
static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
{
int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;
void *p = realloc(*arr ? stbiw__sbraw(*arr) : 0, itemsize * m + sizeof(int)*2);
assert(p);
if (p) {
if (!*arr) ((int *) p)[1] = 0;
*arr = (void *) ((int *) p + 2);
stbiw__sbm(*arr) = m;
}
return *arr;
}
static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
{
while (*bitcount >= 8) {
stbiw__sbpush(data, (unsigned char) *bitbuffer);
*bitbuffer >>= 8;
*bitcount -= 8;
}
return data;
}
static int stbiw__zlib_bitrev(int code, int codebits)
{
int res=0;
while (codebits--) {
res = (res << 1) | (code & 1);
code >>= 1;
}
return res;
}
static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit)
{
int i;
for (i=0; i < limit && i < 258; ++i)
if (a[i] != b[i]) break;
return i;
}
static unsigned int stbiw__zhash(unsigned char *data)
{
stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
return hash;
}
#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount))
#define stbiw__zlib_add(code,codebits) \
(bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush())
#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c)
// default huffman tables
#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8)
#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9)
#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7)
#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8)
#define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n))
#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n))
#define stbiw__ZHASH 16384
unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
{
static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 };
static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 };
static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 };
static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 };
unsigned int bitbuf=0;
int i,j, bitcount=0;
unsigned char *out = NULL;
unsigned char **hash_table[stbiw__ZHASH]; // 64KB on the stack!
if (quality < 5) quality = 5;
stbiw__sbpush(out, 0x78); // DEFLATE 32K window
stbiw__sbpush(out, 0x5e); // FLEVEL = 1
stbiw__zlib_add(1,1); // BFINAL = 1
stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman
for (i=0; i < stbiw__ZHASH; ++i)
hash_table[i] = NULL;
i=0;
while (i < data_len-3) {
// hash next 3 bytes of data to be compressed
int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3;
unsigned char *bestloc = 0;
unsigned char **hlist = hash_table[h];
int n = stbiw__sbcount(hlist);
for (j=0; j < n; ++j) {
if (hlist[j]-data > i-32768) { // if entry lies within window
int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i);
if (d >= best) best=d,bestloc=hlist[j];
}
}
// when hash table entry is too long, delete half the entries
if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) {
memcpy(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
stbiw__sbn(hash_table[h]) = quality;
}
stbiw__sbpush(hash_table[h],data+i);
if (bestloc) {
// "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal
h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1);
hlist = hash_table[h];
n = stbiw__sbcount(hlist);
for (j=0; j < n; ++j) {
if (hlist[j]-data > i-32767) {
int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1);
if (e > best) { // if next match is better, bail on current match
bestloc = NULL;
break;
}
}
}
}
if (bestloc) {
int d = (int) (data+i - bestloc); // distance back
assert(d <= 32767 && best <= 258);
for (j=0; best > lengthc[j+1]-1; ++j);
stbiw__zlib_huff(j+257);
if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);
for (j=0; d > distc[j+1]-1; ++j);
stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5);
if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]);
i += best;
} else {
stbiw__zlib_huffb(data[i]);
++i;
}
}
// write out final bytes
for (;i < data_len; ++i)
stbiw__zlib_huffb(data[i]);
stbiw__zlib_huff(256); // end of block
// pad with 0 bits to byte boundary
while (bitcount)
stbiw__zlib_add(0,1);
for (i=0; i < stbiw__ZHASH; ++i)
(void) stbiw__sbfree(hash_table[i]);
{
// compute adler32 on input
unsigned int i=0, s1=1, s2=0, blocklen = data_len % 5552;
int j=0;
while (j < data_len) {
for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1;
s1 %= 65521, s2 %= 65521;
j += blocklen;
blocklen = 5552;
}
stbiw__sbpush(out, (unsigned char) (s2 >> 8));
stbiw__sbpush(out, (unsigned char) s2);
stbiw__sbpush(out, (unsigned char) (s1 >> 8));
stbiw__sbpush(out, (unsigned char) s1);
}
*out_len = stbiw__sbn(out);
// make returned pointer freeable
memmove(stbiw__sbraw(out), out, *out_len);
return (unsigned char *) stbiw__sbraw(out);
}
unsigned int stbiw__crc32(unsigned char *buffer, int len)
{
static unsigned int crc_table[256];
unsigned int crc = ~0u;
int i,j;
if (crc_table[1] == 0)
for(i=0; i < 256; i++)
for (crc_table[i]=i, j=0; j < 8; ++j)
crc_table[i] = (crc_table[i] >> 1) ^ (crc_table[i] & 1 ? 0xedb88320 : 0);
for (i=0; i < len; ++i)
crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
return ~crc;
}
#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=(unsigned char)(a),(o)[1]=(unsigned char)(b),(o)[2]=(unsigned char)(c),(o)[3]=(unsigned char)(d),(o)+=4)
#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3])
static void stbiw__wpcrc(unsigned char **data, int len)
{
unsigned int crc = stbiw__crc32(*data - len - 4, len+4);
stbiw__wp32(*data, crc);
}
static unsigned char stbiw__paeth(int a, int b, int c)
{
int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);
if (pa <= pb && pa <= pc) return (unsigned char) a;
if (pb <= pc) return (unsigned char) b;
return (unsigned char) c;
}
unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
{
int ctype[5] = { -1, 0, 4, 2, 6 };
unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
unsigned char *out,*o, *filt, *zlib;
signed char *line_buffer;
int i,j,k,p,zlen;
if (stride_bytes == 0)
stride_bytes = x * n;
filt = (unsigned char *) malloc((x*n+1) * y); if (!filt) return 0;
line_buffer = (signed char *) malloc(x * n); if (!line_buffer) { free(filt); return 0; }
for (j=0; j < y; ++j) {
static int mapping[] = { 0,1,2,3,4 };
static int firstmap[] = { 0,1,0,5,6 };
int *mymap = j ? mapping : firstmap;
int best = 0, bestval = 0x7fffffff;
for (p=0; p < 2; ++p) {
for (k= p?best:0; k < 5; ++k) {
int type = mymap[k],est=0;
unsigned char *z = pixels + stride_bytes*j;
for (i=0; i < n; ++i)
switch (type) {
case 0: line_buffer[i] = z[i]; break;
case 1: line_buffer[i] = z[i]; break;
case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break;
case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-stride_bytes],0)); break;
case 5: line_buffer[i] = z[i]; break;
case 6: line_buffer[i] = z[i]; break;
}
for (i=n; i < x*n; ++i) {
switch (type) {
case 0: line_buffer[i] = z[i]; break;
case 1: line_buffer[i] = z[i] - z[i-n]; break;
case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break;
case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break;
case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break;
case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break;
}
}
if (p) break;
for (i=0; i < x*n; ++i)
est += abs((signed char) line_buffer[i]);
if (est < bestval) { bestval = est; best = k; }
}
}
// when we get here, best contains the filter type, and line_buffer contains the data
filt[j*(x*n+1)] = (unsigned char) best;
memcpy(filt+j*(x*n+1)+1, line_buffer, x*n);
}
free(line_buffer);
zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory
free(filt);
if (!zlib) return 0;
// each tag requires 12 bytes of overhead
out = (unsigned char *) malloc(8 + 12+13 + 12+zlen + 12);
if (!out) return 0;
*out_len = 8 + 12+13 + 12+zlen + 12;
o=out;
memcpy(o,sig,8); o+= 8;
stbiw__wp32(o, 13); // header length
stbiw__wptag(o, "IHDR");
stbiw__wp32(o, x);
stbiw__wp32(o, y);
*o++ = 8;
*o++ = (unsigned char) ctype[n];
*o++ = 0;
*o++ = 0;
*o++ = 0;
stbiw__wpcrc(&o,13);
stbiw__wp32(o, zlen);
stbiw__wptag(o, "IDAT");
memcpy(o, zlib, zlen); o += zlen; free(zlib);
stbiw__wpcrc(&o, zlen);
stbiw__wp32(o,0);
stbiw__wptag(o, "IEND");
stbiw__wpcrc(&o,0);
assert(o == out + *out_len);
return out;
}
int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
{
FILE *f;
int len;
unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
if (!png) return 0;
f = fopen(filename, "wb");
if (!f) { free(png); return 0; }
fwrite(png, 1, len, f);
fclose(f);
free(png);
return 1;
}
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
/* Revision history
0.97 (2015-01-18)
fixed HDR asserts, rewrote HDR rle logic
0.96 (2015-01-17)
add HDR output
fix monochrome BMP
0.95 (2014-08-17)
add monochrome TGA output
0.94 (2014-05-31)
rename private functions to avoid conflicts with stb_image.h
0.93 (2014-05-27)
warning fixes
0.92 (2010-08-01)
casts to unsigned char to fix warnings
0.91 (2010-07-17)
first public release
0.90 first internal release
*/

View File

@@ -0,0 +1,90 @@
//
// Copyright 2013 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#ifndef STOPWATCH_H
#define STOPWATCH_H
#if (_WIN32)
#include <windows.h>
#else
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#endif
class Stopwatch {
public:
#ifndef _WIN32
Stopwatch() : _totalElapsed(0) { }
void Start() {
struct timeval l_rtime;
gettimeofday(&l_rtime,0);
_elapsed = (double)l_rtime.tv_sec + (double)l_rtime.tv_usec/1000000.0;
}
void Stop() {
struct timeval l_rtime;
gettimeofday(&l_rtime,0);
_elapsed = ((double)l_rtime.tv_sec + (double)l_rtime.tv_usec/1000000.0)
- _elapsed;
_totalElapsed += _elapsed;
}
double GetElapsed() const {
return _elapsed;
}
double GetTotalElapsed() const {
return _totalElapsed;
}
#else
Stopwatch() : _totalElapsed(0) {
QueryPerformanceFrequency(&_frequency);
}
void Start()
{
QueryPerformanceCounter(&_time);
}
void Stop()
{
LARGE_INTEGER currentTime;
QueryPerformanceCounter(&currentTime);
_elapsed = currentTime.QuadPart - _time.QuadPart;
_totalElapsed+=_elapsed;
}
double GetElapsed() const {
return (double) _elapsed / _frequency.QuadPart;
}
double GetTotalElapsed() const {
return (double) _totalElapsed / _frequency.QuadPart;
}
#endif
private:
#ifndef _WIN32
double _elapsed;
double _totalElapsed;
#else
LARGE_INTEGER _time;
LARGE_INTEGER _frequency;
__int64 _elapsed;
__int64 _totalElapsed;
#endif
};
#endif /* STOPWATCH_H */

View File

@@ -0,0 +1,75 @@
//
// Copyright 2019 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#include "../common/viewerArgsUtils.h"
#include "../../regression/common/arg_utils.h"
#include "../../regression/common/shape_utils.h"
#include "../common/objAnim.h"
#include <stdio.h>
namespace ViewerArgsUtils {
const ObjAnim *
PopulateAnimShapes(const ArgOptions &args,
std::vector<ShapeDesc> *defaultShapes)
{
if (args.GetObjFiles().empty())
return NULL;
const ObjAnim *objAnim = ObjAnim::Create(args.GetObjFiles(),
args.GetDefaultScheme());
if (objAnim && defaultShapes) {
defaultShapes->push_back(ShapeDesc(args.GetObjFiles()[0], "",
args.GetDefaultScheme()));
}
return objAnim;
}
void
PopulateShapes(const ArgOptions &args,
std::vector<ShapeDesc> *defaultShapes)
{
if (defaultShapes) {
args.AppendObjShapes(*defaultShapes, true /* print warnings */);
}
}
void
PopulateShapesOrAnimShapes(
const ArgOptions &args,
std::vector<ShapeDesc> *defaultShapes,
const ObjAnim **objAnim)
{
if (!defaultShapes)
return;
if (args.GetObjFiles().empty())
return;
if (args.GetObjsAreAnim()) {
if (!objAnim) {
printf("Warning: animations of objs are unsupported in this "
"viewer.\n");
return;
}
*objAnim = PopulateAnimShapes(args, defaultShapes);
} else {
PopulateShapes(args, defaultShapes);
}
}
}

View File

@@ -0,0 +1,41 @@
//
// Copyright 2019 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://opensubdiv.org/license.
//
#ifndef VIEWER_ARGS_UTILS_H
#define VIEWER_ARGS_UTILS_H
#include <vector>
class ArgOptions;
struct ShapeDesc;
class ObjAnim;
namespace ViewerArgsUtils {
// From the list of obj files in args, populates the
// defaultShapes vector, treating the objs as an animated series, returning
// an ObjAnim object.
const ObjAnim *PopulateAnimShapes(const ArgOptions &args,
std::vector<ShapeDesc> *defaultShapes = 0);
// From the list of obj files in args, populates the
// defaultShapes vector.
void PopulateShapes(const ArgOptions &args,
std::vector<ShapeDesc> *defaultShapes);
// From the list of obj files in args, populates the
// defaultShapes vector and the objAnim object if animated objs have
// been specified in args.
void PopulateShapesOrAnimShapes(
const ArgOptions &args,
std::vector<ShapeDesc> *defaultShapes,
const ObjAnim **objAnim);
} // namespace ViewerArgsUtils
#endif // VIEWER_ARGS_UTILS_H