v0.8.1.0 Release
v0.8.1.0 Release
This commit is contained in:
@@ -110,12 +110,21 @@ BodyEngine::Err BodyEngine::createKeyPointDetectionFeature(const char* modelPath
|
||||
nvErr = NvAR_SetU32(keyPointDetectHandle, NvAR_Parameter_Config(Temporal), bStabilizeBody);
|
||||
BAIL_IF_CVERR(nvErr, err, BodyEngine::Err::errParameter);
|
||||
|
||||
nvErr = NvAR_SetF32(keyPointDetectHandle, NvAR_Parameter_Config(FocalLength), bFocalLength);
|
||||
BAIL_IF_CVERR(nvErr, err, BodyEngine::Err::errParameter);
|
||||
|
||||
nvErr = NvAR_SetF32(keyPointDetectHandle, NvAR_Parameter_Config(UseCudaGraph), bUseCudaGraph);
|
||||
BAIL_IF_CVERR(nvErr, err, BodyEngine::Err::errParameter);
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
nvErr = NvAR_SetF32(keyPointDetectHandle, NvAR_Parameter_Config(TrackPeople), bEnablePeopleTracking);
|
||||
BAIL_IF_CVERR(nvErr, err, BodyEngine::Err::errParameter);
|
||||
|
||||
nvErr = NvAR_SetU32(keyPointDetectHandle, NvAR_Parameter_Config(ShadowTrackingAge), shadowTrackingAge);
|
||||
BAIL_IF_CVERR(nvErr, err, BodyEngine::Err::errParameter);
|
||||
|
||||
nvErr = NvAR_SetU32(keyPointDetectHandle, NvAR_Parameter_Config(ProbationAge), probationAge);
|
||||
BAIL_IF_CVERR(nvErr, err, BodyEngine::Err::errParameter);
|
||||
|
||||
nvErr = NvAR_SetU32(keyPointDetectHandle, NvAR_Parameter_Config(MaxTargetsTracked), maxTargetsTracked);
|
||||
BAIL_IF_CVERR(nvErr, err, BodyEngine::Err::errParameter);
|
||||
#endif
|
||||
nvErr = NvAR_Load(keyPointDetectHandle);
|
||||
BAIL_IF_CVERR(nvErr, err, BodyEngine::Err::errInitialization);
|
||||
|
||||
@@ -176,18 +185,23 @@ BodyEngine::Err BodyEngine::initKeyPointDetectionIOParams(NvCVImage* inBuf) {
|
||||
NvCV_Status nvErr = NVCV_SUCCESS;
|
||||
BodyEngine::Err err = BodyEngine::Err::errNone;
|
||||
uint output_bbox_size;
|
||||
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
uint output_tracking_bbox_size;
|
||||
#endif
|
||||
nvErr = NvAR_SetObject(keyPointDetectHandle, NvAR_Parameter_Input(Image), inBuf, sizeof(NvCVImage));
|
||||
BAIL_IF_CVERR(nvErr, err, BodyEngine::Err::errParameter);
|
||||
|
||||
nvErr = NvAR_SetF32(keyPointDetectHandle, NvAR_Parameter_Input(FocalLength), bFocalLength);
|
||||
BAIL_IF_CVERR(nvErr, err, BodyEngine::Err::errParameter);
|
||||
|
||||
nvErr = NvAR_GetU32(keyPointDetectHandle, NvAR_Parameter_Config(NumKeyPoints), &numKeyPoints);
|
||||
BAIL_IF_CVERR(nvErr, err, BodyEngine::Err::errParameter);
|
||||
|
||||
keypoints.assign(batchSize * numKeyPoints, {0.f, 0.f});
|
||||
keypoints3D.assign(batchSize * numKeyPoints, {0.f, 0.f, 0.f});
|
||||
jointAngles.assign(batchSize * numKeyPoints, {0.f, 0.f, 0.f, 1.f});
|
||||
keypoints.assign(batchSize * numKeyPoints, { 0.f, 0.f });
|
||||
keypoints3D.assign(batchSize * numKeyPoints, { 0.f, 0.f, 0.f });
|
||||
jointAngles.assign(batchSize * numKeyPoints, { 0.f, 0.f, 0.f, 1.f });
|
||||
keypoints_confidence.assign(batchSize * numKeyPoints, 0.f);
|
||||
referencePose.assign(numKeyPoints, {0.f, 0.f, 0.f});
|
||||
referencePose.assign(numKeyPoints, { 0.f, 0.f, 0.f });
|
||||
|
||||
const void* pReferencePose;
|
||||
nvErr = NvAR_GetObject(keyPointDetectHandle, NvAR_Parameter_Config(ReferencePose), &pReferencePose,
|
||||
@@ -208,19 +222,47 @@ BodyEngine::Err BodyEngine::initKeyPointDetectionIOParams(NvCVImage* inBuf) {
|
||||
BAIL_IF_CVERR(nvErr, err, BodyEngine::Err::errParameter);
|
||||
|
||||
nvErr = NvAR_SetF32Array(keyPointDetectHandle, NvAR_Parameter_Output(KeyPointsConfidence),
|
||||
keypoints_confidence.data(), batchSize * numKeyPoints);
|
||||
keypoints_confidence.data(), sizeof(float));
|
||||
BAIL_IF_CVERR(nvErr, err, BodyEngine::Err::errParameter);
|
||||
|
||||
output_bbox_size = batchSize;
|
||||
if (!bStabilizeBody) output_bbox_size = 25;
|
||||
output_bbox_data.assign(output_bbox_size, {0.f, 0.f, 0.f, 0.f});
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
if (bEnablePeopleTracking) {
|
||||
output_tracking_bbox_size = maxTargetsTracked;
|
||||
output_tracking_bbox_data.assign(output_tracking_bbox_size, { 0.f, 0.f, 0.f, 0.f, 0 });
|
||||
output_tracking_bboxes.boxes = output_tracking_bbox_data.data();
|
||||
output_tracking_bboxes.max_boxes = (uint8_t)output_tracking_bbox_size;
|
||||
output_tracking_bboxes.num_boxes = 0;
|
||||
nvErr =
|
||||
NvAR_SetObject(keyPointDetectHandle, NvAR_Parameter_Output(TrackingBoundingBoxes), &output_tracking_bboxes, sizeof(NvAR_TrackingBBoxes));
|
||||
BAIL_IF_CVERR(nvErr, err, BodyEngine::Err::errParameter);
|
||||
}
|
||||
else {
|
||||
output_bbox_data.assign(25, { 0.f, 0.f, 0.f, 0.f });
|
||||
output_bbox_conf_data.assign(25, 0.f);
|
||||
output_bboxes.boxes = output_bbox_data.data();
|
||||
output_bboxes.max_boxes = (uint8_t)output_bbox_data.size();
|
||||
output_bboxes.num_boxes = 0;
|
||||
nvErr = NvAR_SetObject(keyPointDetectHandle, NvAR_Parameter_Output(BoundingBoxes), &output_bboxes, sizeof(NvAR_BBoxes));
|
||||
BAIL_IF_CVERR(nvErr, err, BodyEngine::Err::errParameter);
|
||||
|
||||
nvErr = NvAR_SetF32Array(keyPointDetectHandle, NvAR_Parameter_Output(BoundingBoxesConfidence),
|
||||
output_bbox_conf_data.data(), output_bboxes.max_boxes);
|
||||
BAIL_IF_CVERR(nvErr, err, BodyEngine::Err::errParameter);
|
||||
}
|
||||
#else
|
||||
output_bbox_data.assign(25, { 0.f, 0.f, 0.f, 0.f });
|
||||
output_bbox_conf_data.assign(25, 0.f);
|
||||
output_bboxes.boxes = output_bbox_data.data();
|
||||
output_bboxes.max_boxes = (uint8_t)output_bbox_size;
|
||||
output_bboxes.num_boxes = (uint8_t)output_bbox_size;
|
||||
nvErr =
|
||||
NvAR_SetObject(keyPointDetectHandle, NvAR_Parameter_Output(BoundingBoxes), &output_bboxes, sizeof(NvAR_BBoxes));
|
||||
output_bboxes.max_boxes = (uint8_t)output_bbox_data.size();
|
||||
output_bboxes.num_boxes = 0;
|
||||
nvErr = NvAR_SetObject(keyPointDetectHandle, NvAR_Parameter_Output(BoundingBoxes), &output_bboxes, sizeof(NvAR_BBoxes));
|
||||
BAIL_IF_CVERR(nvErr, err, BodyEngine::Err::errParameter);
|
||||
|
||||
nvErr = NvAR_SetF32Array(keyPointDetectHandle, NvAR_Parameter_Output(BoundingBoxesConfidence),
|
||||
output_bbox_conf_data.data(), output_bboxes.max_boxes);
|
||||
BAIL_IF_CVERR(nvErr, err, BodyEngine::Err::errParameter);
|
||||
#endif
|
||||
|
||||
bail:
|
||||
return err;
|
||||
}
|
||||
@@ -262,6 +304,9 @@ void BodyEngine::releaseBodyDetectionIOParams() {
|
||||
void BodyEngine::releaseKeyPointDetectionIOParams() {
|
||||
NvCVImage_Dealloc(&inputImageBuffer);
|
||||
if (!output_bbox_data.empty()) output_bbox_data.clear();
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
if (!output_tracking_bbox_data.empty()) output_tracking_bbox_data.clear();
|
||||
#endif
|
||||
if (!keypoints.empty()) keypoints.clear();
|
||||
if (!keypoints3D.empty()) keypoints3D.clear();
|
||||
if (!jointAngles.empty()) jointAngles.clear();
|
||||
@@ -338,21 +383,6 @@ void BodyEngine::enlargeAndSquarifyImageBox(float enlarge, NvAR_Rect& box, int F
|
||||
std::cout << "[bodypose] > NvAR_Run(keyPointDetectHandle): " << duration.count() << " microseconds" << std::endl;
|
||||
#endif
|
||||
|
||||
if (getAverageKeyPointsConfidence() < confidenceThreshold) {
|
||||
return NVCV_ERR_GENERAL;
|
||||
} else {
|
||||
NvAR_Point2f *pt, *endPt;
|
||||
int i = 0;
|
||||
for (endPt = (pt = getKeyPoints()) + numKeyPoints; pt != endPt; ++pt, i += 2) {
|
||||
for (int j = 1; j < batchSize; j++) {
|
||||
pt->x += pt[j * numKeyPoints].x;
|
||||
pt->y += pt[j * numKeyPoints].y;
|
||||
}
|
||||
// average batch of inferences to generate final result keypoints
|
||||
pt->x /= batchSize;
|
||||
pt->y /= batchSize;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_PERF_RUNTIME
|
||||
end = std::chrono::high_resolution_clock::now();
|
||||
duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
|
||||
@@ -367,17 +397,21 @@ NvAR_Point3f* BodyEngine::getKeyPoints3D() { return keypoints3D.data(); }
|
||||
|
||||
NvAR_Quaternion* BodyEngine::getJointAngles() { return jointAngles.data(); }
|
||||
|
||||
NvAR_BBoxes* BodyEngine::getBBoxes(){ return &output_bboxes; }
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
NvAR_TrackingBBoxes* BodyEngine::getTrackingBBoxes() { return &output_tracking_bboxes; }
|
||||
#endif
|
||||
float* BodyEngine::getKeyPointsConfidence() { return keypoints_confidence.data(); }
|
||||
|
||||
float BodyEngine::getAverageKeyPointsConfidence() {
|
||||
float average_confidence = 0.0f;
|
||||
float* keypoints_confidence_all = getKeyPointsConfidence();
|
||||
for (int i = 0; i < batchSize; i++) {
|
||||
for (unsigned int j = 0; j < numKeyPoints; j++) {
|
||||
for (int i = 0; i < output_bboxes.num_boxes; i++) {
|
||||
for (unsigned int j = 0; j < numKeyPoints; j++) {
|
||||
average_confidence += keypoints_confidence_all[i * numKeyPoints + j];
|
||||
}
|
||||
}
|
||||
average_confidence /= batchSize * numKeyPoints;
|
||||
average_confidence /= output_bboxes.num_boxes * numKeyPoints;
|
||||
return average_confidence;
|
||||
}
|
||||
|
||||
@@ -413,7 +447,7 @@ unsigned BodyEngine::acquireBodyBox(cv::Mat& src, NvAR_Rect& bodyBox, int varian
|
||||
}
|
||||
|
||||
unsigned BodyEngine::acquireBodyBoxAndKeyPoints(cv::Mat& src, NvAR_Point2f* refMarks, NvAR_Point3f* refKeyPoints3D,
|
||||
NvAR_Quaternion* refJointAngles, NvAR_Rect& bodyBox, int /*variant*/) {
|
||||
NvAR_Quaternion* refJointAngles, NvAR_BBoxes* refBodyBoxes, int /*variant*/) {
|
||||
unsigned n = 0;
|
||||
NvCVImage fxSrcChunkyCPU;
|
||||
(void)NVWrapperForCVMat(&src, &fxSrcChunkyCPU);
|
||||
@@ -426,14 +460,15 @@ unsigned BodyEngine::acquireBodyBoxAndKeyPoints(cv::Mat& src, NvAR_Point2f* refM
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
#endif
|
||||
if (findKeyPoints() != NVCV_SUCCESS) return 0;
|
||||
bodyBox = output_bboxes.boxes[0];
|
||||
memcpy(refBodyBoxes, getBBoxes(), sizeof(NvAR_BBoxes) );
|
||||
n = 1;
|
||||
#ifdef DEBUG_PERF_RUNTIME
|
||||
auto start2 = std::chrono::high_resolution_clock::now();
|
||||
#endif
|
||||
memcpy(refMarks, getKeyPoints(), sizeof(NvAR_Point2f) * numKeyPoints);
|
||||
memcpy(refKeyPoints3D, getKeyPoints3D(), sizeof(NvAR_Point3f) * numKeyPoints);
|
||||
memcpy(refJointAngles, getJointAngles(), sizeof(NvAR_Quaternion) * numKeyPoints);
|
||||
memcpy(refMarks, getKeyPoints(), sizeof(NvAR_Point2f) * numKeyPoints * batchSize);
|
||||
memcpy(refKeyPoints3D, getKeyPoints3D(), sizeof(NvAR_Point3f) * numKeyPoints * batchSize);
|
||||
memcpy(refJointAngles, getJointAngles(), sizeof(NvAR_Quaternion) * numKeyPoints * batchSize);
|
||||
|
||||
|
||||
#ifdef DEBUG_PERF_RUNTIME
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
@@ -446,13 +481,63 @@ unsigned BodyEngine::acquireBodyBoxAndKeyPoints(cv::Mat& src, NvAR_Point2f* refM
|
||||
#endif
|
||||
return n;
|
||||
}
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
unsigned BodyEngine::acquireBodyBoxAndKeyPoints(cv::Mat& src, NvAR_Point2f* refMarks, NvAR_Point3f* refKeyPoints3D,
|
||||
NvAR_Quaternion* refJointAngles, NvAR_TrackingBBoxes* refBodyBoxes, int /*variant*/) {
|
||||
unsigned n = 0;
|
||||
NvCVImage fxSrcChunkyCPU;
|
||||
(void)NVWrapperForCVMat(&src, &fxSrcChunkyCPU);
|
||||
NvCV_Status cvErr = NvCVImage_Transfer(&fxSrcChunkyCPU, &inputImageBuffer, 1.0f, stream, &tmpImage);
|
||||
|
||||
if (NVCV_SUCCESS != cvErr) {
|
||||
return n;
|
||||
}
|
||||
#ifdef DEBUG_PERF_RUNTIME
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
#endif
|
||||
if (findKeyPoints() != NVCV_SUCCESS) return 0;
|
||||
memcpy(refBodyBoxes, getTrackingBBoxes(), sizeof(NvAR_TrackingBBoxes));
|
||||
n = 1;
|
||||
#ifdef DEBUG_PERF_RUNTIME
|
||||
auto start2 = std::chrono::high_resolution_clock::now();
|
||||
#endif
|
||||
memcpy(refMarks, getKeyPoints(), sizeof(NvAR_Point2f) * numKeyPoints * batchSize);
|
||||
memcpy(refKeyPoints3D, getKeyPoints3D(), sizeof(NvAR_Point3f) * numKeyPoints * batchSize);
|
||||
memcpy(refJointAngles, getJointAngles(), sizeof(NvAR_Quaternion) * numKeyPoints * batchSize);
|
||||
|
||||
|
||||
#ifdef DEBUG_PERF_RUNTIME
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
auto duration3 = std::chrono::duration_cast<std::chrono::microseconds>(start2 - start);
|
||||
std::cout << "[bodypose] run findKeyPoints(): " << duration3.count() << " microseconds" << std::endl;
|
||||
auto duration2 = std::chrono::duration_cast<std::chrono::microseconds>(end - start2);
|
||||
std::cout << "[bodypose] keypoint copy time: " << duration2.count() << " microseconds" << std::endl;
|
||||
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
|
||||
std::cout << "[bodypose] end-to-end time: " << duration.count() << " microseconds" << std::endl;
|
||||
#endif
|
||||
return n;
|
||||
}
|
||||
#endif
|
||||
void BodyEngine::setBodyStabilization(bool _bStabilizeBody) { bStabilizeBody = _bStabilizeBody; }
|
||||
|
||||
void BodyEngine::setMode(int _mode) { nvARMode = _mode; }
|
||||
|
||||
void BodyEngine::setFocalLength(float _bFocalLength) { bFocalLength = _bFocalLength; }
|
||||
BodyEngine::Err BodyEngine::setFocalLength(float _bFocalLength) {
|
||||
bFocalLength = _bFocalLength;
|
||||
NvCV_Status nvErr = NvAR_SetF32(keyPointDetectHandle, NvAR_Parameter_Input(FocalLength), bFocalLength);
|
||||
BodyEngine::Err err = BodyEngine::Err::errNone;
|
||||
if (nvErr != NVCV_SUCCESS) err = BodyEngine::Err::errParameter;
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
void BodyEngine::useCudaGraph(bool _bUseCudaGraph) { bUseCudaGraph = _bUseCudaGraph; }
|
||||
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
void BodyEngine::enablePeopleTracking(bool _bEnablePeopleTracking, unsigned int _shadowTrackingAge, unsigned int _probationAge, unsigned int _maxTargetsTracked) {
|
||||
bEnablePeopleTracking = _bEnablePeopleTracking;
|
||||
shadowTrackingAge = _shadowTrackingAge;
|
||||
probationAge = _probationAge;
|
||||
maxTargetsTracked = _maxTargetsTracked;
|
||||
}
|
||||
#endif
|
||||
void BodyEngine::setAppMode(BodyEngine::mode _mode) { appMode = _mode; }
|
||||
|
||||
@@ -141,17 +141,28 @@ class BodyEngine {
|
||||
NvAR_Point2f* getKeyPoints();
|
||||
NvAR_Point3f* getKeyPoints3D();
|
||||
NvAR_Quaternion* getJointAngles();
|
||||
NvAR_BBoxes* getBBoxes();
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
NvAR_TrackingBBoxes* getTrackingBBoxes();
|
||||
#endif
|
||||
float* getKeyPointsConfidence();
|
||||
float getAverageKeyPointsConfidence();
|
||||
void enlargeAndSquarifyImageBox(float enlarge, NvAR_Rect& box, int FLAG_variant);
|
||||
unsigned findLargestBodyBox(NvAR_Rect& bodyBox, int variant = 0);
|
||||
unsigned acquireBodyBox(cv::Mat& src, NvAR_Rect& bodyBox, int variant = 0);
|
||||
unsigned acquireBodyBoxAndKeyPoints(cv::Mat& src, NvAR_Point2f* refMarks, NvAR_Point3f* refKeyPoints3D,
|
||||
NvAR_Quaternion* refJointAngles, NvAR_Rect& bodyBox, int variant = 0);
|
||||
NvAR_Quaternion* refJointAngles, NvAR_BBoxes* refBodyBoxes, int variant = 0);
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
unsigned acquireBodyBoxAndKeyPoints(cv::Mat& src, NvAR_Point2f* refMarks, NvAR_Point3f* refKeyPoints3D,
|
||||
NvAR_Quaternion* refJointAngles, NvAR_TrackingBBoxes* refBodyBoxes, int variant = 0);
|
||||
#endif
|
||||
void setBodyStabilization(bool);
|
||||
void setMode(int);
|
||||
void setFocalLength(float);
|
||||
BodyEngine::Err setFocalLength(float);
|
||||
void useCudaGraph(bool); // Using cuda graph improves model latency
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
void enablePeopleTracking(bool _bEnablePeopleTracking, unsigned int _shadowTrackingAge = 90, unsigned int _probationAge = 10, unsigned int _maxTargetsTracked = 30);
|
||||
#endif
|
||||
int getNumKeyPoints() { return numKeyPoints; }
|
||||
std::vector<NvAR_Point3f> getReferencePose() { return referencePose; }
|
||||
|
||||
@@ -165,6 +176,11 @@ class BodyEngine {
|
||||
std::vector<NvAR_Rect> output_bbox_data;
|
||||
std::vector<float> output_bbox_conf_data;
|
||||
NvAR_BBoxes output_bboxes{};
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
NvAR_TrackingBBoxes output_tracking_bboxes{};
|
||||
std::vector<NvAR_TrackingBBox> output_tracking_bbox_data;
|
||||
#endif
|
||||
|
||||
int batchSize;
|
||||
int nvARMode;
|
||||
std::mt19937 ran;
|
||||
@@ -178,12 +194,23 @@ class BodyEngine {
|
||||
char *bdOTAModelPath, *ldOTAModelPath;
|
||||
float bFocalLength;
|
||||
bool bUseCudaGraph;
|
||||
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
bool bEnablePeopleTracking;
|
||||
unsigned int shadowTrackingAge;
|
||||
unsigned int probationAge;
|
||||
unsigned int maxTargetsTracked;
|
||||
#endif
|
||||
BodyEngine() {
|
||||
batchSize = 1;
|
||||
nvARMode = 1;
|
||||
bStabilizeBody = true;
|
||||
bUseCudaGraph = true;
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
bEnablePeopleTracking = false;
|
||||
shadowTrackingAge = 90;
|
||||
probationAge = 10;
|
||||
maxTargetsTracked = 30;
|
||||
#endif
|
||||
bFocalLength = FOCAL_LENGTH_DEFAULT;
|
||||
confidenceThreshold = 0.f;
|
||||
appMode = keyPointDetection;
|
||||
|
||||
@@ -37,6 +37,13 @@
|
||||
#include "nvAR_defs.h"
|
||||
#include "opencv2/opencv.hpp"
|
||||
|
||||
#if CV_MAJOR_VERSION >= 4
|
||||
#define CV_CAP_PROP_FRAME_WIDTH cv::CAP_PROP_FRAME_WIDTH
|
||||
#define CV_CAP_PROP_FRAME_HEIGHT cv::CAP_PROP_FRAME_HEIGHT
|
||||
#define CV_CAP_PROP_FPS cv::CAP_PROP_FPS
|
||||
#define CV_CAP_PROP_FRAME_COUNT cv::CAP_PROP_FRAME_COUNT
|
||||
#endif
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.1415926535897932385
|
||||
#endif /* M_PI */
|
||||
@@ -62,6 +69,8 @@
|
||||
|
||||
#define DEBUG_RUNTIME
|
||||
|
||||
#define PEOPLE_TRACKING_BATCH_SIZE 8
|
||||
|
||||
/********************************************************************************
|
||||
* Command-line arguments
|
||||
********************************************************************************/
|
||||
@@ -71,7 +80,10 @@ bool FLAG_debug = false, FLAG_verbose = false, FLAG_temporal = true, FLAG_captur
|
||||
std::string FLAG_outDir, FLAG_inFile, FLAG_outFile, FLAG_modelPath, FLAG_captureCodec = "avc1",
|
||||
FLAG_camRes, FLAG_bodyModel;
|
||||
unsigned int FLAG_appMode = 1, FLAG_mode = 1, FLAG_camindex=0;
|
||||
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
bool FLAG_enablePeopleTracking = false;
|
||||
unsigned int FLAG_shadowTrackingAge = 90, FLAG_probationAge = 10, FLAG_maxTargetsTracked = 30;
|
||||
#endif
|
||||
/********************************************************************************
|
||||
* Usage
|
||||
********************************************************************************/
|
||||
@@ -95,6 +107,12 @@ static void Usage() {
|
||||
" --model_path=<path> specify the directory containing the TRT models\n"
|
||||
" --mode[=0|1] Model Mode. 0: High Quality, 1: High Performance\n"
|
||||
" --app_mode[=(0|1)] App mode. 0: Body detection, 1: Keypoint detection "
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
" --enable_people_tracking[=(0|1)] Enables people tracking "
|
||||
" --shadow_tracking_age Shadow Tracking Age after which tracking information of a person is removed. Measured in frames"
|
||||
" --probation_age Length of probationary period. Measured in frames"
|
||||
" --max_targets_tracked Maximum number of targets to be tracked "
|
||||
#endif
|
||||
"(Default).\n"
|
||||
" --benchmarks[=<pattern>] run benchmarks\n");
|
||||
}
|
||||
@@ -194,6 +212,12 @@ static int ParseMyArgs(int argc, char **argv) {
|
||||
GetFlagArgVal("mode", arg, &FLAG_mode) ||
|
||||
GetFlagArgVal("camindex", arg, &FLAG_camindex) ||
|
||||
GetFlagArgVal("use_cuda_graph", arg, &FLAG_useCudaGraph) ||
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
GetFlagArgVal("enable_people_tracking", arg, &FLAG_enablePeopleTracking) ||
|
||||
GetFlagArgVal("shadow_tracking_age", arg, &FLAG_shadowTrackingAge) ||
|
||||
GetFlagArgVal("probation_age", arg, &FLAG_probationAge) ||
|
||||
GetFlagArgVal("max_targets_tracked", arg, &FLAG_maxTargetsTracked) ||
|
||||
#endif
|
||||
GetFlagArgVal("temporal", arg, &FLAG_temporal))) {
|
||||
continue;
|
||||
} else if (GetFlagArgVal("help", arg, &help)) {
|
||||
@@ -231,10 +255,11 @@ enum {
|
||||
#if 1
|
||||
class MyTimer {
|
||||
public:
|
||||
void start() { t0 = std::chrono::high_resolution_clock::now(); } /**< Start the timer. */
|
||||
void pause() { dt = std::chrono::high_resolution_clock::now() - t0; } /**< Pause the timer. */
|
||||
void resume() { t0 = std::chrono::high_resolution_clock::now() - dt; } /**< Resume the timer. */
|
||||
void stop() { pause(); } /**< Stop the timer. */
|
||||
MyTimer() { dt = dt.zero(); } /**< Clear the duration to 0. */
|
||||
void start() { t0 = std::chrono::high_resolution_clock::now(); } /**< Start the timer. */
|
||||
void pause() { dt = std::chrono::high_resolution_clock::now() - t0; } /**< Pause the timer. */
|
||||
void resume() { t0 = std::chrono::high_resolution_clock::now() - dt; } /**< Resume the timer. */
|
||||
void stop() { pause(); } /**< Stop the timer. */
|
||||
double elapsedTimeFloat() const {
|
||||
return std::chrono::duration<double>(dt).count();
|
||||
} /**< Report the elapsed time as a float. */
|
||||
@@ -310,14 +335,23 @@ class DoApp {
|
||||
Err run();
|
||||
void drawFPS(cv::Mat &img);
|
||||
void DrawBBoxes(const cv::Mat &src, NvAR_Rect *output_bbox);
|
||||
//TODO: Look into ways of simplifying the app for these functions.
|
||||
void DrawBBoxes(const cv::Mat &src, NvAR_BBoxes *output_bbox);
|
||||
void DrawBBoxes(const cv::Mat &src, NvAR_TrackingBBoxes *output_bbox);
|
||||
void DrawKeyPointLine(const cv::Mat& src, NvAR_Point2f* keypoints, int point1, int point2, int color);
|
||||
void DrawKeyPointsAndEdges(const cv::Mat &src, NvAR_Point2f *keypoints, int numKeyPoints, NvAR_Rect* output_bbox);
|
||||
void DrawKeyPointsAndEdges(const cv::Mat &src, NvAR_Point2f *keypoints, int numKeyPoints, NvAR_BBoxes* output_bbox);
|
||||
void drawKalmanStatus(cv::Mat &img);
|
||||
void drawVideoCaptureStatus(cv::Mat &img);
|
||||
void processKey(int key);
|
||||
void writeVideoAndEstResults(const cv::Mat &frame, NvAR_BBoxes output_bboxes, NvAR_Point2f *keypoints = NULL);
|
||||
void writeFrameAndEstResults(const cv::Mat &frame, NvAR_BBoxes output_bboxes, NvAR_Point2f *keypoints = NULL);
|
||||
void writeEstResults(std::ofstream &outputFile, NvAR_BBoxes output_bboxes, NvAR_Point2f *keypoints = NULL);
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
void DrawKeyPointsAndEdges(const cv::Mat &src, NvAR_Point2f *keypoints, int numKeyPoints, NvAR_TrackingBBoxes* output_bbox);
|
||||
void writeVideoAndEstResults(const cv::Mat &frame, NvAR_TrackingBBoxes output_bboxes, NvAR_Point2f *keypoints = NULL);
|
||||
void writeFrameAndEstResults(const cv::Mat &frame, NvAR_TrackingBBoxes output_bboxes, NvAR_Point2f *keypoints = NULL);
|
||||
void writeEstResults(std::ofstream &outputFile, NvAR_TrackingBBoxes output_bboxes, NvAR_Point2f *keypoints = NULL);
|
||||
#endif
|
||||
void getFPS();
|
||||
static const char *errorStringFromCode(Err code);
|
||||
|
||||
@@ -337,6 +371,10 @@ class DoApp {
|
||||
float expr[6];
|
||||
bool drawVisualization, showFPS, captureVideo, captureFrame;
|
||||
float scaleOffsetXY[4];
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
std::vector<cv::Scalar> colorCodes = { cv::Scalar(255,255,255) };
|
||||
const unsigned int peopleTrackingBatchSize = 8; // Batch Size has to be 8 when people tracking is enabled
|
||||
#endif
|
||||
};
|
||||
|
||||
DoApp *gApp = nullptr;
|
||||
@@ -347,13 +385,17 @@ void DoApp::processKey(int key) {
|
||||
case '2':
|
||||
body_ar_engine.destroyFeatures();
|
||||
body_ar_engine.setAppMode(BodyEngine::mode::keyPointDetection);
|
||||
body_ar_engine.createFeatures(FLAG_modelPath.c_str());
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
if (FLAG_enablePeopleTracking) body_ar_engine.createFeatures(FLAG_modelPath.c_str());
|
||||
else
|
||||
#endif
|
||||
body_ar_engine.createFeatures(FLAG_modelPath.c_str(), 1);
|
||||
body_ar_engine.initFeatureIOParams();
|
||||
break;
|
||||
case '1':
|
||||
body_ar_engine.destroyFeatures();
|
||||
body_ar_engine.setAppMode(BodyEngine::mode::bodyDetection);
|
||||
body_ar_engine.createFeatures(FLAG_modelPath.c_str());
|
||||
body_ar_engine.createFeatures(FLAG_modelPath.c_str(), 1);
|
||||
body_ar_engine.initFeatureIOParams();
|
||||
break;
|
||||
case 'C':
|
||||
@@ -381,8 +423,11 @@ DoApp::Err DoApp::initBodyEngine(const char *modelPath) {
|
||||
if (!cap.isOpened()) return errVideo;
|
||||
|
||||
int numKeyPoints = body_ar_engine.getNumKeyPoints();
|
||||
|
||||
nvErr = body_ar_engine.createFeatures(modelPath);
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
if (FLAG_enablePeopleTracking) nvErr = body_ar_engine.createFeatures(modelPath, peopleTrackingBatchSize);
|
||||
else
|
||||
#endif
|
||||
nvErr = body_ar_engine.createFeatures(modelPath, 1);
|
||||
|
||||
#ifdef DEBUG
|
||||
detector->setOutputLocation(outputDir);
|
||||
@@ -425,6 +470,51 @@ void DoApp::DrawBBoxes(const cv::Mat &src, NvAR_Rect *output_bbox) {
|
||||
if (FLAG_offlineMode) bodyDetectOutputVideo.write(frm);
|
||||
}
|
||||
|
||||
void DoApp::DrawBBoxes(const cv::Mat &src, NvAR_BBoxes *output_bbox) {
|
||||
cv::Mat frm;
|
||||
if (FLAG_offlineMode)
|
||||
frm = src.clone();
|
||||
else
|
||||
frm = src;
|
||||
|
||||
if (output_bbox) {
|
||||
for (int i = 0; i < output_bbox->num_boxes; i++) {
|
||||
auto color = cv::Scalar(255, 255, 255);
|
||||
cv::rectangle(frm, cv::Point(lround(output_bbox->boxes[i].x), lround(output_bbox->boxes[i].y)),
|
||||
cv::Point(lround(output_bbox->boxes[i].x + output_bbox->boxes[i].width), lround(output_bbox->boxes[i].y + output_bbox->boxes[i].height)),
|
||||
cv::Scalar(255, 0, 0), 2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (FLAG_offlineMode) bodyDetectOutputVideo.write(frm);
|
||||
}
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
void DoApp::DrawBBoxes(const cv::Mat &src, NvAR_TrackingBBoxes *output_bbox) {
|
||||
cv::Mat frm;
|
||||
if (FLAG_offlineMode)
|
||||
frm = src.clone();
|
||||
else
|
||||
frm = src;
|
||||
|
||||
if (output_bbox) {
|
||||
for (int i = 0; i < output_bbox->num_boxes; i++) {
|
||||
if (colorCodes.size() <= output_bbox->boxes[i].tracking_id)
|
||||
colorCodes.push_back(cv::Scalar(rand() & 0xFF, rand() & 0xFF, rand() & 0xFF));
|
||||
auto color = colorCodes[output_bbox->boxes[i].tracking_id];
|
||||
std::string text = "ID: " + std::to_string(output_bbox->boxes[i].tracking_id);
|
||||
|
||||
cv::rectangle(frm, cv::Point(lround(output_bbox->boxes[i].bbox.x), lround(output_bbox->boxes[i].bbox.y)),
|
||||
cv::Point(lround(output_bbox->boxes[i].bbox.x + output_bbox->boxes[i].bbox.width), lround(output_bbox->boxes[i].bbox.y + output_bbox->boxes[i].bbox.height)),
|
||||
color, 2);
|
||||
cv::putText(frm, text, cv::Point(lround(output_bbox->boxes[i].bbox.x), lround(output_bbox->boxes[i].bbox.y) - 10), cv::FONT_HERSHEY_SIMPLEX, 0.9, color, 2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (FLAG_offlineMode) bodyDetectOutputVideo.write(frm);
|
||||
}
|
||||
#endif
|
||||
void DoApp::writeVideoAndEstResults(const cv::Mat &frm, NvAR_BBoxes output_bboxes, NvAR_Point2f* keypoints) {
|
||||
if (captureVideo) {
|
||||
if (!capturedVideo.isOpened()) {
|
||||
@@ -469,7 +559,54 @@ void DoApp::writeVideoAndEstResults(const cv::Mat &frm, NvAR_BBoxes output_bboxe
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
void DoApp::writeVideoAndEstResults(const cv::Mat &frm, NvAR_TrackingBBoxes output_bboxes, NvAR_Point2f* keypoints) {
|
||||
if (captureVideo) {
|
||||
if (!capturedVideo.isOpened()) {
|
||||
const std::string currentCalendarTime = getCalendarTime();
|
||||
const std::string capturedOutputFileName = currentCalendarTime + ".mp4";
|
||||
getFPS();
|
||||
if (frameTime) {
|
||||
float fps = (float)(1.0 / frameTime);
|
||||
capturedVideo.open(capturedOutputFileName, StringToFourcc(FLAG_captureCodec), fps,
|
||||
cv::Size(frm.cols, frm.rows));
|
||||
if (!capturedVideo.isOpened()) {
|
||||
std::cout << "Error: Could not open video: \"" << capturedOutputFileName << "\"\n";
|
||||
return;
|
||||
}
|
||||
if (FLAG_verbose) {
|
||||
std::cout << "Capturing video started" << std::endl;
|
||||
}
|
||||
}
|
||||
else { // If frameTime is 0.f, returns without writing the frame to the Video
|
||||
return;
|
||||
}
|
||||
const std::string outputsFileName = currentCalendarTime + ".txt";
|
||||
bodyEngineVideoOutputFile.open(outputsFileName, std::ios_base::out);
|
||||
if (!bodyEngineVideoOutputFile.is_open()) {
|
||||
std::cout << "Error: Could not open file: \"" << outputsFileName << "\"\n";
|
||||
return;
|
||||
}
|
||||
std::string keyPointDetectionMode = (keypoints == NULL) ? "Off" : "On";
|
||||
bodyEngineVideoOutputFile << "// BodyDetectOn, KeyPointDetect" << keyPointDetectionMode << "\n ";
|
||||
bodyEngineVideoOutputFile
|
||||
<< "// kNumPeople, (bbox_x, bbox_y, bbox_w, bbox_h){ kNumPeople}, kNumLMs, [lm_x, lm_y]{kNumLMs}\n";
|
||||
}
|
||||
// Write each frame to the Video
|
||||
capturedVideo << frm;
|
||||
writeEstResults(bodyEngineVideoOutputFile, output_bboxes, keypoints);
|
||||
}
|
||||
else {
|
||||
if (capturedVideo.isOpened()) {
|
||||
if (FLAG_verbose) {
|
||||
std::cout << "Capturing video ended" << std::endl;
|
||||
}
|
||||
capturedVideo.release();
|
||||
if (bodyEngineVideoOutputFile.is_open()) bodyEngineVideoOutputFile.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
void DoApp::writeEstResults(std::ofstream &outputFile, NvAR_BBoxes output_bboxes, NvAR_Point2f* keypoints) {
|
||||
/**
|
||||
* Output File Format :
|
||||
@@ -512,7 +649,53 @@ void DoApp::writeEstResults(std::ofstream &outputFile, NvAR_BBoxes output_bboxes
|
||||
|
||||
outputFile << "\n";
|
||||
}
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
void DoApp::writeEstResults(std::ofstream &outputFile, NvAR_TrackingBBoxes output_bboxes, NvAR_Point2f* keypoints) {
|
||||
/**
|
||||
* Output File Format :
|
||||
* BodyDetectOn, KeyPointDetectOn
|
||||
* kNumPeople, (bbox_x, bbox_y, bbox_w, bbox_h){ kNumPeople}, kNumKPs, [j_x, j_y]{kNumKPs}
|
||||
*/
|
||||
|
||||
int bodyDetectOn = (body_ar_engine.appMode == BodyEngine::mode::bodyDetection ||
|
||||
body_ar_engine.appMode == BodyEngine::mode::keyPointDetection)
|
||||
? 1
|
||||
: 0;
|
||||
int keyPointDetectOn = (body_ar_engine.appMode == BodyEngine::mode::keyPointDetection)
|
||||
? 1
|
||||
: 0;
|
||||
outputFile << bodyDetectOn << "," << keyPointDetectOn << "\n";
|
||||
|
||||
if (bodyDetectOn && output_bboxes.num_boxes) {
|
||||
// Append number of bodies detected in the current frame
|
||||
outputFile << unsigned(output_bboxes.num_boxes) << ",";
|
||||
// write outputbboxes to outputFile
|
||||
for (size_t i = 0; i < output_bboxes.num_boxes; i++) {
|
||||
int x1 = (int)output_bboxes.boxes[i].bbox.x, y1 = (int)output_bboxes.boxes[i].bbox.y,
|
||||
width = (int)output_bboxes.boxes[i].bbox.width, height = (int)output_bboxes.boxes[i].bbox.height;
|
||||
unsigned int tracking_id = output_bboxes.boxes[i].tracking_id;
|
||||
outputFile << x1 << "," << y1 << "," << width << "," << height << "," << tracking_id << ",";
|
||||
}
|
||||
}
|
||||
else {
|
||||
outputFile << "0,";
|
||||
}
|
||||
if (keyPointDetectOn && output_bboxes.num_boxes) {
|
||||
int numKeyPoints = body_ar_engine.getNumKeyPoints();
|
||||
// Append number of keypoints
|
||||
outputFile << numKeyPoints << ",";
|
||||
// Append 2 * number of keypoint values
|
||||
NvAR_Point2f *pt, *endPt;
|
||||
for (endPt = (pt = (NvAR_Point2f *)keypoints) + numKeyPoints; pt < endPt; ++pt)
|
||||
outputFile << pt->x << "," << pt->y << ",";
|
||||
}
|
||||
else {
|
||||
outputFile << "0,";
|
||||
}
|
||||
|
||||
outputFile << "\n";
|
||||
}
|
||||
#endif
|
||||
void DoApp::writeFrameAndEstResults(const cv::Mat &frm, NvAR_BBoxes output_bboxes, NvAR_Point2f* keypoints) {
|
||||
if (captureFrame) {
|
||||
const std::string currentCalendarTime = getCalendarTime();
|
||||
@@ -537,28 +720,47 @@ void DoApp::writeFrameAndEstResults(const cv::Mat &frm, NvAR_BBoxes output_bboxe
|
||||
captureFrame = false;
|
||||
}
|
||||
}
|
||||
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
void DoApp::writeFrameAndEstResults(const cv::Mat &frm, NvAR_TrackingBBoxes output_bboxes, NvAR_Point2f* keypoints) {
|
||||
if (captureFrame) {
|
||||
const std::string currentCalendarTime = getCalendarTime();
|
||||
const std::string capturedFrame = currentCalendarTime + ".png";
|
||||
cv::imwrite(capturedFrame, frm);
|
||||
if (FLAG_verbose) {
|
||||
std::cout << "Captured the frame" << std::endl;
|
||||
}
|
||||
// Write Body Engine Outputs
|
||||
const std::string outputFilename = currentCalendarTime + ".txt";
|
||||
std::ofstream outputFile;
|
||||
outputFile.open(outputFilename, std::ios_base::out);
|
||||
if (!outputFile.is_open()) {
|
||||
std::cout << "Error: Could not open file: \"" << outputFilename << "\"\n";
|
||||
return;
|
||||
}
|
||||
std::string keyPointDetectionMode = (keypoints == NULL) ? "Off" : "On";
|
||||
outputFile << "// BodyDetectOn, KeyPointDetect" << keyPointDetectionMode << "\n";
|
||||
outputFile << "// kNumPeople, (bbox_x, bbox_y, bbox_w, bbox_h){ kNumPeople}, kNumLMs, [lm_x, lm_y]{kNumLMs}\n";
|
||||
writeEstResults(outputFile, output_bboxes, keypoints);
|
||||
if (outputFile.is_open()) outputFile.close();
|
||||
captureFrame = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
void DoApp::DrawKeyPointLine(const cv::Mat& src, NvAR_Point2f* keypoints, int point1, int point2, int color) {
|
||||
NvAR_Point2f point1_pos = *(keypoints + point1);
|
||||
NvAR_Point2f point2_pos = *(keypoints + point2);
|
||||
cv::line(src, cv::Point((int)point1_pos.x, (int)point1_pos.y), cv::Point((int)point2_pos.x, (int)point2_pos.y), cv_colors[color], 2);
|
||||
|
||||
}
|
||||
|
||||
void DoApp::DrawKeyPointsAndEdges(const cv::Mat& src, NvAR_Point2f* keypoints, int numKeyPoints, NvAR_Rect* output_bbox) {
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
void DoApp::DrawKeyPointsAndEdges(const cv::Mat& src, NvAR_Point2f* keypoints, int numKeyPoints, NvAR_TrackingBBoxes* output_bbox) {
|
||||
cv::Mat frm;
|
||||
if (FLAG_offlineMode)
|
||||
frm = src.clone();
|
||||
else
|
||||
frm = src;
|
||||
NvAR_Point2f *pt, *endPt;
|
||||
for (endPt = (pt = (NvAR_Point2f *)keypoints) + numKeyPoints; pt < endPt; ++pt)
|
||||
cv::circle(frm, cv::Point(lround(pt->x), lround(pt->y)), 4, cv::Scalar(180, 180, 180), -1);
|
||||
|
||||
if (output_bbox)
|
||||
cv::rectangle(frm, cv::Point(lround(output_bbox->x), lround(output_bbox->y)),
|
||||
cv::Point(lround(output_bbox->x + output_bbox->width), lround(output_bbox->y + output_bbox->height)),
|
||||
cv::Scalar(255, 0, 0), 2);
|
||||
NvAR_Point2f* keypointsBatch8 = keypoints;
|
||||
|
||||
int pelvis = 0;
|
||||
int left_hip = 1;
|
||||
@@ -595,56 +797,187 @@ void DoApp::DrawKeyPointsAndEdges(const cv::Mat& src, NvAR_Point2f* keypoints, i
|
||||
int left_thumb_tip = 32;
|
||||
int right_thumb_tip = 33;
|
||||
|
||||
// center body
|
||||
DrawKeyPointLine(frm, keypoints, pelvis, torso, kColorGreen);
|
||||
DrawKeyPointLine(frm, keypoints, torso, neck, kColorGreen);
|
||||
DrawKeyPointLine(frm, keypoints, neck, pelvis, kColorGreen);
|
||||
for (int i = 0; i < body_ar_engine.output_tracking_bboxes.num_boxes; i++) {
|
||||
|
||||
// right side
|
||||
DrawKeyPointLine(frm, keypoints, right_ankle, right_knee, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_knee, right_hip, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_hip, pelvis, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_hip, right_shoulder, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_shoulder, right_elbow, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_elbow, right_wrist, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_shoulder, neck, kColorRed);
|
||||
keypoints = keypointsBatch8 + (i * 34);
|
||||
|
||||
// right side hand and feet
|
||||
DrawKeyPointLine(frm, keypoints, right_wrist, right_pinky_knuckle, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_wrist, right_middle_tip, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_wrist, right_index_knuckle, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_wrist, right_thumb_tip, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_ankle, right_heel, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_ankle, right_big_toe, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_big_toe, right_small_toe, kColorRed);
|
||||
for (endPt = (pt = (NvAR_Point2f*)keypoints) + numKeyPoints; pt < endPt; ++pt)
|
||||
cv::circle(frm, cv::Point(lround(pt->x), lround(pt->y)), 4, cv::Scalar(180, 180, 180), -1);
|
||||
|
||||
//left side
|
||||
DrawKeyPointLine(frm, keypoints, left_ankle, left_knee, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_knee, left_hip, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_hip, pelvis, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_hip, left_shoulder, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_shoulder, left_elbow, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_elbow, left_wrist, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_shoulder, neck, kColorBlue);
|
||||
if (output_bbox) {
|
||||
while (colorCodes.size()<= output_bbox->boxes[i].tracking_id)
|
||||
colorCodes.push_back(cv::Scalar(rand() & 0xFF, rand() & 0xFF, rand() & 0xFF));
|
||||
auto color = colorCodes[output_bbox->boxes[i].tracking_id];
|
||||
std::string text = "ID: "+std::to_string(output_bbox->boxes[i].tracking_id);
|
||||
cv::rectangle(frm, cv::Point(lround(output_bbox->boxes[i].bbox.x), lround(output_bbox->boxes[i].bbox.y)),
|
||||
cv::Point(lround(output_bbox->boxes[i].bbox.x + output_bbox->boxes[i].bbox.width), lround(output_bbox->boxes[i].bbox.y + output_bbox->boxes[i].bbox.height)),
|
||||
color, 2);
|
||||
cv::putText(frm, text, cv::Point(lround(output_bbox->boxes[i].bbox.x), lround(output_bbox->boxes[i].bbox.y) - 10), cv::FONT_HERSHEY_SIMPLEX, 0.5, color, 2);
|
||||
}
|
||||
|
||||
|
||||
// left side hand and feet
|
||||
DrawKeyPointLine(frm, keypoints, left_wrist, left_pinky_knuckle, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_wrist, left_middle_tip, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_wrist, left_index_knuckle, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_wrist, left_thumb_tip, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_ankle, left_heel, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_ankle, left_big_toe, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_big_toe, left_small_toe, kColorBlue);
|
||||
// center body
|
||||
DrawKeyPointLine(frm, keypoints, pelvis, torso, kColorGreen);
|
||||
DrawKeyPointLine(frm, keypoints, torso, neck, kColorGreen);
|
||||
DrawKeyPointLine(frm, keypoints, neck, pelvis, kColorGreen);
|
||||
|
||||
// head
|
||||
DrawKeyPointLine(frm, keypoints, neck, nose, kColorGreen);
|
||||
DrawKeyPointLine(frm, keypoints, nose, right_eye, kColorGreen);
|
||||
DrawKeyPointLine(frm, keypoints, right_eye, right_ear, kColorGreen);
|
||||
DrawKeyPointLine(frm, keypoints, nose, left_eye, kColorGreen);
|
||||
DrawKeyPointLine(frm, keypoints, left_eye, left_ear, kColorGreen);
|
||||
// right side
|
||||
DrawKeyPointLine(frm, keypoints, right_ankle, right_knee, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_knee, right_hip, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_hip, pelvis, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_hip, right_shoulder, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_shoulder, right_elbow, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_elbow, right_wrist, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_shoulder, neck, kColorRed);
|
||||
|
||||
// right side hand and feet
|
||||
DrawKeyPointLine(frm, keypoints, right_wrist, right_pinky_knuckle, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_wrist, right_middle_tip, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_wrist, right_index_knuckle, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_wrist, right_thumb_tip, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_ankle, right_heel, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_ankle, right_big_toe, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_big_toe, right_small_toe, kColorRed);
|
||||
|
||||
//left side
|
||||
DrawKeyPointLine(frm, keypoints, left_ankle, left_knee, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_knee, left_hip, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_hip, pelvis, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_hip, left_shoulder, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_shoulder, left_elbow, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_elbow, left_wrist, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_shoulder, neck, kColorBlue);
|
||||
|
||||
// left side hand and feet
|
||||
DrawKeyPointLine(frm, keypoints, left_wrist, left_pinky_knuckle, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_wrist, left_middle_tip, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_wrist, left_index_knuckle, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_wrist, left_thumb_tip, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_ankle, left_heel, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_ankle, left_big_toe, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_big_toe, left_small_toe, kColorBlue);
|
||||
|
||||
// head
|
||||
DrawKeyPointLine(frm, keypoints, neck, nose, kColorGreen);
|
||||
DrawKeyPointLine(frm, keypoints, nose, right_eye, kColorGreen);
|
||||
DrawKeyPointLine(frm, keypoints, right_eye, right_ear, kColorGreen);
|
||||
DrawKeyPointLine(frm, keypoints, nose, left_eye, kColorGreen);
|
||||
DrawKeyPointLine(frm, keypoints, left_eye, left_ear, kColorGreen);
|
||||
}
|
||||
|
||||
if (FLAG_offlineMode) keyPointsOutputVideo.write(frm);
|
||||
}
|
||||
#endif
|
||||
void DoApp::DrawKeyPointsAndEdges(const cv::Mat& src, NvAR_Point2f* keypoints, int numKeyPoints, NvAR_BBoxes* output_bbox) {
|
||||
cv::Mat frm;
|
||||
if (FLAG_offlineMode)
|
||||
frm = src.clone();
|
||||
else
|
||||
frm = src;
|
||||
NvAR_Point2f *pt, *endPt;
|
||||
NvAR_Point2f* keypointsBatch8 = keypoints;
|
||||
|
||||
int pelvis = 0;
|
||||
int left_hip = 1;
|
||||
int right_hip = 2;
|
||||
int torso = 3;
|
||||
int left_knee = 4;
|
||||
int right_knee = 5;
|
||||
int neck = 6;
|
||||
int left_ankle = 7;
|
||||
int right_ankle = 8;
|
||||
int left_big_toe = 9;
|
||||
int right_big_toe = 10;
|
||||
int left_small_toe = 11;
|
||||
int right_small_toe = 12;
|
||||
int left_heel = 13;
|
||||
int right_heel = 14;
|
||||
int nose = 15;
|
||||
int left_eye = 16;
|
||||
int right_eye = 17;
|
||||
int left_ear = 18;
|
||||
int right_ear = 19;
|
||||
int left_shoulder = 20;
|
||||
int right_shoulder = 21;
|
||||
int left_elbow = 22;
|
||||
int right_elbow = 23;
|
||||
int left_wrist = 24;
|
||||
int right_wrist = 25;
|
||||
int left_pinky_knuckle = 26;
|
||||
int right_pinky_knuckle = 27;
|
||||
int left_middle_tip = 28;
|
||||
int right_middle_tip = 29;
|
||||
int left_index_knuckle = 30;
|
||||
int right_index_knuckle = 31;
|
||||
int left_thumb_tip = 32;
|
||||
int right_thumb_tip = 33;
|
||||
|
||||
for (int i = 0; i < body_ar_engine.output_bboxes.num_boxes; i++) {
|
||||
|
||||
keypoints = keypointsBatch8 + (i * 34);
|
||||
|
||||
for (endPt = (pt = (NvAR_Point2f*)keypoints) + numKeyPoints; pt < endPt; ++pt)
|
||||
cv::circle(frm, cv::Point(lround(pt->x), lround(pt->y)), 4, cv::Scalar(180, 180, 180), -1);
|
||||
|
||||
if (output_bbox) {
|
||||
cv::rectangle(frm, cv::Point(lround(output_bbox->boxes[i].x), lround(output_bbox->boxes[i].y)),
|
||||
cv::Point(lround(output_bbox->boxes[i].x + output_bbox->boxes[i].width), lround(output_bbox->boxes[i].y + output_bbox->boxes[i].height)),
|
||||
cv::Scalar(255, 0, 0), 2);
|
||||
}
|
||||
|
||||
|
||||
// center body
|
||||
DrawKeyPointLine(frm, keypoints, pelvis, torso, kColorGreen);
|
||||
DrawKeyPointLine(frm, keypoints, torso, neck, kColorGreen);
|
||||
DrawKeyPointLine(frm, keypoints, neck, pelvis, kColorGreen);
|
||||
|
||||
// right side
|
||||
DrawKeyPointLine(frm, keypoints, right_ankle, right_knee, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_knee, right_hip, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_hip, pelvis, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_hip, right_shoulder, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_shoulder, right_elbow, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_elbow, right_wrist, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_shoulder, neck, kColorRed);
|
||||
|
||||
// right side hand and feet
|
||||
DrawKeyPointLine(frm, keypoints, right_wrist, right_pinky_knuckle, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_wrist, right_middle_tip, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_wrist, right_index_knuckle, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_wrist, right_thumb_tip, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_ankle, right_heel, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_ankle, right_big_toe, kColorRed);
|
||||
DrawKeyPointLine(frm, keypoints, right_big_toe, right_small_toe, kColorRed);
|
||||
|
||||
//left side
|
||||
DrawKeyPointLine(frm, keypoints, left_ankle, left_knee, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_knee, left_hip, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_hip, pelvis, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_hip, left_shoulder, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_shoulder, left_elbow, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_elbow, left_wrist, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_shoulder, neck, kColorBlue);
|
||||
|
||||
// left side hand and feet
|
||||
DrawKeyPointLine(frm, keypoints, left_wrist, left_pinky_knuckle, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_wrist, left_middle_tip, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_wrist, left_index_knuckle, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_wrist, left_thumb_tip, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_ankle, left_heel, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_ankle, left_big_toe, kColorBlue);
|
||||
DrawKeyPointLine(frm, keypoints, left_big_toe, left_small_toe, kColorBlue);
|
||||
|
||||
// head
|
||||
DrawKeyPointLine(frm, keypoints, neck, nose, kColorGreen);
|
||||
DrawKeyPointLine(frm, keypoints, nose, right_eye, kColorGreen);
|
||||
DrawKeyPointLine(frm, keypoints, right_eye, right_ear, kColorGreen);
|
||||
DrawKeyPointLine(frm, keypoints, nose, left_eye, kColorGreen);
|
||||
DrawKeyPointLine(frm, keypoints, left_eye, left_ear, kColorGreen);
|
||||
|
||||
}
|
||||
|
||||
if (FLAG_offlineMode) keyPointsOutputVideo.write(frm);
|
||||
}
|
||||
|
||||
DoApp::Err DoApp::acquireFrame() {
|
||||
Err err = errNone;
|
||||
@@ -682,8 +1015,20 @@ DoApp::Err DoApp::acquireBodyBox() {
|
||||
printf("]\n");
|
||||
}
|
||||
if (FLAG_captureOutputs) {
|
||||
writeFrameAndEstResults(frame, body_ar_engine.output_bboxes);
|
||||
writeVideoAndEstResults(frame, body_ar_engine.output_bboxes);
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
if (FLAG_enablePeopleTracking) {
|
||||
writeFrameAndEstResults(frame, body_ar_engine.output_tracking_bboxes);
|
||||
writeVideoAndEstResults(frame, body_ar_engine.output_tracking_bboxes);
|
||||
}
|
||||
else {
|
||||
writeFrameAndEstResults(frame, body_ar_engine.output_bboxes);
|
||||
writeVideoAndEstResults(frame, body_ar_engine.output_bboxes);
|
||||
}
|
||||
#else
|
||||
writeFrameAndEstResults(frame, body_ar_engine.output_bboxes);
|
||||
writeVideoAndEstResults(frame, body_ar_engine.output_bboxes);
|
||||
#endif
|
||||
|
||||
}
|
||||
if (0 == n) return errNoBody;
|
||||
|
||||
@@ -701,18 +1046,29 @@ DoApp::Err DoApp::acquireBodyBox() {
|
||||
DoApp::Err DoApp::acquireBodyBoxAndKeyPoints() {
|
||||
Err err = errNone;
|
||||
int numKeyPoints = body_ar_engine.getNumKeyPoints();
|
||||
NvAR_Rect output_bbox;
|
||||
std::vector<NvAR_Point2f> keypoints2D(numKeyPoints);
|
||||
std::vector<NvAR_Point3f> keypoints3D(numKeyPoints);
|
||||
std::vector<NvAR_Quaternion> jointAngles(numKeyPoints);
|
||||
NvAR_BBoxes output_bbox;
|
||||
NvAR_TrackingBBoxes output_tracking_bbox;
|
||||
std::vector<NvAR_Point2f> keypoints2D(numKeyPoints * 8);
|
||||
std::vector<NvAR_Point3f> keypoints3D(numKeyPoints * 8);
|
||||
std::vector<NvAR_Quaternion> jointAngles(numKeyPoints * 8);
|
||||
|
||||
|
||||
#ifdef DEBUG_PERF_RUNTIME
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
#endif
|
||||
|
||||
unsigned n;
|
||||
// get keypoints in original image resolution coordinate space
|
||||
unsigned n = body_ar_engine.acquireBodyBoxAndKeyPoints(frame, keypoints2D.data(), keypoints3D.data(),
|
||||
jointAngles.data(), output_bbox, 0);
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
if (FLAG_enablePeopleTracking)
|
||||
n = body_ar_engine.acquireBodyBoxAndKeyPoints(frame, keypoints2D.data(), keypoints3D.data(),
|
||||
jointAngles.data(), &output_tracking_bbox, 0);
|
||||
|
||||
else
|
||||
#endif
|
||||
n = body_ar_engine.acquireBodyBoxAndKeyPoints(frame, keypoints2D.data(), keypoints3D.data(),
|
||||
jointAngles.data(), &output_bbox, 0);
|
||||
|
||||
|
||||
#ifdef DEBUG_PERF_RUNTIME
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
@@ -734,17 +1090,37 @@ DoApp::Err DoApp::acquireBodyBoxAndKeyPoints() {
|
||||
printf("]\n");
|
||||
}
|
||||
if (FLAG_captureOutputs) {
|
||||
writeFrameAndEstResults(frame, body_ar_engine.output_bboxes, keypoints2D.data());
|
||||
writeVideoAndEstResults(frame, body_ar_engine.output_bboxes, keypoints2D.data());
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
if (FLAG_enablePeopleTracking) {
|
||||
writeFrameAndEstResults(frame, body_ar_engine.output_tracking_bboxes, keypoints2D.data());
|
||||
writeVideoAndEstResults(frame, body_ar_engine.output_tracking_bboxes, keypoints2D.data());
|
||||
}
|
||||
else {
|
||||
writeFrameAndEstResults(frame, body_ar_engine.output_bboxes, keypoints2D.data());
|
||||
writeVideoAndEstResults(frame, body_ar_engine.output_bboxes, keypoints2D.data());
|
||||
}
|
||||
#else
|
||||
writeFrameAndEstResults(frame, body_ar_engine.output_bboxes, keypoints2D.data());
|
||||
writeVideoAndEstResults(frame, body_ar_engine.output_bboxes, keypoints2D.data());
|
||||
#endif
|
||||
|
||||
}
|
||||
if (0 == n) return errNoBody;
|
||||
|
||||
#ifdef VISUALIZE
|
||||
|
||||
if (drawVisualization) {
|
||||
DrawKeyPointsAndEdges(frame, keypoints2D.data(), numKeyPoints, &output_bbox);
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
if (FLAG_enablePeopleTracking) DrawKeyPointsAndEdges(frame, keypoints2D.data(), numKeyPoints, &output_tracking_bbox);
|
||||
else
|
||||
#endif
|
||||
DrawKeyPointsAndEdges(frame, keypoints2D.data(), numKeyPoints, &output_bbox);
|
||||
if (FLAG_offlineMode) {
|
||||
DrawBBoxes(frame, &output_bbox);
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
if (FLAG_enablePeopleTracking) DrawBBoxes(frame, &output_tracking_bbox);
|
||||
else
|
||||
#endif
|
||||
DrawBBoxes(frame, &output_bbox);
|
||||
}
|
||||
}
|
||||
#endif // VISUALIZE
|
||||
@@ -920,6 +1296,8 @@ DoApp::Err DoApp::run() {
|
||||
}
|
||||
cv::imshow(windowTitle, frame);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!FLAG_offlineMode) {
|
||||
int n = cv::waitKey(1);
|
||||
@@ -991,7 +1369,9 @@ int main(int argc, char **argv) {
|
||||
|
||||
if (FLAG_useCudaGraph) printf("Enable capturing cuda graph = %d\n", FLAG_useCudaGraph);
|
||||
app.body_ar_engine.useCudaGraph(FLAG_useCudaGraph);
|
||||
|
||||
#if NV_MULTI_OBJECT_TRACKER
|
||||
app.body_ar_engine.enablePeopleTracking(FLAG_enablePeopleTracking, FLAG_shadowTrackingAge, FLAG_probationAge, FLAG_maxTargetsTracked);
|
||||
#endif
|
||||
doErr = DoApp::errBodyModelInit;
|
||||
if (FLAG_modelPath.empty()) {
|
||||
printf("WARNING: Model path not specified. Please set --model_path=/path/to/trt/and/body/models, "
|
||||
|
||||
Binary file not shown.
@@ -4,12 +4,14 @@ set(SOURCE_FILES BodyEngine.cpp
|
||||
)
|
||||
|
||||
set(HEADER_FILES BodyEngine.h)
|
||||
set(SOURCE_FILES ${SOURCE_FILES}
|
||||
../../nvar/src/nvARProxy.cpp
|
||||
../../nvar/src/nvCVImageProxy.cpp)
|
||||
if(MSVC)
|
||||
set(SOURCE_FILES ${SOURCE_FILES}
|
||||
../../nvar/src/nvARProxy.cpp
|
||||
../../nvar/src/nvCVImageProxy.cpp)
|
||||
|
||||
set(HEADER_FILES ${HEADER_FILES}
|
||||
../utils/RenderingUtils.h)
|
||||
set(HEADER_FILES ${HEADER_FILES}
|
||||
../utils/RenderingUtils.h)
|
||||
endif(MSVC)
|
||||
|
||||
# Set Visual Studio source filters
|
||||
source_group("Source Files" FILES ${SOURCE_FILES})
|
||||
@@ -21,6 +23,7 @@ target_include_directories(BodyTrack PUBLIC
|
||||
${SDK_INCLUDES_PATH}
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
target_link_libraries(BodyTrack PUBLIC
|
||||
opencv346
|
||||
utils_sample
|
||||
@@ -29,11 +32,21 @@ target_link_libraries(BodyTrack PUBLIC
|
||||
set(ARSDK_PATH_STR ${CMAKE_CURRENT_SOURCE_DIR}/../../bin)
|
||||
set(OPENCV_PATH_STR ${CMAKE_CURRENT_SOURCE_DIR}/../external/opencv/bin)
|
||||
set(PATH_STR "PATH=%PATH%" ${OPENCV_PATH_STR})
|
||||
set(CMD_ARG_STR "")
|
||||
set_target_properties(BodyTrack PROPERTIES
|
||||
FOLDER SampleApps
|
||||
VS_DEBUGGER_ENVIRONMENT "${PATH_STR}"
|
||||
VS_DEBUGGER_COMMAND_ARGUMENTS "${CMD_ARG_STR}"
|
||||
set(CMD_ARG_STR "--model_path=\"${CMAKE_CURRENT_SOURCE_DIR}/../../bin/models\"")
|
||||
set_target_properties(BodyTrack PROPERTIES
|
||||
FOLDER SampleApps
|
||||
VS_DEBUGGER_ENVIRONMENT "${PATH_STR}"
|
||||
VS_DEBUGGER_COMMAND_ARGUMENTS "${CMD_ARG_STR}"
|
||||
)
|
||||
elseif(UNIX)
|
||||
find_package(PNG REQUIRED)
|
||||
find_package(JPEG REQUIRED)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
|
||||
target_link_libraries(BodyTrack PUBLIC
|
||||
nvARPose
|
||||
NVCVImage
|
||||
OpenCV
|
||||
utils_sample
|
||||
)
|
||||
|
||||
endif(MSVC)
|
||||
|
||||
|
||||
@@ -6,3 +6,5 @@ target_link_libraries(utils_sample INTERFACE GLM)
|
||||
add_subdirectory(external)
|
||||
add_subdirectory(FaceTrack)
|
||||
add_subdirectory(BodyTrack)
|
||||
add_subdirectory(GazeRedirect)
|
||||
add_subdirectory(ExpressionApp)
|
||||
|
||||
2378
samples/ExpressionApp/BackEndOpenGL/FaceIO.cpp
Normal file
2378
samples/ExpressionApp/BackEndOpenGL/FaceIO.cpp
Normal file
File diff suppressed because it is too large
Load Diff
231
samples/ExpressionApp/BackEndOpenGL/FaceIO.h
Normal file
231
samples/ExpressionApp/BackEndOpenGL/FaceIO.h
Normal file
@@ -0,0 +1,231 @@
|
||||
/*###############################################################################
|
||||
#
|
||||
# Copyright 2019-2021 NVIDIA Corporation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
###############################################################################*/
|
||||
|
||||
#ifndef __FACE_IO__
|
||||
#define __FACE_IO__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum FaceIOErr {
|
||||
kIOErrNone,
|
||||
kIOErrFileNotFound,
|
||||
kIOErrFileOpen,
|
||||
kIOErrEOF,
|
||||
kIOErrRead,
|
||||
kIOErrWrite,
|
||||
kIOErrSyntax,
|
||||
kIOErrFormat,
|
||||
kIOErrNotValue,
|
||||
kIOErrNullPointer,
|
||||
kIOErrParameter,
|
||||
};
|
||||
|
||||
const char* FaceIOErrorStringFromCode(FaceIOErr err);
|
||||
|
||||
/********************************************************************************
|
||||
********************************************************************************
|
||||
********************************************************************************
|
||||
***** IO Adapter *****
|
||||
********************************************************************************
|
||||
********************************************************************************
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* FaceIOAdapter.
|
||||
* Subclass from this and supply the accessors.
|
||||
********************************************************************************/
|
||||
|
||||
class FaceIOAdapter {
|
||||
public:
|
||||
virtual uint32_t getShapeMeanSize() const { return 0; } /* The size of the mean shape mean, in elements. */
|
||||
virtual uint32_t getShapeModesSize() const { return 0; } /* The total size of all shape modes (numModes*modeSize) */
|
||||
virtual uint32_t getShapeNumModes() const { return 0; } /* The number of shape modes. */
|
||||
virtual uint32_t getShapeEigenvaluesSize() const { return 0; } /* The number of shape eigenvalues
|
||||
(should equal the number of modes) */
|
||||
virtual float* getShapeMean(uint32_t /*size*/) { return nullptr; } /* Get a pointer to the shape mean.
|
||||
If a nonzero size if supplied, it is resized first. */
|
||||
virtual float* getShapeModes(uint32_t /*modeSize*/, uint32_t /*numModes*/) { return nullptr; } /* Get a pointer to the
|
||||
shape modes, resizing first, if the parameters are nonzero. */
|
||||
virtual float* getShapeEigenvalues(uint32_t /*numModes*/) { return nullptr; } /* Get a pointer to the shape eigenvalues,
|
||||
resizing first if numModes is nonzero. */
|
||||
|
||||
virtual uint32_t getColorMeanSize() const { return 0; } /* The color mean ... */
|
||||
virtual uint32_t getColorModesSize() const { return 0; } /* ... and modes */
|
||||
virtual uint32_t getColorNumModes() const { return 0; }
|
||||
virtual uint32_t getColorEigenvaluesSize() const { return 0; }
|
||||
virtual float* getColorMean(uint32_t /*size*/) { return nullptr; }
|
||||
virtual float* getColorModes(uint32_t /*modeSize*/, uint32_t /*numModes*/) { return nullptr; }
|
||||
virtual float* getColorEigenvalues(uint32_t /*numModes*/) { return nullptr; }
|
||||
|
||||
virtual void setTriangleListSize(uint32_t /*size*/) {} /* The triangle list */
|
||||
virtual uint32_t getTriangleListSize() const = 0;
|
||||
virtual uint16_t* getTriangleList(uint32_t /*size*/) { return nullptr; }
|
||||
|
||||
virtual void setTextureCoordinatesSize(uint32_t /*size*/) {} /* The texture coordinates */
|
||||
virtual uint32_t getTextureCoordinatesSize() const { return 0; }
|
||||
virtual float* getTextureCoordinates(uint32_t /*size*/) { return nullptr; }
|
||||
|
||||
virtual void setNumBlendShapes(uint32_t /*numShapes*/) {} /* The blend shapes */
|
||||
virtual void setBlendShapeName(uint32_t /*i*/, const char* /*name*/) {}
|
||||
virtual uint32_t getNumBlendShapes() const { return 0; }
|
||||
virtual const char* getBlendShapeName(uint32_t /*i*/) const { return nullptr; }
|
||||
virtual uint32_t getBlendShapeSize(uint32_t /*i*/) const { return 0; }
|
||||
virtual float* getBlendShape(uint32_t /*i*/, uint32_t /*size*/) { return nullptr; }
|
||||
|
||||
virtual void setIbugLandmarkMappingsSize(uint32_t /*n*/) {} /* The mappings from IBUG landmarks to vertex index */
|
||||
virtual uint32_t getIbugLandmarkMappingsSize() const { return 0; }
|
||||
virtual uint16_t* getIbugLandmarkMappings(uint32_t /*size*/) { return nullptr; }
|
||||
virtual void appendIbugLandmarkMapping(uint16_t /*i*/) {}
|
||||
virtual void appendIbugLandmarkMapping(uint16_t /*i*/, uint16_t /*j*/) {}
|
||||
|
||||
virtual void setIbugRightContourSize(uint32_t /*n*/) {} /* The IBUG contour on the right side of the face */
|
||||
virtual uint32_t getIbugRightContourSize() const { return 0; }
|
||||
virtual uint16_t* getIbugRightContour(uint32_t /*size*/) { return nullptr; }
|
||||
virtual void appendIbugRightContour(uint16_t /*i*/) {}
|
||||
|
||||
virtual void setIbugLeftContourSize(uint32_t /*n*/) {} /* The IBUG contour on the left side of the face */
|
||||
virtual uint32_t getIbugLeftContourSize() const { return 0; }
|
||||
virtual uint16_t* getIbugLeftContour(uint32_t /*size*/) { return nullptr; }
|
||||
virtual void appendIbugLeftContour(uint16_t /*i*/) {}
|
||||
|
||||
virtual void setModelRightContourSize(uint32_t /*n*/) {} /* The right contour of our model */
|
||||
virtual uint32_t getModelRightContourSize() const { return 0; }
|
||||
virtual uint16_t* getModelRightContour(uint32_t /*size*/) { return nullptr; }
|
||||
virtual void appendModelRightContour(uint16_t /*i*/) {}
|
||||
|
||||
virtual void setModelLeftContourSize(uint32_t /*n*/) {} /* The left contour of our model */
|
||||
virtual uint32_t getModelLeftContourSize() const { return 0; }
|
||||
virtual uint16_t* getModelLeftContour(uint32_t /*size*/) { return nullptr; }
|
||||
virtual void appendModelLeftContour(uint16_t /*i*/) {}
|
||||
|
||||
virtual void setAdjacentFacesSize(uint32_t /*n*/) {} /* The topology of adjacent faces to each edge */
|
||||
virtual uint32_t getAdjacentFacesSize() const { return 0; }
|
||||
virtual uint16_t* getAdjacentFaces(uint32_t /*size*/) { return nullptr; }
|
||||
virtual void appendAdjacentFace(uint16_t /*i*/) {}
|
||||
virtual void appendAdjacentFaces(uint16_t /*i*/, uint16_t /*j*/) {}
|
||||
|
||||
virtual void setAdjacentVerticesSize(uint32_t /*n*/) {} /* The topology of adjacent vertices to each edge */
|
||||
virtual uint32_t getAdjacentVerticesSize() const { return 0; }
|
||||
virtual uint16_t* getAdjacentVertices(uint32_t /*size*/) { return nullptr; }
|
||||
virtual void appendAdjacentVertex(uint16_t /*i*/) {}
|
||||
virtual void appendAdjacentVertices(uint16_t /*i*/, uint16_t /*j*/) {}
|
||||
|
||||
virtual void setNvlmLandmarksSize(uint32_t /*n*/) {} /* The tracked landmarks */
|
||||
virtual uint32_t getNvlmLandmarksSize() const { return 0; }
|
||||
virtual uint16_t* getNvlmLandmarks(uint32_t /*size*/) { return nullptr; }
|
||||
virtual void appendNvlmLandmark(uint16_t /*i*/) {}
|
||||
|
||||
virtual void setNvlmRightContourSize(uint32_t /*n*/) {} /* The tracked right jawline contour */
|
||||
virtual uint32_t getNvlmRightContourSize() const { return 0; }
|
||||
virtual uint16_t* getNvlmRightContour(uint32_t /*size*/) { return nullptr; }
|
||||
virtual void appendNvlmRightContour(uint16_t /*i*/) {}
|
||||
|
||||
virtual void setNvlmLeftContourSize(uint32_t /*n*/) {}; /* The tracked left jawline contour */
|
||||
virtual uint32_t getNvlmLeftContourSize() const { return 0; }
|
||||
virtual uint16_t* getNvlmLeftContour(uint32_t /*size*/) { return nullptr; }
|
||||
virtual void appendNvlmLeftContour(uint16_t /*i*/) {}
|
||||
|
||||
virtual void setNumPartitions(uint32_t /*n*/) {}
|
||||
virtual void setPartitionName(uint32_t /*i*/, const char* /*name*/) {}
|
||||
virtual void setPartitionMaterialName(uint32_t /*i*/, const char* /*name*/) {}
|
||||
virtual void setPartition(uint32_t /*i*/, uint32_t /*faceIndex*/, uint32_t /*numFaces*/,
|
||||
uint32_t /*vertexIndex*/, uint32_t /*numVertices*/, int32_t /*smoothingGroup*/) {}
|
||||
virtual uint32_t getNumPartitions() const { return 0; }
|
||||
virtual const char* getPartitionName(uint32_t /*i*/) const { return nullptr; }
|
||||
virtual const char* getPartitionMaterialName(uint32_t /*i*/) const { return nullptr; }
|
||||
virtual int16_t getPartition(uint32_t /*i*/, uint32_t* faceIndex, uint32_t* numFaces, uint32_t* vertexIndex,
|
||||
uint32_t* numVertices, int32_t* smoothingGroup) const
|
||||
{ if (faceIndex) *faceIndex = 0u; if (numFaces) *numFaces = 0u; if (vertexIndex) *vertexIndex = 0u;
|
||||
if (numVertices) *numVertices = 0u; if (smoothingGroup) *smoothingGroup = -1; return /*partitionIndex*/-1;
|
||||
}
|
||||
|
||||
|
||||
/* Const accessors do not have the ability to resize. */
|
||||
const float* getShapeMean() const { return const_cast<FaceIOAdapter*>(this)->getShapeMean(0); }
|
||||
const float* getShapeModes() const { return const_cast<FaceIOAdapter*>(this)->getShapeModes(0, 0); }
|
||||
const float* getShapeEigenvalues() const { return const_cast<FaceIOAdapter*>(this)->getShapeEigenvalues(0); }
|
||||
const float* getColorMean() const { return const_cast<FaceIOAdapter*>(this)->getColorMean(0); }
|
||||
const float* getColorModes() const { return const_cast<FaceIOAdapter*>(this)->getColorModes(0, 0); }
|
||||
const float* getColorEigenvalues() const { return const_cast<FaceIOAdapter*>(this)->getColorEigenvalues(0); }
|
||||
const float* getTextureCoordinates() const { return const_cast<FaceIOAdapter*>(this)->getTextureCoordinates(0); }
|
||||
const uint16_t* getTriangleList() const { return const_cast<FaceIOAdapter*>(this)->getTriangleList(0); }
|
||||
const float* getBlendShape(uint32_t i) const { return const_cast<FaceIOAdapter*>(this)->getBlendShape(i, 0); }
|
||||
const uint16_t* getIbugLandmarkMappings() const { return const_cast<FaceIOAdapter*>(this)->getIbugLandmarkMappings(0); }
|
||||
const uint16_t* getIbugRightContour() const { return const_cast<FaceIOAdapter*>(this)->getIbugRightContour(0); }
|
||||
const uint16_t* getIbugLeftContour() const { return const_cast<FaceIOAdapter*>(this)->getIbugLeftContour(0); }
|
||||
const uint16_t* getModelRightContour() const { return const_cast<FaceIOAdapter*>(this)->getModelRightContour(0); }
|
||||
const uint16_t* getModelLeftContour() const { return const_cast<FaceIOAdapter*>(this)->getModelLeftContour(0); }
|
||||
const uint16_t* getAdjacentFaces() const { return const_cast<FaceIOAdapter*>(this)->getAdjacentFaces(0); }
|
||||
const uint16_t* getAdjacentVertices() const { return const_cast<FaceIOAdapter*>(this)->getAdjacentVertices(0); }
|
||||
const uint16_t* getNvlmLandmarks() const { return const_cast<FaceIOAdapter*>(this)->getNvlmLandmarks(0); }
|
||||
const uint16_t* getNvlmRightContour() const { return const_cast<FaceIOAdapter*>(this)->getNvlmRightContour(0); }
|
||||
const uint16_t* getNvlmLeftContour() const { return const_cast<FaceIOAdapter*>(this)->getNvlmLeftContour(0); }
|
||||
};
|
||||
|
||||
/** Write the face model as an NVF model.
|
||||
* @param[in] fac the face I/O adapter for the target data structure.
|
||||
* @param[in] fileName the desired name of the output file.
|
||||
* @return kIOErrNone if the file was written completed successfully.
|
||||
* @return kIOErrFileOpen if the file could not be opened.
|
||||
* @return kIOErrWrite if an error occurred while writing the file.
|
||||
*/
|
||||
FaceIOErr WriteNVFFaceModel(FaceIOAdapter* fac, const char* fileName);
|
||||
|
||||
/** Read a face model from an NVF file.
|
||||
* @param[in] fileName the name of the file to be read.
|
||||
* @param[in,out] fac the face I/O adapter for the target data structure.
|
||||
* @return kIOErrNone if the file was read successfully.
|
||||
* @return kIOErrFileNotFound if the file was not found .
|
||||
* @return kIOErrFileOpen if the file could not be opened.
|
||||
* @return kIOErrRead if an error occurred while reading the file.
|
||||
* @return kIOErrSyntax if a syntax error has been encountered while reading the file.
|
||||
*/
|
||||
FaceIOErr ReadNVFFaceModel(const char* fileName, FaceIOAdapter* fac);
|
||||
|
||||
/** Read a face model from five OES files.
|
||||
* @param[in] shape the name of the shape file to be read.
|
||||
* @param[in] ibugNumandmarks the number of Ibug landmarks.
|
||||
* @param[in] blendShapes the name of the blend shapes file to be read.
|
||||
* @param[in] contours the name of the contours file to be read.
|
||||
* @param[in] topology the name of the topology file to be read.
|
||||
* @param[in,out] fac the face I/O adapter for the target data structure.
|
||||
* @return kIOErrNone if the file was read successfully.
|
||||
* @return kIOErrFileNotFound if the file was not found .
|
||||
* @return kIOErrFileOpen if the file could not be opened.
|
||||
* @return kIOErrRead if an error occurred while reading the file.
|
||||
* @return kIOErrSyntax if a syntax error has been encountered while reading the file.
|
||||
*/
|
||||
FaceIOErr ReadEOSFaceModel(const char* shape, const unsigned ibugNumLandmarks, const char* blendShapes,
|
||||
const char* contours, const char* topology, FaceIOAdapter* fac);
|
||||
|
||||
/** Write the face model as a JSON model.
|
||||
* @param[in] fac the face I/O adapter for the target data structure.
|
||||
* @param[in] fileName the desired name of the output file.
|
||||
* If NULL is supplied, it is written to the standard output.
|
||||
* @return kIOErrNone if the file was written completed successfully.
|
||||
* @return kIOErrFileOpen if the file could not be opened.
|
||||
* @return kIOErrWrite if an error occurred while writing the file.
|
||||
*/
|
||||
FaceIOErr PrintJSONFaceModel(FaceIOAdapter* fac, const char* fileName);
|
||||
|
||||
#endif /* __FACE_IO__ */
|
||||
314
samples/ExpressionApp/BackEndOpenGL/GLMaterial.cpp
Normal file
314
samples/ExpressionApp/BackEndOpenGL/GLMaterial.cpp
Normal file
@@ -0,0 +1,314 @@
|
||||
/*###############################################################################
|
||||
#
|
||||
# Copyright 2016-2021 NVIDIA Corporation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
###############################################################################*/
|
||||
|
||||
#include "GLMaterial.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define strcasecmp _stricmp
|
||||
#endif // _MSC_VER
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
///// UTILITY FUNCTIONS /////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
static void SplitString(const std::string &s, std::vector<std::string>&tokens) {
|
||||
tokens.clear();
|
||||
std::string token;
|
||||
std::istringstream tokenStream(s);
|
||||
while (std::getline(tokenStream, token, ' ')) {
|
||||
if (0 == token.size())
|
||||
continue;
|
||||
tokens.push_back(token);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void SetColorFromStringArray(GLSpectrum3f& color, std::string* strs) {
|
||||
color.r = strtof(strs[0].c_str(), nullptr);
|
||||
color.g = strtof(strs[1].c_str(), nullptr);
|
||||
color.b = strtof(strs[2].c_str(), nullptr);
|
||||
}
|
||||
|
||||
|
||||
static bool StrToBool(const char* str) {
|
||||
return strcasecmp(str, "true") == 0 ||
|
||||
strcasecmp(str, "on") == 0 ||
|
||||
strcasecmp(str, "yes") == 0 ||
|
||||
strcasecmp(str, "1") == 0;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
///// GLMaterial /////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
GLMaterial::~GLMaterial() {
|
||||
//if (diffuseTexture)
|
||||
// delete diffuseTexture;
|
||||
}
|
||||
|
||||
|
||||
GLMaterial::GLMaterial() {
|
||||
clear();
|
||||
}
|
||||
|
||||
|
||||
GLMaterial::GLMaterial(const GLMaterial& mtl) {
|
||||
*this = mtl;
|
||||
}
|
||||
|
||||
|
||||
void GLMaterial::setTextureFile(const char* file) {
|
||||
if (file) diffuseTextureFile = file;
|
||||
else diffuseTextureFile.clear();
|
||||
}
|
||||
|
||||
|
||||
void GLMaterial::clear() {
|
||||
diffuseColor.set(1.f, 1.f, 1.f);
|
||||
ambientColor.set(0.f, 0.f, 0.f);
|
||||
specularColor.set(0.f, 0.f, 0.f);
|
||||
transmissionColor.set(0.f, 0.f, 0.f);
|
||||
specularExponent = 0.f;
|
||||
opacity = 1.f;
|
||||
diffuseTexture = nullptr;
|
||||
diffuseTextureFile.clear();
|
||||
illuminationModel = kUnspecifiedIlluminationModel;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
///// GLMaterialLibrary /////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
struct GLMaterialName {
|
||||
GLMaterial mtl;
|
||||
std::string name;
|
||||
GLMaterialName() {}
|
||||
GLMaterialName(const GLMaterial& matParam, const char* nameParam) {
|
||||
mtl = matParam;
|
||||
name = nameParam;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct GLMaterialLibrary::Impl {
|
||||
std::vector<GLMaterialName> lib;
|
||||
};
|
||||
|
||||
|
||||
GLMaterialLibrary::GLMaterialLibrary() {
|
||||
pimpl = new Impl;
|
||||
}
|
||||
|
||||
|
||||
GLMaterialLibrary::~GLMaterialLibrary() {
|
||||
delete pimpl;
|
||||
}
|
||||
|
||||
|
||||
void GLMaterialLibrary::clear() {
|
||||
pimpl->lib.clear();
|
||||
}
|
||||
|
||||
|
||||
unsigned GLMaterialLibrary::numMaterials() const {
|
||||
return unsigned(pimpl->lib.size());
|
||||
}
|
||||
|
||||
|
||||
NvCV_Status GLMaterialLibrary::addMaterial(const GLMaterial& mtrl, const char* name) {
|
||||
if (getMaterial(name))
|
||||
return NVCV_ERR_SELECTOR;
|
||||
pimpl->lib.emplace_back(mtrl, name);
|
||||
return NVCV_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
NvCV_Status GLMaterialLibrary::addDiffuseMaterial(const GLSpectrum3f& color, const char* name) {
|
||||
GLMaterial mtrl;
|
||||
if (getMaterial(name))
|
||||
return NVCV_ERR_SELECTOR;
|
||||
mtrl.diffuseColor = color;
|
||||
pimpl->lib.emplace_back(mtrl, name);
|
||||
return NVCV_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
NvCV_Status GLMaterialLibrary::removeMaterial(const char* name) {
|
||||
unsigned i, n;
|
||||
for (i = 0, n = unsigned(pimpl->lib.size()); i < n; ++i) {
|
||||
if (name == pimpl->lib[i].name) {
|
||||
pimpl->lib.erase(pimpl->lib.begin() + i);
|
||||
return NVCV_SUCCESS;
|
||||
}
|
||||
}
|
||||
return NVCV_ERR_FEATURENOTFOUND;
|
||||
}
|
||||
|
||||
|
||||
GLMaterial* GLMaterialLibrary::newMaterial(const char* name) {
|
||||
if (getMaterial(name))
|
||||
return nullptr;
|
||||
size_t z = pimpl->lib.size();
|
||||
pimpl->lib.resize(z + 1);
|
||||
GLMaterialName* mtn = &pimpl->lib[z];
|
||||
mtn->name = name;
|
||||
return &mtn->mtl;
|
||||
}
|
||||
|
||||
|
||||
const GLMaterial* GLMaterialLibrary::getMaterial(const char* name) const {
|
||||
GLMaterialName *mp, *mEnd;
|
||||
|
||||
for (mEnd = (mp = pimpl->lib.data()) + pimpl->lib.size(); mp < mEnd; ++mp)
|
||||
if (name == mp->name)
|
||||
return &mp->mtl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
const GLMaterial* GLMaterialLibrary::getMaterial(unsigned i, const char** name) const {
|
||||
if (i < pimpl->lib.size()) {
|
||||
const GLMaterialName& matn = pimpl->lib[i];
|
||||
if (name)
|
||||
*name = matn.name.c_str();
|
||||
return &matn.mtl;
|
||||
}
|
||||
if (name)
|
||||
name = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
NvCV_Status GLMaterialLibrary::read(const char* name) {
|
||||
unsigned lineNum;
|
||||
std::vector<std::string> tokens;
|
||||
GLMaterial *mtl = nullptr;
|
||||
|
||||
clear();
|
||||
std::ifstream fd(name);
|
||||
if (!fd.is_open())
|
||||
return NVCV_ERR_READ;
|
||||
std::string line;
|
||||
|
||||
for (lineNum = 1; std::getline(fd, line); ++lineNum) {
|
||||
SplitString(line, tokens);
|
||||
if (!tokens.size())
|
||||
continue;
|
||||
if (tokens[0][0] == '#') {
|
||||
continue;
|
||||
}
|
||||
if (tokens[0] == "newmtl" && 2 == tokens.size()) {
|
||||
mtl = newMaterial(tokens[1].c_str());
|
||||
continue;
|
||||
}
|
||||
if (tokens[0] == "Ka" && 4 == tokens.size()) {
|
||||
SetColorFromStringArray(mtl->ambientColor, &tokens[1]);
|
||||
continue;
|
||||
}
|
||||
if (tokens[0] == "Kd" && 4 == tokens.size()) {
|
||||
SetColorFromStringArray(mtl->diffuseColor, &tokens[1]);
|
||||
continue;
|
||||
}
|
||||
if (tokens[0] == "Ks" && 4 == tokens.size()) {
|
||||
SetColorFromStringArray(mtl->specularColor, &tokens[1]);
|
||||
continue;
|
||||
}
|
||||
if (tokens[0] == "Tf" && 4 == tokens.size()) {
|
||||
SetColorFromStringArray(mtl->transmissionColor, &tokens[1]);
|
||||
continue;
|
||||
}
|
||||
if (tokens[0] == "illum" && 2 == tokens.size()) {
|
||||
mtl->illuminationModel = (unsigned char)strtol(tokens[1].c_str(), nullptr, 10);
|
||||
continue;
|
||||
}
|
||||
if (tokens[0] == "d" && 2 == tokens.size()) {
|
||||
/* We don't support "_d" */
|
||||
mtl->opacity = strtof(tokens[1].c_str(), nullptr);
|
||||
continue;
|
||||
}
|
||||
if (tokens[0] == "Ns" && 2 == tokens.size()) { /* We don't support "-d" */
|
||||
mtl->specularExponent = strtof(tokens[1].c_str(), nullptr);
|
||||
continue;
|
||||
}
|
||||
if (tokens[0] == "sharpness") { /* We don't support sharpness */
|
||||
continue;
|
||||
}
|
||||
if (tokens[0] == "Ni") { /* We don't support index of refraction */
|
||||
continue;
|
||||
}
|
||||
if (tokens[0] == "map_Kd") {
|
||||
for (unsigned i = 1; i < tokens.size(); ++i) {
|
||||
if (tokens[i] == "-blendu") {
|
||||
++i;
|
||||
}
|
||||
else if (tokens[i] == "-blendv") {
|
||||
++i;
|
||||
}
|
||||
else if (tokens[i] == "-cc") {
|
||||
++i;
|
||||
}
|
||||
else if (tokens[i] == "-clamp") {
|
||||
++i;
|
||||
}
|
||||
else if (tokens[i] == "-mm") {
|
||||
++i;
|
||||
}
|
||||
else if (tokens[i] == "-o") {
|
||||
i += 3;
|
||||
}
|
||||
else if (tokens[i] == "-s") {
|
||||
i += 3;
|
||||
}
|
||||
else if (tokens[i] == "-t") {
|
||||
i += 3;
|
||||
}
|
||||
else if (tokens[i] == "-texres") {
|
||||
++i;
|
||||
}
|
||||
else if (tokens[i][0] == '-') {
|
||||
printf("Unknown option: \"%s\"\n", tokens[i].c_str());
|
||||
}
|
||||
else {
|
||||
mtl->diffuseTextureFile = tokens[i];
|
||||
}
|
||||
}
|
||||
if (mtl->diffuseTextureFile.empty())
|
||||
printf("No diffuse texture given on line %u\n", lineNum);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return NVCV_SUCCESS;
|
||||
}
|
||||
143
samples/ExpressionApp/BackEndOpenGL/GLMaterial.h
Normal file
143
samples/ExpressionApp/BackEndOpenGL/GLMaterial.h
Normal file
@@ -0,0 +1,143 @@
|
||||
/*###############################################################################
|
||||
#
|
||||
# Copyright 2016-2021 NVIDIA Corporation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
###############################################################################*/
|
||||
|
||||
#ifndef __GLMATERIAL_H
|
||||
#define __GLMATERIAL_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "GLSpectrum.h"
|
||||
#include "nvCVStatus.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Specification for light transport on the surfaces of objects.
|
||||
/// @todo Store the provenance of the material?
|
||||
/// @todo Should we store the name, too?
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class GLMaterial {
|
||||
public:
|
||||
/// Default constructor.
|
||||
GLMaterial();
|
||||
|
||||
/// Copy constructor.
|
||||
/// @param[in] mtl the material to copy.
|
||||
/// @note a copy is made of the diffuseTextureFile, if not NULL.
|
||||
GLMaterial(const GLMaterial& mtl);
|
||||
|
||||
/// Destructor.
|
||||
/// @note the diffuseTextureFile string is disposed.
|
||||
/// @note the opaque diffuseTexture is *not* disposed.
|
||||
~GLMaterial();
|
||||
|
||||
/// Assignment.
|
||||
/// This copies the diffuseTextureFile, if not NULL>
|
||||
/// @param[in] mtl the material to copy (RHS).
|
||||
/// @return a reference to the LHS of the assignment.
|
||||
//GLMaterial& operator=(const GLMaterial& mtl); // default implementation
|
||||
|
||||
/// Reset as it was in the constructor: 0 materials.
|
||||
void clear();
|
||||
|
||||
/// Use this to set the diffuseTextureFile, by making a copy of the specified string.
|
||||
/// @param[in] fileName the file name of the texture file. A copy of the string is made.
|
||||
void setTextureFile(const char* fileName);
|
||||
|
||||
GLSpectrum3f ambientColor; ///< The ambient color, in [0,1].
|
||||
GLSpectrum3f diffuseColor; ///< The diffuse color, in [0,1].
|
||||
GLSpectrum3f specularColor; ///< The specular color, in [0,1].
|
||||
GLSpectrum3f transmissionColor; ///< The transmission color, in [0,1].
|
||||
float specularExponent; ///< The specular exponent, in [1, 10000]
|
||||
float opacity; ///< The opacity, in [0,1].
|
||||
std::string diffuseTextureFile; ///< The name of the diffuse texture file. Set through setTextureFile().
|
||||
void *diffuseTexture; ///< User-defined texture representation -- unmanaged.
|
||||
unsigned char illuminationModel; ///< The illumination model, in [0,10], or kUnspecifiedIlluminationModel.
|
||||
static const int kUnspecifiedIlluminationModel = 255; ///< The value to be used for an unspecified illumination model.
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Library of material specifications for surface light transport.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class GLMaterialLibrary {
|
||||
public:
|
||||
/// Constructor.
|
||||
GLMaterialLibrary();
|
||||
|
||||
/// Destructor.
|
||||
~GLMaterialLibrary();
|
||||
|
||||
/// Reset as it was in the constructor: 0 materials.
|
||||
void clear();
|
||||
|
||||
/// Read from a file
|
||||
NvCV_Status read(const char* name);
|
||||
|
||||
/// Add a new material to the library. A copy is made both of material and name.
|
||||
/// @param[in] mtrl the material to be added to the library.
|
||||
/// @param[in] name the name of the material, for future access.
|
||||
/// @return keErrNone if the operation was completed successfully.
|
||||
/// @return keErrDuplicate if a material of the same name is already found in the library.
|
||||
NvCV_Status addMaterial(const GLMaterial& mtrl, const char* name);
|
||||
|
||||
/// Add a new diffuse material to the library. A copy is made both of the name.
|
||||
/// @param[in] color the diffuse color to be added to the library.
|
||||
/// @param[in] name the name of the material, for future access.
|
||||
/// @return keErrNone if the operation was completed successfully.
|
||||
/// @return keErrDuplicate if a material of the same name is already found in the library.
|
||||
NvCV_Status addDiffuseMaterial(const GLSpectrum3f& color, const char* name);
|
||||
|
||||
/// Remove a material.
|
||||
/// @param[in] name the name of the material to remove.
|
||||
/// @return keErrNone if the operation was completed successfully.
|
||||
NvCV_Status removeMaterial(const char* name);
|
||||
|
||||
/// Create a new material with the given name.
|
||||
/// @param[in] name the name of the material, for future access.
|
||||
/// @return a pointer to the new material in the database, if the operation was completed successfully.
|
||||
/// @return NULL, if a material of the same name is already found in the library.
|
||||
GLMaterial* newMaterial(const char* name);
|
||||
|
||||
/// Get the number of materials in the material library.
|
||||
/// @return the number of materials.
|
||||
unsigned numMaterials() const;
|
||||
|
||||
/// Get the material with the specified name.
|
||||
/// @param[in] name the name of the material to get.
|
||||
/// @return the specified material, or NULL if the material was not found.
|
||||
const GLMaterial* getMaterial(const char* name) const;
|
||||
|
||||
/// Get the material with the specified index.
|
||||
/// @param[in] i the index of the material to get.
|
||||
/// @param[out] name the name of the material with the specified index (can be NULL).
|
||||
/// @return the specified material, or NULL if the material was not found.
|
||||
const GLMaterial* getMaterial(unsigned i, const char** name = nullptr) const;
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
Impl *pimpl;
|
||||
};
|
||||
|
||||
|
||||
#endif /* __GLMATERIAL_H */
|
||||
624
samples/ExpressionApp/BackEndOpenGL/GLMesh.cpp
Normal file
624
samples/ExpressionApp/BackEndOpenGL/GLMesh.cpp
Normal file
@@ -0,0 +1,624 @@
|
||||
/*###############################################################################
|
||||
#
|
||||
# Copyright 2021 NVIDIA Corporation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
###############################################################################*/
|
||||
|
||||
#include "GLMesh.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// ////
|
||||
//// GLMesh ////
|
||||
//// ////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
// Note: we assume that the transformation is affine, i.e. that M[3] = M[7] = M[11] = 0 and M[15] = 1.
|
||||
static void TransformPoints(const glm::mat4x4& M, unsigned numPts, const glm::vec3 *pts, glm::vec3 *xPts) {
|
||||
for (; numPts--; ++pts, ++xPts) { // NB it is better to do the dot products in double precision
|
||||
glm::vec3 q; // Use an intermediate variable to allow transformation in-place.
|
||||
q.x = M[0][0] * pts->x + M[1][0] * pts->y + M[2][0] * pts->z + M[3][0];
|
||||
q.y = M[0][1] * pts->x + M[1][1] * pts->y + M[2][1] * pts->z + M[3][1];
|
||||
q.z = M[0][2] * pts->x + M[1][2] * pts->y + M[2][2] * pts->z + M[3][2];
|
||||
*xPts = q;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Note: We assume here that the transformation is isotropic;
|
||||
// otherwise we would need to transform by the inverse transpose of the upper left.
|
||||
static void TransformNormals(const glm::mat4x4& M, unsigned numPts, const glm::vec3 *pts, glm::vec3 *xPts) {
|
||||
for (; numPts--; ++pts, ++xPts) { // NB it is better to do the dot products in double precision
|
||||
glm::vec3 q; // Use an intermediate variable to allow transformation in-place.
|
||||
q.x = M[0][0] * pts->x + M[1][0] * pts->y + M[2][0] * pts->z;
|
||||
q.y = M[0][1] * pts->x + M[1][1] * pts->y + M[2][1] * pts->z;
|
||||
q.z = M[0][2] * pts->x + M[1][2] * pts->y + M[2][2] * pts->z;
|
||||
*xPts = glm::normalize(q);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// GLMesh API
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
GLMesh::GLMesh(const GLMesh& mesh) {
|
||||
m_faceVertexCount = mesh.m_faceVertexCount;
|
||||
m_vertices = mesh.m_vertices;
|
||||
m_vertexIndices = mesh.m_vertexIndices;
|
||||
m_texCoords = mesh.m_texCoords;
|
||||
m_textureIndices = mesh.m_textureIndices;
|
||||
m_normals = mesh.m_normals;
|
||||
m_normalIndices = mesh.m_normalIndices;
|
||||
m_faceNormals = mesh.m_faceNormals;
|
||||
|
||||
}
|
||||
|
||||
GLMesh::GLMesh() { }
|
||||
GLMesh::~GLMesh() { }
|
||||
void GLMesh::resizeVertices(unsigned n) { m_vertices.resize(n); }
|
||||
void GLMesh::resizeTexCoords(unsigned n) {
|
||||
m_texCoords.resize(n);
|
||||
m_textureIndices.resize(n ? unsigned(m_vertexIndices.size()) : 0);
|
||||
}
|
||||
void GLMesh::resizeNormals(unsigned n) {
|
||||
m_normals.resize(n);
|
||||
m_normalIndices.resize(n ? unsigned(m_vertexIndices.size()) : 0);
|
||||
}
|
||||
void GLMesh::resizeFaces(unsigned n) { m_faceVertexCount.resize(n); }
|
||||
void GLMesh::resizeTriangles(unsigned n) { m_faceVertexCount.clear(); m_faceVertexCount.resize(n, 3); }
|
||||
void GLMesh::resizeVertexIndices(unsigned n) {
|
||||
m_vertexIndices.resize(n);
|
||||
m_textureIndices.resize(m_texCoords.size() ? n : 0);
|
||||
m_normalIndices.resize(m_normals.size() ? n : 0);
|
||||
}
|
||||
void GLMesh::resizeDualIndices(unsigned n) {
|
||||
m_dualIndices.resize(n);
|
||||
m_vertexFaceCount.resize(m_vertices.size());
|
||||
}
|
||||
void GLMesh::useFaceNormals(bool yes) { m_faceNormals.resize(yes ? numFaces() : 0); }
|
||||
|
||||
unsigned GLMesh::numVertices() const { return unsigned(m_vertices.size()); }
|
||||
unsigned GLMesh::numTexCoords() const { return unsigned(m_texCoords.size()); }
|
||||
unsigned GLMesh::numNormals() const { return unsigned(m_normals.size()); }
|
||||
unsigned GLMesh::numFaces() const { return unsigned(m_faceVertexCount.size()); }
|
||||
unsigned GLMesh::numIndices() const { return unsigned(m_vertexIndices.size()); }
|
||||
|
||||
|
||||
void GLMesh::initPartitions() {
|
||||
m_partitions.resize(1);
|
||||
Partition& pt = m_partitions[0];
|
||||
pt.faceIndex = 0;
|
||||
pt.vertexIndex = 0;
|
||||
pt.name.clear();
|
||||
pt.materialName.clear();
|
||||
}
|
||||
|
||||
|
||||
NvCV_Status GLMesh::startPartition(const char *name, const char *material, int smooth) {
|
||||
if (name)
|
||||
for (const GLMesh::Partition& p : m_partitions)
|
||||
if (p.name == name)
|
||||
return NVCV_ERR_SELECTOR;
|
||||
|
||||
unsigned i = unsigned(m_partitions.size());
|
||||
GLMesh::Partition *pt = &m_partitions[i - 1];
|
||||
|
||||
if (m_faceVertexCount.size() != pt->faceIndex) {
|
||||
m_partitions.resize(i + 1);
|
||||
pt = &m_partitions[i];
|
||||
pt->faceIndex = unsigned(m_faceVertexCount.size());
|
||||
pt->vertexIndex = unsigned(m_vertexIndices.size());
|
||||
}
|
||||
if (name) pt->name = name;
|
||||
if (material) pt->materialName = material;
|
||||
if (smooth >= 0) pt->smooth = smooth;
|
||||
return NVCV_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
NvCV_Status GLMesh::partitionMesh(unsigned numPartitions, const GLMesh::Partition *srcPartition) {
|
||||
m_partitions.resize(numPartitions);
|
||||
for (unsigned i = 0; i < numPartitions; ++i, ++srcPartition) {
|
||||
if (srcPartition->faceIndex >= m_faceVertexCount.size()) {
|
||||
initPartitions();
|
||||
return NVCV_ERR_MISMATCH;
|
||||
}
|
||||
|
||||
GLMesh::Partition& pt = m_partitions[i];
|
||||
pt.faceIndex = srcPartition->faceIndex;
|
||||
pt.vertexIndex = srcPartition->vertexIndex;
|
||||
pt.numFaces = srcPartition->numFaces;
|
||||
pt.numVertexIndices = srcPartition->numVertexIndices;
|
||||
pt.name = srcPartition->name;
|
||||
pt.materialName = srcPartition->materialName;
|
||||
}
|
||||
//computeStartingVertexIndices();
|
||||
|
||||
return NVCV_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
NvCV_Status GLMesh::updatePartition(unsigned i, const GLMesh::Partition& update) {
|
||||
if (i >= m_partitions.size())
|
||||
return NVCV_ERR_FEATURENOTFOUND;
|
||||
|
||||
GLMesh::Partition& pt = m_partitions[i];
|
||||
pt.faceIndex = update.faceIndex;
|
||||
pt.vertexIndex = update.vertexIndex;
|
||||
if (update.name.empty()) pt.name.clear();
|
||||
else pt.name = update.name;
|
||||
if (update.materialName.empty()) pt.materialName.clear();
|
||||
else pt.materialName = update.materialName;
|
||||
return NVCV_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void GLMesh::computeStartingVertexIndices() {
|
||||
unsigned vertIx;
|
||||
std::sort(m_partitions.begin(), m_partitions.end());
|
||||
const unsigned short *faceCount = m_faceVertexCount.data(), *lastFace;
|
||||
GLMesh::Partition *pt = m_partitions.data(), *lastPt = pt + m_partitions.size() - 1;
|
||||
for (vertIx = 0; pt != lastPt; ++pt) {
|
||||
pt->vertexIndex = vertIx;
|
||||
for (lastFace = faceCount + (pt[1].faceIndex - pt[0].faceIndex); faceCount != lastFace; ++faceCount)
|
||||
vertIx += *faceCount;
|
||||
}
|
||||
pt->vertexIndex = vertIx;
|
||||
}
|
||||
|
||||
|
||||
NvCV_Status GLMesh::getPartition(unsigned i, GLMesh::Partition& pt) const {
|
||||
if (i > m_partitions.size())
|
||||
return NVCV_ERR_FEATURENOTFOUND;
|
||||
pt = m_partitions[i];
|
||||
return NVCV_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
bool GLMesh::indicesMatch(const std::vector<unsigned short>& ivecA, const std::vector<unsigned short>& ivecB) {
|
||||
size_t n = ivecA.size();
|
||||
const unsigned short *a = ivecA.data(),
|
||||
*b = ivecB.data();
|
||||
|
||||
if (ivecB.size() != n)
|
||||
return false;
|
||||
for (; n--; ++a, ++b)
|
||||
if (*a != *b)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void GLMesh::assureConsistency() {
|
||||
if (m_texCoords.size() && (m_textureIndices.size() != m_vertexIndices.size()))
|
||||
m_textureIndices.resize(m_vertexIndices.size());
|
||||
if (m_normals.size() && (m_normalIndices.size() != m_vertexIndices.size()))
|
||||
m_normalIndices.resize(m_vertexIndices.size());
|
||||
if (m_faceNormals.size() && (m_faceNormals.size() != (m_vertexIndices.size() / 3)))
|
||||
m_faceNormals.resize(m_vertexIndices.size() / 3);
|
||||
}
|
||||
|
||||
|
||||
void GLMesh::clear() {
|
||||
m_faceVertexCount.resize(0);
|
||||
m_vertices.resize(0);
|
||||
m_texCoords.resize(0);
|
||||
m_normals.resize(0);
|
||||
m_faceNormals.resize(0);
|
||||
m_vertexIndices.resize(0);
|
||||
m_textureIndices.resize(0);
|
||||
m_normalIndices.resize(0);
|
||||
initPartitions();
|
||||
}
|
||||
|
||||
|
||||
glm::vec3* GLMesh::getVertices() {
|
||||
return m_vertices.data();
|
||||
}
|
||||
|
||||
glm::vec2* GLMesh::getTexCoords() {
|
||||
assureConsistency();
|
||||
return m_texCoords.size() ? m_texCoords.data() : nullptr;
|
||||
}
|
||||
|
||||
glm::vec3* GLMesh::getNormals() {
|
||||
assureConsistency();
|
||||
return m_normals.size() ? m_normals.data() : nullptr;
|
||||
}
|
||||
|
||||
glm::vec3* GLMesh::getFaceNormals() {
|
||||
assureConsistency();
|
||||
return m_faceNormals.size() ? m_faceNormals.data() : nullptr;
|
||||
}
|
||||
|
||||
const glm::vec3* GLMesh::getVertices() const { return const_cast<GLMesh*>(this)->getVertices(); }
|
||||
const glm::vec2* GLMesh::getTexCoords() const { return const_cast<GLMesh*>(this)->getTexCoords(); }
|
||||
const glm::vec3* GLMesh::getNormals() const { return const_cast<GLMesh*>(this)->getNormals(); }
|
||||
const glm::vec3* GLMesh::getFaceNormals() const { return const_cast<GLMesh*>(this)->getFaceNormals(); }
|
||||
|
||||
unsigned short* GLMesh::getFaceVertexCounts() { return m_faceVertexCount.data(); }
|
||||
unsigned short* GLMesh::getVertexIndices() { return m_vertexIndices.data(); }
|
||||
unsigned short* GLMesh::getTextureIndices() {
|
||||
return m_textureIndices.size() ? m_textureIndices.data() : nullptr;
|
||||
}
|
||||
unsigned short* GLMesh::getNormalIndices() {
|
||||
return m_normalIndices.size() ? m_normalIndices.data() : nullptr;
|
||||
}
|
||||
const unsigned short* GLMesh::getFaceVertexCounts() const { return m_faceVertexCount.data(); }
|
||||
const unsigned short* GLMesh::getVertexIndices() const { return m_vertexIndices.data(); }
|
||||
const unsigned short* GLMesh::getTextureIndices() const { return const_cast<GLMesh*>(this)->getTextureIndices(); }
|
||||
const unsigned short* GLMesh::getNormalIndices() const { return const_cast<GLMesh*>(this)->getNormalIndices(); }
|
||||
|
||||
unsigned short* GLMesh::getVertexFaceCounts() { return m_vertexFaceCount.data(); }
|
||||
unsigned short* GLMesh::getDualIndices() {
|
||||
return m_dualIndices.size() ? m_dualIndices.data() : nullptr;
|
||||
}
|
||||
const unsigned short* GLMesh::getVertexFaceCounts() const { return const_cast<GLMesh*>(this)->getVertexFaceCounts(); }
|
||||
const unsigned short* GLMesh::getDualIndices() const { return const_cast<GLMesh*>(this)->getDualIndices(); }
|
||||
|
||||
|
||||
void GLMesh::addVertex(float x, float y, float z) { m_vertices.emplace_back(glm::vec3{ x, y, z }); }
|
||||
void GLMesh::addTexCoord(float u, float v) { m_texCoords.emplace_back(glm::vec2{ u, v }); }
|
||||
void GLMesh::addNormal(float x, float y, float z) { m_normals.emplace_back(glm::vec3{ x, y, z }); }
|
||||
|
||||
void GLMesh::addVertices(unsigned numVertices, const float *vertices) {
|
||||
size_t preVertices = m_vertices.size();
|
||||
m_vertices.resize(preVertices + numVertices);
|
||||
memcpy(m_vertices.data() + preVertices, vertices, numVertices * sizeof(*m_vertices.data()));
|
||||
}
|
||||
|
||||
void GLMesh::addTexCoords(unsigned numTexCoords, const float *texCoords) {
|
||||
size_t preTexCoords = m_texCoords.size();
|
||||
m_texCoords.resize(preTexCoords + numTexCoords);
|
||||
memcpy(m_texCoords.data() + preTexCoords, texCoords, numTexCoords * sizeof(*m_texCoords.data()));
|
||||
}
|
||||
|
||||
void GLMesh::addNormals(unsigned numNormals, const float *normals) {
|
||||
size_t preNormals = m_normals.size();
|
||||
m_normals.resize(preNormals + numNormals);
|
||||
memcpy(m_normals.data() + preNormals, normals, numNormals * sizeof(*m_normals.data()));
|
||||
}
|
||||
|
||||
|
||||
void GLMesh::addFace(unsigned numVertices, const unsigned short *vertexIndices,
|
||||
const unsigned short *textureIndices, const unsigned short *normalIndices)
|
||||
{
|
||||
size_t n;
|
||||
m_faceVertexCount.push_back((unsigned short)numVertices);
|
||||
if (vertexIndices) {
|
||||
n = m_vertexIndices.size();
|
||||
m_vertexIndices.resize(n + numVertices);
|
||||
memcpy(m_vertexIndices.data() + n, vertexIndices, numVertices * sizeof(*vertexIndices));
|
||||
}
|
||||
if (textureIndices) {
|
||||
n = m_textureIndices.size();
|
||||
m_textureIndices.resize(n + numVertices);
|
||||
memcpy(m_textureIndices.data() + n, textureIndices, numVertices * sizeof(*textureIndices));
|
||||
}
|
||||
if (normalIndices) {
|
||||
n = m_normalIndices.size();
|
||||
m_normalIndices.resize(n + numVertices);
|
||||
memcpy(m_normalIndices.data() + n, normalIndices, numVertices * sizeof(*normalIndices));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GLMesh::addFaces(unsigned numFaces, unsigned numVerticesPerFace, const unsigned short *vertexIndices,
|
||||
const unsigned short *textureIndices, const unsigned short *normalIndices)
|
||||
{
|
||||
size_t numIndices = numFaces * numVerticesPerFace,
|
||||
indexBytes = numIndices * sizeof(*vertexIndices);
|
||||
size_t n;
|
||||
|
||||
n = m_faceVertexCount.size();
|
||||
m_faceVertexCount.resize(n + numFaces, (unsigned short)numVerticesPerFace);
|
||||
|
||||
if (vertexIndices) {
|
||||
n = m_vertexIndices.size();
|
||||
m_vertexIndices.resize(n + numIndices);
|
||||
memcpy(m_vertexIndices.data() + n, vertexIndices, indexBytes);
|
||||
}
|
||||
if (textureIndices) {
|
||||
n = m_textureIndices.size();
|
||||
m_textureIndices.resize(n + numIndices);
|
||||
memcpy(m_textureIndices.data() + n, textureIndices, indexBytes);
|
||||
}
|
||||
if (normalIndices) {
|
||||
n = m_normalIndices.size();
|
||||
m_normalIndices.resize(n + numIndices);
|
||||
memcpy(m_normalIndices.data() + n, normalIndices, indexBytes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool GLMesh::isTriMesh() const {
|
||||
unsigned n;
|
||||
const unsigned short *ix;
|
||||
|
||||
for (n = numFaces(), ix = getFaceVertexCounts(); n--; ++ix)
|
||||
if (*ix != 3)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool GLMesh::isQuadMesh() const {
|
||||
unsigned n;
|
||||
const unsigned short *ix;
|
||||
|
||||
for (n = numFaces(), ix = getFaceVertexCounts(); n--; ++ix)
|
||||
if (*ix != 4)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool GLMesh::isTriQuadMesh() const {
|
||||
unsigned n;
|
||||
const unsigned short *ix;
|
||||
|
||||
for (n = numFaces(), ix = getFaceVertexCounts(); n--; ++ix)
|
||||
if (*ix > 4)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void GLMesh::transform(const glm::mat4x4& M) {
|
||||
TransformPoints (M, unsigned(m_vertices.size()), m_vertices.data(), m_vertices.data());
|
||||
TransformNormals(M, unsigned(m_normals.size()), m_normals.data(), m_normals.data());
|
||||
TransformNormals(M, unsigned(m_faceNormals.size()), m_faceNormals.data(), m_faceNormals.data());
|
||||
}
|
||||
|
||||
|
||||
unsigned GLMesh::numPartitions() const {
|
||||
return unsigned(m_partitions.size());
|
||||
}
|
||||
|
||||
|
||||
void GLMesh::finishPartitioning() {
|
||||
computeStartingVertexIndices();
|
||||
}
|
||||
|
||||
|
||||
NvCV_Status GLMesh::setMaterial(const char *name) {
|
||||
Partition pt{};
|
||||
pt.materialName = name;
|
||||
return partitionMesh(1, &pt);
|
||||
}
|
||||
|
||||
|
||||
void GLMesh::computeFaceNormals(int weighted) {
|
||||
const glm::vec3 *vertices = m_vertices.data();
|
||||
const unsigned short *numVertices = m_faceVertexCount.data();
|
||||
glm::vec3 *nrm, *nrmEnd;
|
||||
const unsigned short *ix;
|
||||
const glm::vec3 *p0, *p1, *p2;
|
||||
glm::vec3 n;
|
||||
float mag;
|
||||
|
||||
useFaceNormals(true);
|
||||
nrm = getFaceNormals();
|
||||
nrmEnd = nrm + numFaces();
|
||||
ix = m_vertexIndices.data();
|
||||
|
||||
for (; nrm != nrmEnd; ++nrm, ix += *numVertices++) {
|
||||
if (3 == *numVertices) {
|
||||
p0 = &vertices[ix[0]];
|
||||
p1 = &vertices[ix[1]];
|
||||
p2 = &vertices[ix[2]];
|
||||
n = glm::cross((*p1 - *p0), (*p2 - *p0));
|
||||
}
|
||||
else {
|
||||
unsigned numPts = *numVertices;
|
||||
unsigned i;
|
||||
p0 = &vertices[ix[numPts - 1]];
|
||||
n = { 0.f, 0.f, 0.f };
|
||||
for (i = 0, p0 = &vertices[ix[numPts - 1]]; i < numPts; ++i, p0 = p1) {
|
||||
p1 = &vertices[ix[i]];
|
||||
n.x -= (p1->y - p0->y) * (p1->z + p0->z);
|
||||
n.y -= (p1->z - p0->z) * (p1->x + p0->x);
|
||||
n.z -= (p1->x - p0->x) * (p1->y + p0->y);
|
||||
}
|
||||
}
|
||||
mag = glm::length(n);
|
||||
if (weighted == 0) { if (mag) n /= mag; } // Unit vector
|
||||
else if (weighted > 0) { n *= 0.5f; } // Area-weighted normal
|
||||
else /* weighted < 0 */ { if (mag) n /= mag * mag * 0.25f; } // Inverse-area-weighted vector
|
||||
*nrm = n;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GLMesh::computeVertexNormals(int weighted) {
|
||||
glm::vec3 nrm;
|
||||
|
||||
computeFaceNormals(weighted);
|
||||
if (m_normals.size() != m_vertices.size()) {
|
||||
m_normals.resize(m_vertices.size());
|
||||
m_normalIndices = m_vertexIndices;
|
||||
}
|
||||
|
||||
if (m_vertexFaceCount.size() == m_vertices.size()) { // We already have the dual topology
|
||||
glm::vec3 *n, *nEnd;
|
||||
unsigned short *numPolys, *ix, *ixEnd;
|
||||
for (nEnd = (n = m_normals.data()) + m_vertexFaceCount.size(), numPolys = m_vertexFaceCount.data(), ix = m_dualIndices.data(); n != nEnd; ++n, ++numPolys) {
|
||||
for (ixEnd = ix + *numPolys, nrm = { 0.f, 0.f, 0.f }; ix != ixEnd; ++ix)
|
||||
nrm += m_faceNormals[*ix];
|
||||
*n = glm::normalize(nrm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GLMesh::BoundingBox::unionPoint(const glm::vec3& pt) { /* This works with NaN's */
|
||||
if (!(_box[0].x < pt.x)) _box[0].x = pt.x; if (!(_box[1].x > pt.x)) _box[1].x = pt.x;
|
||||
if (!(_box[0].y < pt.y)) _box[0].y = pt.y; if (!(_box[1].y > pt.y)) _box[1].y = pt.y;
|
||||
if (!(_box[0].z < pt.z)) _box[0].z = pt.z; if (!(_box[1].z > pt.z)) _box[1].z = pt.z;
|
||||
}
|
||||
|
||||
void GLMesh::BoundingBox::set(unsigned numPts, const glm::vec3 *pts) {
|
||||
_box[0] = pts[0];
|
||||
_box[1] = pts[0];
|
||||
for (++pts; --numPts; ++pts)
|
||||
unionPoint(*pts);
|
||||
}
|
||||
|
||||
void GLMesh::BoundingBox::set(unsigned numPts, const glm::vec3 *pts, const glm::mat4x4& M) {
|
||||
memset(this, -1, sizeof(*this)); // Set to NaN
|
||||
for (; numPts--; ++pts) {
|
||||
glm::vec3 q;
|
||||
TransformPoints(M, 1, pts, &q);
|
||||
unionPoint(q);
|
||||
}
|
||||
}
|
||||
|
||||
void GLMesh::BoundingSphere::set(unsigned numPts, const glm::vec3 *pts) {
|
||||
/* Ritter algorithm */
|
||||
float d, d0;
|
||||
glm::vec3 p0, p1;
|
||||
const glm::vec3 *pp, *pEnd = pts + numPts;
|
||||
|
||||
p0 = p1 = pts[0]; // Choose one point
|
||||
for (pp = pts + 1, d0 = 0; pp != pEnd; ++pp) {
|
||||
if (!(d0 > (d = glm::distance(p0, *pp)))) {
|
||||
d0 = d;
|
||||
p1 = *pp; // Find the furthest point
|
||||
}
|
||||
}
|
||||
p0 = p1; // Choose that furthest point
|
||||
for (pp = pts, d0 = 0; pp != pEnd; ++pp) {
|
||||
if (!(d0 > (d = glm::distance(p0, *pp)))) {
|
||||
d0 = d;
|
||||
p1 = *pp; // Find the furthest point from that
|
||||
}
|
||||
}
|
||||
|
||||
_radius = d0 * .5f; // Make a sphere ...
|
||||
_center = (p1 - p0) * .5f + p0; // ... from these furthest points
|
||||
|
||||
bool done;
|
||||
// Accommodate every outlier as we encounter them
|
||||
do {
|
||||
done = true;
|
||||
for (pp = pts; pp != pEnd; ++pp) { // Check that all points are in this sphere
|
||||
glm::vec3 v = *pp - _center;
|
||||
d0 = glm::length(v);
|
||||
if (d0 > _radius) { // If not, ...
|
||||
d = (d0 - _radius) * .5f;
|
||||
_center += v * (d / d0); // ... adjust the sphere center ...
|
||||
_radius += d; // ... and radius to accommodate this new point
|
||||
done = false;
|
||||
}
|
||||
}
|
||||
} while (!done);
|
||||
}
|
||||
|
||||
|
||||
void GLMesh::BoundingSphere::set(unsigned numPts, const glm::vec3 *pts, const glm::mat4x4& M) {
|
||||
std::vector<glm::vec3> xPts(numPts);
|
||||
TransformPoints(M, numPts, pts, xPts.data());
|
||||
set(numPts, xPts.data());
|
||||
}
|
||||
|
||||
void GLMesh::getBoundingBox(BoundingBox *bbox, const glm::mat4x4 *M) const {
|
||||
if (M) bbox->set(unsigned(m_vertices.size()), m_vertices.data(), *M);
|
||||
else bbox->set(unsigned(m_vertices.size()), m_vertices.data());
|
||||
}
|
||||
|
||||
|
||||
void GLMesh::getBoundingSphere(BoundingSphere *bsph, const glm::mat4x4 *M) const {
|
||||
if (M) bsph->set(unsigned(m_vertices.size()), m_vertices.data(), *M);
|
||||
else bsph->set(unsigned(m_vertices.size()), m_vertices.data());
|
||||
}
|
||||
|
||||
|
||||
unsigned GLMesh::notRenderable(unsigned /*options*/) const {
|
||||
unsigned result = RENDERABLE;
|
||||
|
||||
if (!isTriMesh())
|
||||
result |= NOT_TRIMESH;
|
||||
if (0 != m_textureIndices.size() && !indicesMatch(m_vertexIndices, m_textureIndices))
|
||||
result |= COMPLEX_TOPOLOGY;
|
||||
if (0 != m_normalIndices.size() && !indicesMatch(m_vertexIndices, m_normalIndices))
|
||||
result |= COMPLEX_TOPOLOGY;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
NvCV_Status GLMesh::append(const GLMesh& other, const glm::mat4x4 *M) {
|
||||
if ((!numTexCoords() != !other.numTexCoords()) || (!numNormals() != !other.numNormals()))
|
||||
return NVCV_ERR_MISMATCH;
|
||||
|
||||
unsigned indexOffset = numVertices(),
|
||||
thisCount = numIndices(),
|
||||
otherCount = other.numIndices(),
|
||||
i;
|
||||
|
||||
// Add vertices
|
||||
addVertices(other.numVertices(), &other.getVertices()->x);
|
||||
if (M)
|
||||
TransformPoints(*M, other.numVertices(), getVertices() + indexOffset, getVertices() + indexOffset);
|
||||
if (0 != (i = other.numTexCoords()))
|
||||
addTexCoords(i, &other.getTexCoords()->x);
|
||||
if (0 != (i = other.numNormals())) {
|
||||
addNormals(i, &other.getNormals()->x);
|
||||
if (M)
|
||||
TransformNormals(*M, other.numNormals(), getNormals() + indexOffset, getNormals() + indexOffset);
|
||||
}
|
||||
|
||||
{ // Add indices
|
||||
const unsigned short *nvx = other.getFaceVertexCounts(),
|
||||
*vix = other.getVertexIndices(),
|
||||
*tix = other.getTextureIndices(),
|
||||
*nix = other.getNormalIndices();
|
||||
for (i = other.numFaces(); i--; ++nvx) {
|
||||
addFace(*nvx, vix, tix, nix);
|
||||
vix += *nvx;
|
||||
if (tix) tix += *nvx;
|
||||
if (nix) nix += *nvx;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{ // Offset the new indices
|
||||
unsigned short *ix;
|
||||
for (i = otherCount, ix = getVertexIndices() + thisCount; i--; ++ix)
|
||||
*ix += (unsigned short)indexOffset;
|
||||
if (nullptr != (ix = getTextureIndices()))
|
||||
for (i = otherCount, ix += thisCount; i--; ++ix)
|
||||
*ix += (unsigned short)indexOffset;
|
||||
if (nullptr != (ix = getNormalIndices()))
|
||||
for (i = otherCount, ix += thisCount; i--; ++ix)
|
||||
*ix += (unsigned short)indexOffset;
|
||||
}
|
||||
|
||||
return NVCV_SUCCESS;
|
||||
}
|
||||
280
samples/ExpressionApp/BackEndOpenGL/GLMesh.h
Normal file
280
samples/ExpressionApp/BackEndOpenGL/GLMesh.h
Normal file
@@ -0,0 +1,280 @@
|
||||
/*###############################################################################
|
||||
#
|
||||
# Copyright 2021 NVIDIA Corporation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
###############################################################################*/
|
||||
|
||||
#ifndef __GLMESH_H
|
||||
#define __GLMESH_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "glm/glm.hpp"
|
||||
#include "nvCVStatus.h"
|
||||
|
||||
|
||||
class GLMesh {
|
||||
public:
|
||||
struct Partition {
|
||||
unsigned faceIndex; ///< The index of the first face in the partition.
|
||||
unsigned numFaces; ///< The number of faces in the partition.
|
||||
unsigned vertexIndex; ///< The index of the first topological vertex in the partition.
|
||||
unsigned numVertexIndices; ///< The number of topological vertices in the partition.
|
||||
std::string name; ///< The name of the partition.
|
||||
std::string materialName; ///< The name of the material assigned to the partition.
|
||||
int smooth; ///< The smoothing group > 0; no smoothing == 0; unassigned < 0.
|
||||
|
||||
Partition() { smooth = -1; }
|
||||
bool operator<(const Partition& pt) const { return faceIndex < pt.faceIndex; }
|
||||
void finishPartitioning();
|
||||
};
|
||||
class BoundingBox {
|
||||
public:
|
||||
void unionPoint(const glm::vec3& pt);
|
||||
void set(unsigned numPts, const glm::vec3* pts);
|
||||
void set(unsigned numPts, const glm::vec3* pts, const glm::mat4x4& M);
|
||||
glm::vec3& min() { return _box[0]; }
|
||||
glm::vec3& max() { return _box[1]; }
|
||||
const glm::vec3& min() const { return _box[0]; }
|
||||
const glm::vec3& max() const { return _box[1]; }
|
||||
glm::vec3 center() const { return (_box[0] + _box[1]) * 0.5f; }
|
||||
private:
|
||||
glm::vec3 _box[2];
|
||||
};
|
||||
class BoundingSphere {
|
||||
public:
|
||||
void set(unsigned numPts, const glm::vec3* pts);
|
||||
void set(unsigned numPts, const glm::vec3* pts, const glm::mat4x4& M);
|
||||
glm::vec3& center() { return _center; }
|
||||
const glm::vec3& center() const { return _center; }
|
||||
float& radius() { return _radius; }
|
||||
float radius() const { return _radius; }
|
||||
|
||||
private:
|
||||
glm::vec3 _center;
|
||||
float _radius;
|
||||
};
|
||||
enum { BOUNDARY = 0xFFFFu }; ///< An index that indicates the boundary
|
||||
|
||||
GLMesh();
|
||||
GLMesh(const GLMesh& mesh);
|
||||
~GLMesh();
|
||||
|
||||
|
||||
/// Get the number of faces.
|
||||
/// @return the number of faces.
|
||||
unsigned numFaces() const;
|
||||
|
||||
/// Get the number of XYZ vertices.
|
||||
/// @return the number of XYZ vertices.
|
||||
unsigned numVertices() const;
|
||||
|
||||
/// Get the number of UV texture coordinates.
|
||||
/// @return the number of UV texture coordinates.
|
||||
unsigned numTexCoords() const;
|
||||
|
||||
/// Get the number of XYZ normals.
|
||||
/// @return the number of XYZ normals.
|
||||
unsigned numNormals() const;
|
||||
|
||||
/// Get the number of vertex indices.
|
||||
/// @return the number of vertex indices.
|
||||
unsigned numIndices() const;
|
||||
|
||||
/// Evaluate whether the mesh is composed only of triangles.
|
||||
/// @return true if all faces have 3 vertices; false otherwise.
|
||||
bool isTriMesh() const;
|
||||
|
||||
/// Evaluate whether the mesh is composed only of quadrilaterals.
|
||||
/// @return true if all faces have 4 vertices; false otherwise.
|
||||
bool isQuadMesh() const;
|
||||
|
||||
/// Evaluate whether the mesh is composed only of triangles and quadrilaterals.
|
||||
/// @return true if no face has greater than 4 vertices; false otherwise.
|
||||
bool isTriQuadMesh() const;
|
||||
|
||||
void resizeVertices(unsigned numVert);
|
||||
void resizeTexCoords(unsigned numTexCoord);
|
||||
void resizeNormals(unsigned numNorm);
|
||||
void resizeFaces(unsigned numFace);
|
||||
void resizeTriangles(unsigned numTriangles);
|
||||
void resizeVertexIndices(unsigned numIndices);
|
||||
void resizeDualIndices(unsigned numIndices);
|
||||
void clear();
|
||||
|
||||
glm::vec3* getVertices(); ///< Get the vertices. @return a pointer to the vertices.
|
||||
const glm::vec3* getVertices() const; ///< Get the vertices. @return a pointer to the vertices.
|
||||
glm::vec2* getTexCoords(); ///< Get the texture coordinates. @return a pointer to the texture coordinates.
|
||||
const glm::vec2* getTexCoords() const; ///< Get the texture coordinates. @return a pointer to the texture coordinates.
|
||||
glm::vec3* getNormals(); ///< Get the vertex normals. @return a pointer to the vertex normals.
|
||||
const glm::vec3* getNormals() const; ///< Get the vertex normals. @return a pointer to the vertex normals.
|
||||
glm::vec3* getFaceNormals(); ///< Get the face normals, computed with computeFaceNormals(). @return a pointer to the vertex normals.
|
||||
const glm::vec3* getFaceNormals() const; ///< Get the face normals, computed with computeFaceNormals(). @return a pointer to the vertex normals.
|
||||
unsigned short* getFaceVertexCounts(); ///< Get the vertex counts for each face, in the primal topology. @return an array of vertex counts, one per face.
|
||||
const unsigned short* getFaceVertexCounts() const; ///< Get the vertex counts for each face, in the primal topology. @return an array of vertex counts, one per face.
|
||||
unsigned short* getVertexIndices(); ///< Get the vertex indices for each face: the primal topology. @return a pointer to the vertex indices.
|
||||
const unsigned short* getVertexIndices() const; ///< Get the vertex indices for each face: the primal topology. @return a pointer to the vertex indices.
|
||||
unsigned short* getTextureIndices(); ///< Get the texture indices for each face: the primal topology. @return a pointer to the texture indices.
|
||||
const unsigned short* getTextureIndices() const; ///< Get the texture indices for each face: the primal topology. @return a pointer to the texture indices.
|
||||
unsigned short* getNormalIndices(); ///< Get the normal indices for each face: the primal topology. @return a pointer to the normal indices.
|
||||
const unsigned short* getNormalIndices() const; ///< Get the normal indices for each face: the primal topology. @return a pointer to the normal indices.
|
||||
unsigned short* getVertexFaceCounts(); ///< Get the face counts for each vertex, in the dual topology. @return an array of face counts, one per vertex.
|
||||
const unsigned short* getVertexFaceCounts() const; ///< Get the face counts for each vertex, in the dual topology. @return an array of face counts, one per vertex.
|
||||
unsigned short* getDualIndices(); ///< Get the face indices for each vertex: the dual topology. @return a pointer to the dual face indices.
|
||||
const unsigned short* getDualIndices() const; ///< Get the face indices for each vertex: the dual topology. @return a pointer to the dual face indices.
|
||||
|
||||
void addVertex(float x, float y, float z);
|
||||
void addTexCoord(float u, float v);
|
||||
void addNormal(float x, float y, float z);
|
||||
|
||||
void addVertices(unsigned numVertices, const float* vertices);
|
||||
void addTexCoords(unsigned numTexCoords, const float* texCoords);
|
||||
void addNormals(unsigned numNormals, const float* normals);
|
||||
|
||||
void addFace(unsigned numVertices, const unsigned short* vertexIndices,
|
||||
const unsigned short* textureIndices, const unsigned short* normalIndices);
|
||||
|
||||
void addFaces(unsigned numFaces, unsigned numVerticesPerFace, const unsigned short* vertexIndices,
|
||||
const unsigned short* textureIndices, const unsigned short* normalIndices);
|
||||
|
||||
/// Compute the normals per face.
|
||||
/// @param[in] specify the weighing for the normals. In all cases, the zero vector will
|
||||
/// be returned for faces with zero area.
|
||||
/// 0: unit vectors.
|
||||
/// +1: vectors weighted by the area.
|
||||
/// -1: vectors weighted by the reciprocal of the area.
|
||||
void computeFaceNormals(int weighted = 0);
|
||||
|
||||
/// Compute the vertex normals. The face normals will be computed in the process.
|
||||
/// @param[in] weighted Determines the weighting used to combine the face normals:
|
||||
/// 0: all incident faces normals will have the same weight.
|
||||
/// -1: the normals will be weighted by inverse area of the face.
|
||||
void computeVertexNormals(int weighted = 0);
|
||||
|
||||
void transform(const glm::mat4x4& M);
|
||||
|
||||
/// Get the number of partitions.
|
||||
/// There is always at least one, which may neither have a name nor a material.
|
||||
/// @return the number of partitions.
|
||||
unsigned numPartitions() const;
|
||||
|
||||
/// The easiest way to partition a mesh: call this after all vertices and attributes
|
||||
/// are recorded, and before the first face of each partition is recorded.
|
||||
/// @param[in] name the name of the new partition.
|
||||
/// @param[in] material the name of the material to be used in the new partition.
|
||||
/// @param[in] smooth {-1, 0, 1} means {unspecified, not smooth, smooth}.
|
||||
/// @return NvCV_StatusNone if the partition was retrieved successfully.
|
||||
/// @return NvCV_StatusDuplicate if a partition with the same name already exists.
|
||||
NvCV_Status startPartition(const char* name, const char* material, int smooth = -1);
|
||||
|
||||
/// Get the specified partition.
|
||||
/// @param[in] i the index of the partition to retrieve.
|
||||
/// @param[out] pt a place to store the specified partition.
|
||||
/// @return NvCV_StatusNone if the partition was retrieved successfully.
|
||||
/// @return NvCV_StatusTooBig if the face index was >= the number of faces.
|
||||
NvCV_Status getPartition(unsigned i, Partition& pt) const;
|
||||
|
||||
/// Update the specified partition.
|
||||
/// The function finishPartitioning() should be called
|
||||
/// after the last updatePartition() has been called.
|
||||
/// @param[in] i the index of the partition.
|
||||
/// @param[in] partition the desired value for the specified partition.
|
||||
/// @return NvCV_StatusNone if the partition was updated successfully.
|
||||
/// @return NvCV_StatusTooBig if the face index was >= the number of faces.
|
||||
NvCV_Status updatePartition(unsigned i, const Partition& partition);
|
||||
|
||||
/// Partition the mesh.
|
||||
/// @param[in] numPartitions the number of partitions.
|
||||
/// @param[in] partitions the array of partitions. Only { faceIndex, name, and
|
||||
/// materialName need be supplied}; the rest are computed.
|
||||
/// @return NvCV_StatusNone if the partition was executed successfully.
|
||||
/// @return NvCV_StatusTooBig if any faceIndex was >= the number of faces.
|
||||
NvCV_Status partitionMesh(unsigned numPartitions, const Partition* partitions);
|
||||
|
||||
/// The last step after partitioning with updatePartition().
|
||||
/// This is not needed if the partitions were created solely with the use of
|
||||
/// startPartition() or PartitionMesh().
|
||||
/// @note The partitions may be reordered (sorted) after calling finishPartitioning().
|
||||
void finishPartitioning();
|
||||
|
||||
/// Set a single material for the whole mesh.
|
||||
/// @param[in] name the name of the material.
|
||||
NvCV_Status setMaterial(const char* name);
|
||||
|
||||
/// Get the bounding box, optionally with an affine transformation.
|
||||
/// @param[out] bbox a place to store the bounding box.
|
||||
/// @param[in] M pointer to a modeling matrix; NULL implies the identity.
|
||||
void getBoundingBox(BoundingBox* bbox, const glm::mat4x4* M = nullptr) const;
|
||||
|
||||
/// Get the bounding box, optionally with an affine transformation.
|
||||
/// @param[out] bbox a place to store the bounding box.
|
||||
/// @param[in] M pointer to a modeling matrix; NULL implies the identity.
|
||||
void getBoundingSphere(BoundingSphere* bsph, const glm::mat4x4* M = nullptr) const;
|
||||
|
||||
/// Query whether the PolyMesh is not renderable easily by Open GL.
|
||||
/// Since the more typical query would be whether it is renderable instead,
|
||||
/// this seems like negative logic, but this choice was made to return a bit vector
|
||||
/// indicating the reason that the Polymesh is not renderable.
|
||||
/// @param[in] options Rendering options; currently ignored.
|
||||
/// @return RENDERABLE if the PolyMesh is renderable. Otherwise a bit vector of:
|
||||
/// NOT_TRIMESH if some faces are not triangular;
|
||||
/// COMPLEX_TOPOLOGY if the vertex attribute topology is inconsistent;
|
||||
unsigned notRenderable(unsigned options) const;
|
||||
|
||||
/// Append another mesh.
|
||||
/// @param[in] mesh the other mesh.
|
||||
/// @param[in] M an optional affine transform
|
||||
NvCV_Status append(const GLMesh& mesh, const glm::mat4x4* M = nullptr);
|
||||
|
||||
/// Bit vector components indicating non-renderability.
|
||||
enum {
|
||||
RENDERABLE = 0x0, ///< The PolyMesh is renderable.
|
||||
NOT_TRIMESH = 0x1, ///< Some faces are not triangular.
|
||||
COMPLEX_TOPOLOGY = 0x2 ///< The vertex topology is not consistent.
|
||||
};
|
||||
|
||||
private:
|
||||
void initPartitions();
|
||||
void computeStartingVertexIndices();
|
||||
static bool indicesMatch(const std::vector<unsigned short>& ivecA, const std::vector<unsigned short>& ivecB);
|
||||
void assureConsistency();
|
||||
void useFaceNormals(bool yes);
|
||||
|
||||
std::vector<unsigned short> m_faceVertexCount;
|
||||
|
||||
std::vector<glm::vec3> m_vertices;
|
||||
std::vector<unsigned short> m_vertexIndices;
|
||||
|
||||
std::vector<glm::vec2> m_texCoords;
|
||||
std::vector<unsigned short> m_textureIndices;
|
||||
|
||||
std::vector<glm::vec3> m_normals;
|
||||
std::vector<unsigned short> m_normalIndices;
|
||||
|
||||
std::vector<glm::vec3> m_faceNormals;
|
||||
|
||||
std::vector<Partition> m_partitions;
|
||||
|
||||
std::vector<unsigned short> m_vertexFaceCount; // the number of faces surrounding each vertex
|
||||
std::vector<unsigned short> m_dualIndices; // the face indices for each vertex
|
||||
};
|
||||
|
||||
#endif // __GLMESH_H
|
||||
632
samples/ExpressionApp/BackEndOpenGL/GLShaders.cpp
Normal file
632
samples/ExpressionApp/BackEndOpenGL/GLShaders.cpp
Normal file
@@ -0,0 +1,632 @@
|
||||
/*###############################################################################
|
||||
#
|
||||
# Copyright 2016-2021 NVIDIA Corporation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
###############################################################################*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include "glad/glad.h"
|
||||
#else
|
||||
#include <GLES3/gl3.h>
|
||||
#endif // _MSC_VER
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
#include "GLShaders.h"
|
||||
|
||||
|
||||
enum {
|
||||
myErrNone = 0,
|
||||
myErrShader = -1,
|
||||
myErrProgram = -2,
|
||||
myErrTexture = -3,
|
||||
};
|
||||
|
||||
|
||||
#define BAIL_IF_ERR(err) do { if ((err)) { goto bail; } } while(0)
|
||||
#define _STRINGIFY_(token) #token
|
||||
#define STRINGIFY(token) _STRINGIFY_(token)
|
||||
#define MAYBE_UNUSED(token) if (token){}
|
||||
|
||||
|
||||
/****************************************************************************//**
|
||||
* Print Shader Log.
|
||||
* \param[in] id the ID of the shader.
|
||||
* \param[in] type either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
|
||||
* \param[in] shader the shader source code.
|
||||
********************************************************************************/
|
||||
|
||||
static void PrintShaderLog(GLuint id, GLenum type, const char *shader) {
|
||||
GLsizei msgLength;
|
||||
std::string errMsg;
|
||||
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &msgLength);
|
||||
errMsg.resize(msgLength);
|
||||
glGetShaderInfoLog(id, msgLength, &msgLength, &errMsg[0]);
|
||||
fprintf(stderr, "\nShader Log:\n%sfor %s Shader:\n%s\n", errMsg.c_str(),
|
||||
((type == GL_VERTEX_SHADER) ? "Vertex" : "Fragment"), shader);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************//**
|
||||
* Print Program Log.
|
||||
* \param[in] id the id of the program.
|
||||
********************************************************************************/
|
||||
|
||||
static void PrintProgramLog(GLuint id) {
|
||||
GLsizei msgLength;
|
||||
std::string errMsg;
|
||||
glGetProgramiv(id, GL_INFO_LOG_LENGTH, &msgLength);
|
||||
errMsg.resize(msgLength);
|
||||
glGetProgramInfoLog(id, msgLength, &msgLength, &errMsg[0]);
|
||||
fprintf(stderr, "\nProgram Log:\n%s\n", errMsg.c_str());
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************//**
|
||||
* NewShader
|
||||
********************************************************************************/
|
||||
|
||||
static int NewShader(const char *shaderStr, GLenum type, GLuint *shaderID) {
|
||||
GLuint id;
|
||||
GLint result;
|
||||
|
||||
*shaderID = 0;
|
||||
id = glCreateShader(type);
|
||||
glShaderSource(id, 1, &shaderStr, NULL);
|
||||
glCompileShader(id);
|
||||
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
|
||||
if (result) {
|
||||
*shaderID = id;
|
||||
return myErrNone;
|
||||
}
|
||||
else {
|
||||
PrintShaderLog(id, type, shaderStr);
|
||||
glDeleteShader(id);
|
||||
return myErrShader;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************//**
|
||||
* NewProgram
|
||||
********************************************************************************/
|
||||
|
||||
static int NewProgram(GLuint vertexShader, GLuint fragmentShader, GLuint *progID) {
|
||||
GLint result;
|
||||
GLuint id;
|
||||
|
||||
*progID = 0;
|
||||
|
||||
id = glCreateProgram();
|
||||
glAttachShader(id, vertexShader);
|
||||
glAttachShader(id, fragmentShader);
|
||||
|
||||
glLinkProgram(id);
|
||||
glGetProgramiv(id, GL_LINK_STATUS, &result);
|
||||
if (result) {
|
||||
*progID = id;
|
||||
return myErrNone;
|
||||
}
|
||||
else {
|
||||
PrintProgramLog(id);
|
||||
glDeleteProgram(id);
|
||||
return myErrProgram;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************//**
|
||||
* IndexTypeFromSize
|
||||
********************************************************************************/
|
||||
|
||||
static GLenum IndexTypeFromSize(unsigned indexSize) {
|
||||
return (indexSize < 2) ? GL_UNSIGNED_BYTE
|
||||
: (indexSize == 2) ? GL_UNSIGNED_SHORT
|
||||
: GL_UNSIGNED_INT;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
********************************************************************************
|
||||
***** SMOOTH RENDERER *****
|
||||
********************************************************************************
|
||||
********************************************************************************/
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* Shaders
|
||||
********************************************************************************/
|
||||
|
||||
const char SmoothRenderer::_vertexShader[] =
|
||||
"uniform mat4 MVP;\n"
|
||||
"attribute vec3 vCol;\n"
|
||||
"attribute vec3 vPos;\n"
|
||||
"varying vec3 color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" gl_Position = MVP * vec4(vPos, 1.0);\n"
|
||||
" color = vCol;\n"
|
||||
"}\n";
|
||||
const char SmoothRenderer::_fragmentShader[] =
|
||||
"varying vec3 color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" gl_FragColor = vec4(color, 1.0);\n"
|
||||
"}\n";
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* startup
|
||||
********************************************************************************/
|
||||
|
||||
int SmoothRenderer::startup() {
|
||||
int err = myErrNone;
|
||||
GLuint vertexShader = 0, fragmentShader = 0;
|
||||
|
||||
_programID = 0;
|
||||
BAIL_IF_ERR(err = NewShader(_vertexShader, GL_VERTEX_SHADER, &vertexShader));
|
||||
BAIL_IF_ERR(err = NewShader(_fragmentShader, GL_FRAGMENT_SHADER, &fragmentShader));
|
||||
BAIL_IF_ERR(err = NewProgram(vertexShader, fragmentShader, &_programID));
|
||||
_maxtrixID = glGetUniformLocation(_programID, "MVP");
|
||||
_vtxPosID = glGetAttribLocation(_programID, "vPos");
|
||||
_vtxColID = glGetAttribLocation(_programID, "vCol");
|
||||
err = (-1 == _maxtrixID || -1 == _vtxPosID || -1 == _vtxColID) ? myErrShader : myErrNone;
|
||||
|
||||
bail:
|
||||
if (myErrNone != err) shutdown();
|
||||
if (fragmentShader) glDeleteShader(fragmentShader);
|
||||
if (vertexShader) glDeleteShader(vertexShader);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* use
|
||||
********************************************************************************/
|
||||
|
||||
int SmoothRenderer::use() {
|
||||
if (0 == _programID)
|
||||
return myErrProgram;
|
||||
glUseProgram(_programID);
|
||||
return myErrNone;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* drawElements, from user memory
|
||||
********************************************************************************/
|
||||
|
||||
void SmoothRenderer::drawElements(GLsizei numVertices, const GLfloat *positions, const GLfloat *colors,
|
||||
GLenum graphicsMode, GLsizei indexCount, GLenum indexType, const GLvoid *indices, const GLfloat *M
|
||||
) {
|
||||
MAYBE_UNUSED(numVertices);
|
||||
glUseProgram(_programID);
|
||||
if (M)
|
||||
glUniformMatrix4fv(_maxtrixID, 1, GL_FALSE, M);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
if (colors) { /* Separate array for position and color */
|
||||
glEnableVertexAttribArray(_vtxPosID);
|
||||
glVertexAttribPointer(_vtxPosID, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(*positions), positions);
|
||||
glEnableVertexAttribArray(_vtxColID);
|
||||
glVertexAttribPointer(_vtxColID, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(*colors), colors);
|
||||
}
|
||||
else { /* One contiguous array for position and color */
|
||||
glEnableVertexAttribArray(_vtxPosID);
|
||||
glVertexAttribPointer(_vtxPosID, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(*positions), positions);
|
||||
glEnableVertexAttribArray(_vtxColID);
|
||||
glVertexAttribPointer(_vtxColID, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(*positions), positions + 3);
|
||||
}
|
||||
glDrawElements(graphicsMode, indexCount, indexType, indices);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* drawElements, from buffer objects
|
||||
********************************************************************************/
|
||||
|
||||
void SmoothRenderer::drawElements(GLuint vtxBuf, unsigned posOff, unsigned colOff,
|
||||
GLenum graphicsMode, GLsizei numIndices, unsigned indexSize, GLuint topoBuf, const GLfloat *M
|
||||
) {
|
||||
GLenum err;
|
||||
glUseProgram(_programID);
|
||||
if (M)
|
||||
glUniformMatrix4fv(_maxtrixID, 1, GL_FALSE, M);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vtxBuf);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, topoBuf);
|
||||
if (!(colOff == 12 || colOff == 0)) { /* Separate array for position and color */
|
||||
glEnableVertexAttribArray(_vtxPosID);
|
||||
glVertexAttribPointer(_vtxPosID, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)(intptr_t)posOff);
|
||||
glEnableVertexAttribArray(_vtxColID);
|
||||
glVertexAttribPointer(_vtxColID, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)(intptr_t)colOff);
|
||||
}
|
||||
else { /* One contiguous array for position and color */
|
||||
glEnableVertexAttribArray(_vtxPosID);
|
||||
glVertexAttribPointer(_vtxPosID, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(intptr_t)(posOff + 0 * sizeof(float)));
|
||||
glEnableVertexAttribArray(_vtxColID);
|
||||
glVertexAttribPointer(_vtxColID, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(intptr_t)(posOff + 3 * sizeof(float)));
|
||||
err = glGetError(); if (err) printf("glVertexAttribPointer returns %d\n", err);
|
||||
}
|
||||
glDrawElements(graphicsMode, numIndices, IndexTypeFromSize(indexSize), (void*)0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
********************************************************************************
|
||||
***** TEXTURE RENDERER *****
|
||||
********************************************************************************
|
||||
********************************************************************************/
|
||||
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* shaders
|
||||
********************************************************************************/
|
||||
|
||||
const char TextureRenderer::_vertexShader[] =
|
||||
"uniform mat4 MVP;\n" // Model, view, projection matrices, concatenated.
|
||||
"attribute vec3 vPos;\n" // Vertex position
|
||||
"attribute vec2 vTex;\n" // Vertex texture coordinate
|
||||
"varying vec2 texCoord;\n" // Interpolated texture coordinate
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" gl_Position = MVP * vec4(vPos, 1.0);\n"
|
||||
" texCoord = vTex;\n"
|
||||
"}\n";
|
||||
const char TextureRenderer::_fragmentShader[] =
|
||||
"uniform sampler2D tex;\n"
|
||||
"varying vec2 texCoord;\n" // Interpolated texture coordinate
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" gl_FragColor = texture2D(tex, texCoord);\n"
|
||||
"}\n";
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* startup
|
||||
********************************************************************************/
|
||||
|
||||
int TextureRenderer::startup() {
|
||||
int err = myErrNone;
|
||||
GLuint vertexShader = 0, fragmentShader = 0;
|
||||
|
||||
if (_programID)
|
||||
return myErrNone;
|
||||
_programID = 0;
|
||||
BAIL_IF_ERR(err = NewShader(_vertexShader, GL_VERTEX_SHADER, &vertexShader));
|
||||
BAIL_IF_ERR(err = NewShader(_fragmentShader, GL_FRAGMENT_SHADER, &fragmentShader));
|
||||
BAIL_IF_ERR(err = NewProgram(vertexShader, fragmentShader, &_programID));
|
||||
_maxtrixID = _vtxPosID = _vtxTexID = -1;
|
||||
_maxtrixID = glGetUniformLocation(_programID, "MVP");
|
||||
_vtxPosID = glGetAttribLocation(_programID, "vPos");
|
||||
_vtxTexID = glGetAttribLocation(_programID, "vTex");
|
||||
err = (-1 == _maxtrixID || -1 == _vtxPosID || -1 == _vtxTexID) ? myErrShader : myErrNone;
|
||||
|
||||
bail:
|
||||
if (myErrNone != err) shutdown();
|
||||
if (fragmentShader) glDeleteShader(fragmentShader);
|
||||
if (vertexShader) glDeleteShader(vertexShader);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* use
|
||||
********************************************************************************/
|
||||
|
||||
int TextureRenderer::use() {
|
||||
if (0 == _programID)
|
||||
return myErrProgram;
|
||||
glUseProgram(_programID);
|
||||
return myErrNone;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* drawElements, from user buffers
|
||||
********************************************************************************/
|
||||
|
||||
void TextureRenderer::drawElements(GLsizei numVertices, const GLfloat *xyz, const GLfloat *uv,
|
||||
GLenum graphicsMode, GLsizei indexCount, GLenum indexType, const GLvoid *indices, GLuint texID ,const GLfloat *M
|
||||
) {
|
||||
MAYBE_UNUSED(numVertices);
|
||||
glUseProgram(_programID);
|
||||
if (M)
|
||||
glUniformMatrix4fv(_maxtrixID, 1, GL_FALSE, M);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, texID);
|
||||
|
||||
if (uv) { /* Separate array for position and color */
|
||||
glEnableVertexAttribArray(_vtxPosID);
|
||||
glVertexAttribPointer(_vtxPosID, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(*xyz), xyz);
|
||||
glEnableVertexAttribArray(_vtxTexID);
|
||||
glVertexAttribPointer(_vtxTexID, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(*uv), uv);
|
||||
}
|
||||
else { /* One contiguous array for position and color */
|
||||
glEnableVertexAttribArray(_vtxPosID);
|
||||
glVertexAttribPointer(_vtxPosID, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(*xyz), xyz);
|
||||
glEnableVertexAttribArray(_vtxTexID);
|
||||
glVertexAttribPointer(_vtxTexID, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(*xyz), xyz + 3);
|
||||
}
|
||||
glDrawElements(graphicsMode, indexCount, indexType, indices);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* drawElements, from buffer objects
|
||||
********************************************************************************/
|
||||
|
||||
void TextureRenderer::drawElements(
|
||||
GLuint vtxBuf, unsigned xyzOff, unsigned uvOff, GLenum graphicsMode,
|
||||
GLsizei numIndices, GLenum indexSize, GLuint indexBuf, GLuint texID, const GLfloat *M
|
||||
) {
|
||||
GLenum err;
|
||||
glUseProgram(_programID);
|
||||
if (M)
|
||||
glUniformMatrix4fv(_maxtrixID, 1, GL_FALSE, M);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vtxBuf);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuf);
|
||||
glBindTexture(GL_TEXTURE_2D, texID);
|
||||
|
||||
if (!(uvOff == 12 || uvOff == 0)) { /* Separate array for position and color */
|
||||
glEnableVertexAttribArray(_vtxPosID);
|
||||
glVertexAttribPointer(_vtxPosID, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)(intptr_t)xyzOff);
|
||||
glEnableVertexAttribArray(_vtxTexID);
|
||||
glVertexAttribPointer(_vtxTexID, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)(intptr_t)uvOff);
|
||||
}
|
||||
else { /* One contiguous array for position and color */
|
||||
glEnableVertexAttribArray(_vtxPosID);
|
||||
glVertexAttribPointer(_vtxPosID, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(intptr_t)(xyzOff + 0 * sizeof(float)));
|
||||
glEnableVertexAttribArray(_vtxTexID);
|
||||
glVertexAttribPointer(_vtxTexID, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(intptr_t)(xyzOff + 3 * sizeof(float)));
|
||||
err = glGetError(); if (err) printf("glVertexAttribPointer returns %d\n", err);
|
||||
}
|
||||
glDrawElements(graphicsMode, numIndices, IndexTypeFromSize(indexSize), (void*)0);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* drawQuad, from user buffers
|
||||
********************************************************************************/
|
||||
|
||||
void TextureRenderer::drawQuad(const float xyz[4*3], const float uv[4*2], GLuint texID, const float *M) {
|
||||
static const unsigned char indices[4] = { 0, 1, 2, 3 }; // These need to be static, because GL is asynchronous
|
||||
drawElements(4, xyz, uv, GL_TRIANGLE_FAN, 4, GL_UNSIGNED_BYTE, indices, texID, M);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* Mesh shader
|
||||
********************************************************************************/
|
||||
|
||||
class MeshShader {
|
||||
static const char _vertexShader[], _fragmentShader[];
|
||||
};
|
||||
// The ambient and diffuse coefficients are rolled into the ambCol and litCol, respectively.
|
||||
const char MeshShader::_vertexShader[] =
|
||||
"uniform mat4 MVP;\n" // Model, view, projection matrices, concatenated.
|
||||
"uniform mat3 N;\n" // Normal matrix.
|
||||
"uniform vec3 litDir;\n" // Light direction
|
||||
"uniform vec3 litCol;\n" // Light color multiplied by the diffuse coefficient
|
||||
"uniform vec3 ambCol;\n" // Ambient color multiplied by the ambient coefficient
|
||||
"attribute vec3 vtxPos;\n" // Vertex position
|
||||
"attribute vec3 vtxNor;\n" // Vertex normal
|
||||
"attribute vec2 vtxTex;\n" // Vertex texture coordinate
|
||||
"varying vec2 texCoord;\n" // Interpolated texture coordinate
|
||||
"varying vec3 illum;\n" // Interpolated illumination
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" gl_Position = MVP * vec4(vtxPos, 1.0);\n"
|
||||
" texCoord = vtxTex;\n"
|
||||
" illum = max(dot(N * vtxNor, litDir) * litCol + ambCol;\n"
|
||||
"}\n";
|
||||
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* UpdateTexture
|
||||
********************************************************************************/
|
||||
|
||||
GLenum UpdateTexture(GLint texID, GLsizei width, GLsizei height, GLsizei rowBytes, GLenum glFormat, const GLvoid *pixels) {
|
||||
glBindTexture(GL_TEXTURE_2D, texID);
|
||||
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
|
||||
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, rowBytes / 4);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, glFormat, GL_UNSIGNED_BYTE, pixels);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); // restore to default
|
||||
return glGetError();
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
********************************************************************************
|
||||
***** LAMBERTIAN RENDERER *****
|
||||
********************************************************************************
|
||||
********************************************************************************/
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* Shaders
|
||||
********************************************************************************/
|
||||
|
||||
const char LambertianRenderer::_vertexShader[] =
|
||||
"#version 120\n"
|
||||
"uniform mat4 M;\n"
|
||||
"uniform mat4 VP;\n"
|
||||
"uniform vec4 lightLoc[" STRINGIFY(LAMBERTIAN_NUM_LIGHTS) "];\n"
|
||||
"uniform vec3 lightColor[" STRINGIFY(LAMBERTIAN_NUM_LIGHTS) "];\n"
|
||||
"uniform vec3 Ka;\n"
|
||||
"uniform vec3 Kd;\n"
|
||||
"attribute vec3 vPos;\n"
|
||||
"attribute vec3 vNrm;\n"
|
||||
"varying vec3 color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec4 loc = M * vec4(vPos, 1.);\n" // Transform points into world space ...
|
||||
" gl_Position = VP * loc;\n" // ... and screen space
|
||||
" vec3 N = normalize(mat3(M) * vNrm);\n" // Transform normal into world space, assuming isotropic scaling
|
||||
" color = Ka;\n" // Initialize color to ambient
|
||||
" for (int i = 0; i < " STRINGIFY(LAMBERTIAN_NUM_LIGHTS) "; ++i)\n"
|
||||
" {\n"
|
||||
" vec3 L = normalize(lightLoc[i].xyz - lightLoc[i].w * loc.xyz);\n" // Compute vector to light: w must be either 1 or 0
|
||||
" float d = dot(L, N);\n" // Lambertian lighting
|
||||
" if (d > 0.)\n" // If the light hits the outside surface, ...
|
||||
" color += d * lightColor[i] * Kd;\n" // ... accumulate color from the light source
|
||||
" }\n"
|
||||
"}\n";
|
||||
const char LambertianRenderer::_fragmentShader[] =
|
||||
"varying vec3 color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" gl_FragColor = vec4(color, 1.);\n" // Interpolate the color
|
||||
"}\n";
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* startup
|
||||
********************************************************************************/
|
||||
|
||||
int LambertianRenderer::startup() {
|
||||
int err = myErrNone;
|
||||
GLuint vertexShader = 0, fragmentShader = 0;
|
||||
|
||||
_programID = 0;
|
||||
BAIL_IF_ERR(err = NewShader(_vertexShader, GL_VERTEX_SHADER, &vertexShader));
|
||||
BAIL_IF_ERR(err = NewShader(_fragmentShader, GL_FRAGMENT_SHADER, &fragmentShader));
|
||||
BAIL_IF_ERR(err = NewProgram(vertexShader, fragmentShader, &_programID));
|
||||
_lightLoc = glGetUniformLocation(_programID, "lightLoc"); // light locations
|
||||
_lightColor = glGetUniformLocation(_programID, "lightColor"); // light diffuse colors
|
||||
_MmatrixID = glGetUniformLocation(_programID, "M"); // M matrix; require UL 3x3 to be orthogonal
|
||||
_VPmatrixID = glGetUniformLocation(_programID, "VP"); // VP matrix
|
||||
_ambientColorID = glGetUniformLocation(_programID, "Ka"); // ambient color
|
||||
_diffuseColorID = glGetUniformLocation(_programID, "Kd"); // diffuse color
|
||||
_vtxPosID = glGetAttribLocation(_programID, "vPos"); // vertex positions
|
||||
_vtxNrmID = glGetAttribLocation(_programID, "vNrm"); // vertex normals
|
||||
|
||||
err = (-1 == _lightLoc || -1 == _lightColor || -1 == _MmatrixID || -1 == _VPmatrixID || -1 == _ambientColorID
|
||||
|| -1 == _diffuseColorID || -1 == _vtxPosID || -1 == _vtxNrmID) ? myErrShader : myErrNone;
|
||||
BAIL_IF_ERR(err);
|
||||
|
||||
bail:
|
||||
if (myErrNone != err) shutdown();
|
||||
if (fragmentShader) glDeleteShader(fragmentShader);
|
||||
if (vertexShader) glDeleteShader(vertexShader);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* use
|
||||
********************************************************************************/
|
||||
|
||||
int LambertianRenderer::use() {
|
||||
if (0 == _programID)
|
||||
return myErrProgram;
|
||||
glUseProgram(_programID);
|
||||
return myErrNone;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* set lights
|
||||
********************************************************************************/
|
||||
|
||||
void LambertianRenderer::setLights(const float locXYZW[4*LAMBERTIAN_NUM_LIGHTS], const float colorRGB[3*LAMBERTIAN_NUM_LIGHTS]) {
|
||||
glUseProgram(_programID);
|
||||
glUniform4fv(_lightLoc, LAMBERTIAN_NUM_LIGHTS, locXYZW);
|
||||
glUniform3fv(_lightColor, LAMBERTIAN_NUM_LIGHTS, colorRGB);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* drawElements, from user memory
|
||||
********************************************************************************/
|
||||
|
||||
void LambertianRenderer::drawElements(GLsizei numVertices, const GLfloat *positions, const GLfloat *normals,
|
||||
GLenum graphicsMode, GLsizei indexCount, GLenum indexType, const GLvoid *indices,
|
||||
const GLfloat M[4*4], const GLfloat VP[4*4], const float Ka[3], const float Kd[3]
|
||||
) {
|
||||
MAYBE_UNUSED(numVertices);
|
||||
glUseProgram(_programID);
|
||||
if (M) glUniformMatrix4fv(_MmatrixID, 1, GL_FALSE, M);
|
||||
if (VP) glUniformMatrix4fv(_VPmatrixID, 1, GL_FALSE, VP);
|
||||
if (Ka) glUniform3fv(_ambientColorID, 1, Ka);
|
||||
if (Kd) glUniform3fv(_diffuseColorID, 1, Kd);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
if (normals) { /* Separate array for position and color */
|
||||
glEnableVertexAttribArray(_vtxPosID);
|
||||
glVertexAttribPointer(_vtxPosID, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(*positions), positions);
|
||||
glEnableVertexAttribArray(_vtxNrmID);
|
||||
glVertexAttribPointer(_vtxNrmID, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(*normals), normals);
|
||||
}
|
||||
else { /* One contiguous array for position and color */
|
||||
glEnableVertexAttribArray(_vtxPosID);
|
||||
glVertexAttribPointer(_vtxPosID, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(*positions), positions);
|
||||
glEnableVertexAttribArray(_vtxNrmID);
|
||||
glVertexAttribPointer(_vtxNrmID, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(*normals), normals + 3);
|
||||
}
|
||||
glDrawElements(graphicsMode, indexCount, indexType, indices);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* drawElements, from buffer objects
|
||||
********************************************************************************/
|
||||
|
||||
void LambertianRenderer::drawElements(GLuint vtxBuf, unsigned posOff, unsigned nrmOff,
|
||||
GLenum graphicsMode, GLsizei numIndices, unsigned indexSize, GLuint indexBuf,
|
||||
const GLfloat M[4*4], const GLfloat VP[4*4], const float Ka[3], const float Kd[3]
|
||||
) {
|
||||
GLenum err;
|
||||
|
||||
glUseProgram(_programID);
|
||||
if (M) glUniformMatrix4fv(_MmatrixID, 1, GL_FALSE, M);
|
||||
if (VP) glUniformMatrix4fv(_VPmatrixID, 1, GL_FALSE, VP);
|
||||
if (Ka) glUniform3fv(_ambientColorID, 1, Ka);
|
||||
if (Kd) glUniform3fv(_diffuseColorID, 1, Kd);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vtxBuf);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuf);
|
||||
if (!(nrmOff == 12 || nrmOff == 0)) { /* Separate array for position and normal */
|
||||
glEnableVertexAttribArray(_vtxPosID);
|
||||
glVertexAttribPointer(_vtxPosID, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)(intptr_t)posOff);
|
||||
glEnableVertexAttribArray(_vtxNrmID);
|
||||
glVertexAttribPointer(_vtxNrmID, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)(intptr_t)nrmOff);
|
||||
}
|
||||
else { /* One contiguous array for position and normal */
|
||||
glEnableVertexAttribArray(_vtxPosID);
|
||||
glVertexAttribPointer(_vtxPosID, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(intptr_t)(posOff + 0 * sizeof(float)));
|
||||
glEnableVertexAttribArray(_vtxNrmID);
|
||||
glVertexAttribPointer(_vtxNrmID, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(intptr_t)(posOff + 3 * sizeof(float)));
|
||||
err = glGetError(); if (err) printf("glVertexAttribPointer returns %d\n", err);
|
||||
}
|
||||
glDrawElements(graphicsMode, numIndices, IndexTypeFromSize(indexSize), (void*)0);
|
||||
}
|
||||
366
samples/ExpressionApp/BackEndOpenGL/GLShaders.h
Normal file
366
samples/ExpressionApp/BackEndOpenGL/GLShaders.h
Normal file
@@ -0,0 +1,366 @@
|
||||
/*###############################################################################
|
||||
#
|
||||
# Copyright 2016-2021 NVIDIA Corporation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
###############################################################################*/
|
||||
|
||||
#ifndef __ARSHADERS_H__
|
||||
#define __ARSHADERS_H__
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include "glad/glad.h"
|
||||
#else
|
||||
#include <GLES3/gl3.h>
|
||||
#endif // _MSC_VER
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
********************************************************************************
|
||||
***** SMOOTH RENDERER *****
|
||||
********************************************************************************
|
||||
********************************************************************************/
|
||||
|
||||
class SmoothRenderer {
|
||||
public:
|
||||
|
||||
SmoothRenderer() { _programID = 0; }
|
||||
~SmoothRenderer() { shutdown(); }
|
||||
|
||||
int startup();
|
||||
void shutdown() { if (_programID) glDeleteProgram(_programID); _programID = 0; }
|
||||
int use();
|
||||
int activate() { return startup(); } // DEPRECATED
|
||||
void deactivate() { shutdown(); } // DEPRECATED
|
||||
|
||||
/** These take vertex and topology data in user-space buffers.
|
||||
* @param[in] numPts The number of points in xyz or rgb.
|
||||
* @param[in] xyz The vertex locations {x, y, z }.
|
||||
* @param[in] rgb The vertex colors { r, g, b }, in [0, 1].
|
||||
* @param[in] numIndices The number of indices.
|
||||
* @param[in] indices The indices. Note that three versions are given, where indices can be 1, 2, or 4 bytes.
|
||||
* @param[in] M the matrix.
|
||||
*/
|
||||
void drawTriMesh(unsigned numPts, const float* xyz, const float* rgb,
|
||||
unsigned numIndices, const unsigned char* indices, const float* M = nullptr) {
|
||||
drawElements(numPts, xyz, rgb, GL_TRIANGLES, numIndices, GL_UNSIGNED_BYTE, indices, M);
|
||||
}
|
||||
void drawTriMesh(unsigned numPts, const float* xyz, const float* rgb,
|
||||
unsigned numIndices, const unsigned short* indices, const float* M = nullptr) {
|
||||
drawElements(numPts, xyz, rgb, GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, indices, M);
|
||||
}
|
||||
void drawTriMesh(unsigned numPts, const float* xyz, const float* rgb,
|
||||
unsigned numIndices, const unsigned int* indices, const float* M = nullptr) {
|
||||
drawElements(numPts, xyz, rgb, GL_TRIANGLES, numIndices, GL_UNSIGNED_INT, indices, M);
|
||||
}
|
||||
|
||||
/** These take vertex and topology data in GL buffer objects
|
||||
* @param[in] vtxBuf the vertex buffer object identifier.
|
||||
* @param[in] xyzOff the offset, in bytes, of the xyz positions in the vertex buffer.
|
||||
* @param[in] rgbOff the offset, in bytes, of the rgb color in the vertex buffer.
|
||||
* @param[in] numIndices the number of indices.
|
||||
* @param[in] indexBuf the index buffer object identifier.
|
||||
* @param[in] indexSize the byte size of the indices: 1, 2, or 4.
|
||||
* @param[in] M the matrix.
|
||||
*/
|
||||
void drawTriMesh(GLuint vtxBuf, unsigned xyzOff, unsigned rgbOff,
|
||||
unsigned numIndices, GLuint indexBuf, GLenum indexSize, const float* M) {
|
||||
drawElements(vtxBuf, xyzOff, rgbOff, GL_TRIANGLES, numIndices, indexSize, indexBuf, M);
|
||||
}
|
||||
|
||||
private:
|
||||
/** Render geometry from user buffers, pre-shaded at vertices.
|
||||
* @param[in] numVertices The number of 3D vertices.
|
||||
* @param[in] positions The array of 3D positions -- one for every vertex.
|
||||
* @param[in] colors The array of RGB colors -- one for every vertex.
|
||||
* @param[in] graphicsMode One of { GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN }.
|
||||
* GL_QUADS is not supported.
|
||||
* @param[in] indexCount The number of 0-based vertex indices that define the geometry
|
||||
* from the vertices and graphics mode.
|
||||
* @param[in] indexType The type of index { GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT }.
|
||||
* @param[in] indices The array of vertices.
|
||||
* @param[in] M The modeling-viewing-projection matrix.
|
||||
*/
|
||||
void drawElements(GLsizei numVertices, const GLfloat* positions, const GLfloat* colors,
|
||||
GLenum graphicsMode, GLsizei indexCount, GLenum indexType, const GLvoid* indices, const GLfloat* M);
|
||||
|
||||
/** Render geometry from GL buffer objects, pre-shaded at vertices.
|
||||
* @param[in] vtxBuf The ID of the GL buffer used to store the vertices.
|
||||
* @param[in] posOff The offset of the positions in the vertex buffer. This is typically 0,
|
||||
* but is not restricted so.
|
||||
* @param[in] colOff The offset of the colors in the vertex buffer. Both planar (homogeneous, separate)
|
||||
* and chunky (nonhomogeneous, interleaved) representations are accommodated.
|
||||
* @param[in] graphicsMode One of { GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN }.
|
||||
* GL_QUADS is not supported.
|
||||
* @param[in] indexCount The number of 0-based vertex indices that define the geometry
|
||||
* from the vertices and graphics mode.
|
||||
* @param[in] indexType The type of index { GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT }.
|
||||
* @param[in] indexBuf The ID of the GL buffer used to store the indices.
|
||||
* @param[in] M The modeling-viewing-projection matrix.
|
||||
*/
|
||||
void drawElements(GLuint vtxBuf, unsigned posOff, unsigned colOff,
|
||||
GLenum graphicsMode, GLsizei indexCount, GLenum indexType, GLuint indexBuf, const GLfloat* M);
|
||||
|
||||
GLuint _programID;
|
||||
GLint _maxtrixID, _vtxPosID, _vtxColID;
|
||||
static const char _vertexShader[], _fragmentShader[];
|
||||
};
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
********************************************************************************
|
||||
***** TEXTURE RENDERER *****
|
||||
********************************************************************************
|
||||
********************************************************************************/
|
||||
|
||||
class TextureRenderer {
|
||||
public:
|
||||
|
||||
TextureRenderer() { _programID = 0; }
|
||||
~TextureRenderer() { shutdown(); }
|
||||
|
||||
int startup();
|
||||
void shutdown() { if (_programID) glDeleteProgram(_programID); _programID = 0; }
|
||||
int use();
|
||||
int activate() { return startup(); } // DEPRECATED
|
||||
void deactivate() { shutdown(); } // DEPRECATED
|
||||
|
||||
/** These take vertex and topology data in user-space buffers.
|
||||
* @param[in] numPts The number of points in xyz or uv.
|
||||
* @param[in] xyz The vertex locations {x, y, z }.
|
||||
* @param[in] uv The vertex texture coordinates { u, v }, in [0, 1].
|
||||
* @param[in] numIndices The number of indices.
|
||||
* @param[in] indices The indices. Note that three versions are given, where indices can be 1, 2, or 4 bytes.
|
||||
* @param[in] texID The texture ID.
|
||||
* @param[in] M the matrix. NULL keeps the matrix as it was in the last invocation.
|
||||
*/
|
||||
void drawTriMesh(unsigned numPts, const float* xyz, const float* uv,
|
||||
unsigned numIndices, const unsigned char* indices, GLuint texID, const float* M = nullptr) {
|
||||
drawElements(numPts, xyz, uv, GL_TRIANGLES, numIndices, GL_UNSIGNED_BYTE, indices, texID, M);
|
||||
}
|
||||
void drawTriMesh(unsigned numPts, const float* xyz, const float* uv,
|
||||
unsigned numIndices, const unsigned short* indices, GLuint texID, const float* M = nullptr) {
|
||||
drawElements(numPts, xyz, uv, GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, indices, texID, M);
|
||||
}
|
||||
void drawTriMesh(unsigned numPts, const float* xyz, const float* uv,
|
||||
unsigned numIndices, const unsigned int* indices, GLuint texID, const float* M = nullptr) {
|
||||
drawElements(numPts, xyz, uv, GL_TRIANGLES, numIndices, GL_UNSIGNED_INT, indices, texID, M);
|
||||
}
|
||||
|
||||
/** Draw a texture-mapped quadrilateral.
|
||||
* @param[in] xyz The vertex locations {x, y, z }.
|
||||
* @param[in] uv The vertex texture coordinates { u, v }, in [0, 1].
|
||||
* @param[in] texID The texture ID.
|
||||
* @param[in] M the matrix. NULL keeps the matrix as it was in the last invocation.
|
||||
*/
|
||||
void drawQuad(const float xyz[4 * 3], const float uv[4 * 2], GLuint texID, const float* M = nullptr);
|
||||
|
||||
/** These take vertex and topology data in GL buffer objects
|
||||
* @param[in] vtxBuf the vertex buffer object identifier.
|
||||
* @param[in] xyzOff the offset, in bytes, of the xyz positions in the vertex buffer.
|
||||
* @param[in] uvOff the offset, in bytes, of the texture coordinates in the vertex buffer.
|
||||
* @param[in] numIndices the number of indices.
|
||||
* @param[in] indexBuf the index buffer object identifier.
|
||||
* @param[in] indexSize the byte size of the indices: 1, 2, or 4.
|
||||
* @param[in] texID The texture ID.
|
||||
* @param[in] M the matrix. NULL keeps the matrix as it was in the last invocation.
|
||||
*/
|
||||
void drawTriMesh(GLuint vtxBuf, unsigned xyzOff, unsigned rgbOff,
|
||||
unsigned numIndices, GLuint indexBuf, GLenum indexSize, GLuint texID, const float* M) {
|
||||
drawElements(vtxBuf, xyzOff, rgbOff, GL_TRIANGLES, numIndices, indexSize, indexBuf, texID, M);
|
||||
}
|
||||
|
||||
private:
|
||||
/** Render geometry from user buffers.
|
||||
* @param[in] numVertices The number of 3D vertices.
|
||||
* @param[in] positions The array of 3D positions -- one for every vertex.
|
||||
* @param[in] uv The array of texture coordinates -- one for every vertex.
|
||||
* @param[in] graphicsMode One of { GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN }.
|
||||
* GL_QUADS is not supported.
|
||||
* @param[in] indexCount The number of 0-based vertex indices that define the geometry
|
||||
* from the vertices and graphics mode.
|
||||
* @param[in] indexType The type of index { GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT }.
|
||||
* @param[in] indices The array of vertices.
|
||||
* @param[in] texID The ID of the texture to be used.
|
||||
* @param[in] M The modeling-viewing-projection matrix.
|
||||
*/
|
||||
void drawElements(GLsizei numVertices, const GLfloat* positions, const GLfloat* uv, GLenum graphicsMode,
|
||||
GLsizei indexCount, GLenum indexType, const GLvoid* indices, GLuint texID, const GLfloat* M);
|
||||
|
||||
/** Render geometry from GL buffer objects.
|
||||
* @param[in] vtxBuf The ID of the GL buffer used to store the vertices.
|
||||
* @param[in] posOff The offset of the positions in the vertex buffer. This is typically 0,
|
||||
* but is not restricted so.
|
||||
* @param[in] uvOff The offset of the texture coordinates in the vertex buffer. Both planar
|
||||
* (homogeneous, separate) and chunky (nonhomogeneous, interleaved)
|
||||
* representations are accommodated.
|
||||
* @param[in] graphicsMode One of { GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN }.
|
||||
* GL_QUADS is not supported.
|
||||
* @param[in] indexCount The number of 0-based vertex indices that define the geometry
|
||||
* from the vertices and graphics mode.
|
||||
* @param[in] indexSize The size of index { 1, 2, 4 } in bytes.
|
||||
* @param[in] indexBuf The ID of the GL buffer used to store the indices.
|
||||
* @param[in] texID The ID of the texture to be used.
|
||||
* @param[in] M The modeling-viewing-projection matrix.
|
||||
*/
|
||||
void drawElements(GLuint vtxBuf, unsigned posOff, unsigned uvOff, GLenum graphicsMode,
|
||||
GLsizei indexCount, GLenum indexSize, GLuint indexBuf, GLuint texID, const GLfloat* M);
|
||||
|
||||
GLuint _programID;
|
||||
GLint _maxtrixID, _vtxPosID, _vtxTexID;
|
||||
static const char _vertexShader[], _fragmentShader[];
|
||||
};
|
||||
|
||||
|
||||
/** Update the specified texture.
|
||||
* @param[in] texID The ID of the texture to be updated.
|
||||
* @param[in] width The width of the source image.
|
||||
* @param[in] height The height of the source image.
|
||||
* @param[in] rowBytes The byte stride between pixels vertically in the source image (must be positive).
|
||||
* @param[in] glFormat The format of the source image. One of { GL_RGBA, GL_BGRA, GL_RGB, GL_BGR, GL_RG, GL_R }.
|
||||
* @param[in] pixels A pointer to pixel(0,0) of the source image.
|
||||
* @return GL_NO_ERROR if the update was successful.
|
||||
*/
|
||||
GLenum UpdateTexture(GLint texID, GLsizei width, GLsizei height, GLsizei rowBytes, GLenum glFormat,
|
||||
const GLvoid* pixels);
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
********************************************************************************
|
||||
***** LAMBERTIAN SHADER *****
|
||||
********************************************************************************
|
||||
********************************************************************************/
|
||||
|
||||
/** The camera is assumed to be at the origin. Lights are represented in the camera coordinate system.
|
||||
* The model coordinates are transformed M * pt;
|
||||
* the normal transformed by (M{3x3})^(-1)^(T), or simply M{3x3} assuming the scaling is isotropic.
|
||||
* We further assume that M{3x3} is orthonormal.
|
||||
*/
|
||||
class LambertianRenderer {
|
||||
public:
|
||||
#define LAMBERTIAN_NUM_LIGHTS 2
|
||||
|
||||
LambertianRenderer() { _programID = 0; }
|
||||
~LambertianRenderer() { shutdown(); }
|
||||
|
||||
int startup();
|
||||
void shutdown() { if (_programID) glDeleteProgram(_programID); _programID = 0; }
|
||||
int use();
|
||||
|
||||
/** Set all lights. We accommodate point lights or directional lights.
|
||||
* These are specified in camera space, which we assume is fixed while the objects move.
|
||||
* @param[in] locXYZW The location of the lights -- in camera space.
|
||||
* The homogeneous coordinate W is used to choose between
|
||||
* directional lights (W=0) and point lights (W=1).
|
||||
* The result is undefined for other values of W.
|
||||
* @param[in] colorRGB the emissive color of the light source, RGB in [0, 1].
|
||||
* To turn a light off, set its emissive color to (0,0,0).
|
||||
*/
|
||||
void setLights(const float locXYZW[4 * LAMBERTIAN_NUM_LIGHTS], const float colorRGB[3 * LAMBERTIAN_NUM_LIGHTS]);
|
||||
|
||||
/* These take vertex and topology data in user-space buffers.
|
||||
* @param[in] numPts The number of points in xyz or normals.
|
||||
* @param[in] xyz The vertex locations {x, y, z}.
|
||||
* @param[in] nrm The vertex normals {nx, ny, nz}.
|
||||
* @param[in] numIndices The number of indices.
|
||||
* @param[in] indices The indices. Note that three versions are given, where indices can be 1, 2, or 4 bytes.
|
||||
* @param[in] M The modeling matrix. If NULL, the previous matrix will be used.
|
||||
* @param[in] VP The viewing+projection matrix. If NULL, the previous matrix will be used.
|
||||
* @param[in] Ka The ambient color {r, g, b}. If NULL, the previous ambient color will be used.
|
||||
* @param[in] Kd The diffuse color {r, g, b}. If NULL, the previous diffuse color will be used.
|
||||
*/
|
||||
void drawTriMesh(unsigned numPts, const float* xyz, const float* nrm, unsigned numIndices, const unsigned char* indices,
|
||||
const float* M = nullptr, const float* VP = nullptr, const float* Ka = nullptr, const float* Kd = nullptr) {
|
||||
drawElements(numPts, xyz, nrm, GL_TRIANGLES, numIndices, GL_UNSIGNED_BYTE, indices, M, VP, Ka, Kd);
|
||||
}
|
||||
void drawTriMesh(unsigned numPts, const float* xyz, const float* nrm, unsigned numIndices, const unsigned short* indices,
|
||||
const float* M = nullptr, const float* VP = nullptr, const float* Ka = nullptr, const float* Kd = nullptr) {
|
||||
drawElements(numPts, xyz, nrm, GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, indices, M, VP, Ka, Kd);
|
||||
}
|
||||
void drawTriMesh(unsigned numPts, const float* xyz, const float* nrm, unsigned numIndices, const unsigned int* indices,
|
||||
const float* M = nullptr, const float* VP = nullptr, const float* Ka = nullptr, const float* Kd = nullptr) {
|
||||
drawElements(numPts, xyz, nrm, GL_TRIANGLES, numIndices, GL_UNSIGNED_INT, indices, M, VP, Ka, Kd);
|
||||
}
|
||||
|
||||
/* These take vertex and topology data in GL buffer objects
|
||||
* @param[in] vtxBuf the vertex buffer object identifier.
|
||||
* @param[in] xyzOff the offset, in bytes, of the xyz positions in the vertex buffer.
|
||||
* @param[in] nrmOff the offset, in bytes, of the normals in the vertex buffer.
|
||||
* @param[in] numIndices the number of indices.
|
||||
* @param[in] indexBuf the index buffer object identifier.
|
||||
* @param[in] indexSize the byte size of the indices: 1, 2, or 4.
|
||||
* @param[in] M The modeling matrix. If NULL, the previous matrix will be used.
|
||||
* @param[in] VP The viewing+projection matrix. If NULL, the previous matrix will be used.
|
||||
* @param[in] Ka The ambient color {r, g, b}. If NULL, the previous ambient color will be used.
|
||||
* @param[in] Kd The diffuse color {r, g, b}. If NULL, the previous diffuse color will be used.
|
||||
*/
|
||||
void drawTriMesh(GLuint vtxBuf, unsigned xyzOff, unsigned rgbOff, unsigned numIndices, GLuint indexBuf, GLenum indexSize,
|
||||
const float* M = nullptr, const float* VP = nullptr, const float* Ka = nullptr, const float* Kd = nullptr) {
|
||||
drawElements(vtxBuf, xyzOff, rgbOff, GL_TRIANGLES, numIndices, indexSize, indexBuf, M, VP, Ka, Kd);
|
||||
}
|
||||
|
||||
private:
|
||||
/** Render geometry from user buffers.
|
||||
* @param[in] numVertices The number of 3D vertices.
|
||||
* @param[in] positions The array of 3D positions -- one for every vertex.
|
||||
* @param[in] normals The array of normals -- one for every vertex.
|
||||
* @param[in] graphicsMode One of { GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN }.
|
||||
* GL_QUADS is not supported.
|
||||
* @param[in] indexCount The number of 0-based vertex indices that define the geometry
|
||||
* from the vertices and graphics mode.
|
||||
* @param[in] indexType The type of index { GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT }.
|
||||
* @param[in] indices The array of vertices.
|
||||
* @param[in] MV The modeling-viewing matrix.
|
||||
* @param[in] P The projection matrix.
|
||||
* @param[in] Ka The ambient color.
|
||||
* @param[in] Kd The diffuse color.
|
||||
*/
|
||||
void drawElements(GLsizei numVertices, const GLfloat* positions, const GLfloat* normals,
|
||||
GLenum graphicsMode, GLsizei indexCount, GLenum indexType, const GLvoid* indices,
|
||||
const GLfloat M[4 * 4], const GLfloat VP[4 * 4], const float Ka[3], const float Kd[3]);
|
||||
|
||||
/** Render geometry from GL buffer objects.
|
||||
* @param[in] vtxBuf The ID of the GL buffer used to store the vertices.
|
||||
* @param[in] posOff The offset of the positions in the vertex buffer. This is typically 0,
|
||||
* but is not restricted so.
|
||||
* @param[in] nrmOff The offset of the normals in the vertex buffer. Both planar (homogeneous, separate)
|
||||
* and chunky (nonhomogeneous, interleaved) representations are accommodated.
|
||||
* @param[in] graphicsMode One of { GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN }.
|
||||
* GL_QUADS is not supported.
|
||||
* @param[in] numIndices The number of 0-based vertex indices that define the geometry
|
||||
* from the vertices and graphics mode.
|
||||
* @param[in] indexSize The size of index { 1, 2, 4 } in bytes.
|
||||
* @param[in] indexBuf The ID of the GL buffer used to store the indices.
|
||||
* @param[in] M The modeling matrix.
|
||||
* @param[in] VP The viewing+projection matrix.
|
||||
* @param[in] Ka The ambient color.
|
||||
* @param[in] Kd The diffuse color.
|
||||
*/
|
||||
void drawElements(GLuint vtxBuf, unsigned posOff, unsigned nrmOff,
|
||||
GLenum graphicsMode, GLsizei numIndices, unsigned indexSize, GLuint indexBuf,
|
||||
const GLfloat M[4 * 4], const GLfloat VP[4 * 4], const float Ka[3], const float Kd[3]);
|
||||
|
||||
GLuint _programID;
|
||||
GLint _MmatrixID, _VPmatrixID, _lightLoc, _lightColor, _ambientColorID, _diffuseColorID;
|
||||
GLint _vtxPosID, _vtxNrmID;
|
||||
static const char _vertexShader[], _fragmentShader[];
|
||||
};
|
||||
|
||||
|
||||
#endif /* __ARSHADERS_H__ */
|
||||
106
samples/ExpressionApp/BackEndOpenGL/GLSpectrum.h
Normal file
106
samples/ExpressionApp/BackEndOpenGL/GLSpectrum.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/*###############################################################################
|
||||
#
|
||||
# Copyright 2016-2021 NVIDIA Corporation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
###############################################################################*/
|
||||
|
||||
#ifndef __GLSPECTRUM_H
|
||||
#define __GLSPECTRUM_H
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// The representation used for spectral parameters in surface illumination transport.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct GLSpectrum3f {
|
||||
float r, g, b; ///< Red, green and blue components of the color spectrum.
|
||||
|
||||
/// Default constructor.
|
||||
GLSpectrum3f() {}
|
||||
|
||||
/// Initialization constructor.
|
||||
/// @param[in] R the red component.
|
||||
/// @param[in] G the green component.
|
||||
/// @param[in] B the blue component.
|
||||
GLSpectrum3f(float R, float G, float B) { set(R, G, B); }
|
||||
|
||||
/// Access to the array of spectral components.
|
||||
/// @return a pointer to the array of spectral components.
|
||||
const float* data() const { return &r; }
|
||||
|
||||
/// Access to the array of spectral components.
|
||||
/// @return a pointer to the array of spectral components.
|
||||
float* data() { return &r; }
|
||||
|
||||
/// Set the spectral components.
|
||||
/// @param[in] R the red component.
|
||||
/// @param[in] G the green component.
|
||||
/// @param[in] B the blue component.
|
||||
void set(float R, float G, float B) { r = R; g = G; b = B; };
|
||||
|
||||
/// Componentwise scaling of the spectrum.
|
||||
/// @param[in] the scaling spectrum (RHS).
|
||||
/// @return The LHS, scaled by the RHS.
|
||||
GLSpectrum3f& operator*=(const GLSpectrum3f& k) { r *= k.r; g *= k.g; b *= k.b; return *this; }
|
||||
|
||||
/// Componentwise augmentation of the spectrum.
|
||||
/// @param[in] the delta spectrum (RHS).
|
||||
/// @return The LHS, augmented by the RHS.
|
||||
GLSpectrum3f& operator+=(const GLSpectrum3f& k) { r += k.r; g += k.g; b += k.b; return *this; }
|
||||
|
||||
/// Scalar scaling of the spectrum.
|
||||
/// @param[in] the scalar (RHS).
|
||||
/// @return The LHS, scaled by the RHS.
|
||||
GLSpectrum3f& operator*=(float s) { r *= s; g *= s; b *= s; return *this; }
|
||||
|
||||
/// Scalar scaling of the spectrum.
|
||||
/// @param[in] the scalar (RHS).
|
||||
/// @return The LHS, scaled by the RHS.
|
||||
GLSpectrum3f& operator/=(float s) { r /= s; g /= s; b /= s; return *this; }
|
||||
|
||||
/// Componentwise scaling of the spectrum.
|
||||
/// @param[in] k the scaling spectrum (RHS).
|
||||
/// @return The componentwise product of the LHS and RHS.
|
||||
GLSpectrum3f operator*(const GLSpectrum3f& k) const { return GLSpectrum3f(r * k.r, g * k.g, b * k.b); }
|
||||
|
||||
/// Componentwise augmentation of the spectrum.
|
||||
/// @param[in] k the scale vector (RHS).
|
||||
/// @return The componentwise sum of the LHS and RHS.
|
||||
GLSpectrum3f operator+(const GLSpectrum3f& k) const { return GLSpectrum3f(r + k.r, g + k.g, b + k.b); }
|
||||
|
||||
/// Scalar scaling of the spectrum.
|
||||
/// @param[in] s the scalar (RHS).
|
||||
/// @return The product of the LHS and the RHS scalar.
|
||||
GLSpectrum3f operator*(float s) const { return GLSpectrum3f(r * s, g * s, b * s); }
|
||||
|
||||
/// Scalar scaling of the spectrum.
|
||||
/// @param[in] s the scalar (RHS).
|
||||
/// @return The product of the LHS and the RHS scalar.
|
||||
GLSpectrum3f operator/(float s) const { return GLSpectrum3f(r / s, g / s, b / s); }
|
||||
};
|
||||
|
||||
/// Scalar scaling of the spectrum.
|
||||
/// @param[in] s the scalar (LHS).
|
||||
/// @param[in] k the spectrum to be scaled (RHS).
|
||||
/// @return The product of the RHS and the scalar LHS.
|
||||
inline GLSpectrum3f operator*(float s, const GLSpectrum3f& k) { return GLSpectrum3f(s * k.r, s * k.g, s * k.b); }
|
||||
|
||||
|
||||
#endif // __GLSPECTRUM_H
|
||||
645
samples/ExpressionApp/BackEndOpenGL/OpenGLMeshRenderer.cpp
Normal file
645
samples/ExpressionApp/BackEndOpenGL/OpenGLMeshRenderer.cpp
Normal file
@@ -0,0 +1,645 @@
|
||||
/*###############################################################################
|
||||
#
|
||||
# Copyright 2021 NVIDIA Corporation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
###############################################################################*/
|
||||
|
||||
#include "OpenGLMeshRenderer.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include "glad/glad.h"
|
||||
#define strcasecmp _stricmp
|
||||
#else
|
||||
#include <GLES3/gl3.h>
|
||||
#endif // _MSC_VER
|
||||
|
||||
#include "FaceIO.h"
|
||||
#include "GLFW/glfw3.h"
|
||||
#include "glm/glm.hpp"
|
||||
#include "glm/gtc/matrix_transform.hpp"
|
||||
#include "glm/gtc/quaternion.hpp"
|
||||
#include "GLMaterial.h"
|
||||
#include "GLMesh.h"
|
||||
#include "GLShaders.h"
|
||||
#include "GLSpectrum.h"
|
||||
#include "nvAR_defs.h"
|
||||
#include "nvCVOpenCV.h"
|
||||
#include "opencv2/highgui/highgui.hpp"
|
||||
#include "SimpleFaceModel.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
///// SUPPORT MACROS AND FUNCTIONS /////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define BAIL_IF_ERR(err) do { if ((err) != 0) { goto bail; } } while(0)
|
||||
#define BAIL(err, code) do { err = code; goto bail; } while(0)
|
||||
|
||||
#ifndef __BYTE_ORDER__ /* How bytes are packed into a 32 bit word */
|
||||
#define __ORDER_LITTLE_ENDIAN__ 3210 /* First byte in the least significant position */
|
||||
#define __ORDER_BIG_ENDIAN__ 0123 /* First byte in the most significant position */
|
||||
#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) || _MSC_VER
|
||||
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
|
||||
#endif /* _MSC_VER */
|
||||
#endif /* __BYTE_ORDER__ */
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* glfwErrorCallback
|
||||
********************************************************************************/
|
||||
|
||||
static void glfwErrorCallback(int error, const char *description) {
|
||||
fprintf(stderr, "Error %d: %s\n", error, description);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* MakeGLContext
|
||||
********************************************************************************/
|
||||
|
||||
static NvCV_Status MakeGLContext(int width, int height, const char *title, GLFWwindow **pWindow) {
|
||||
NvCV_Status nvErr = NVCV_SUCCESS;
|
||||
GLFWwindow *window;
|
||||
|
||||
/* Get a context */
|
||||
glfwSetErrorCallback(glfwErrorCallback);
|
||||
if (!glfwInit()) {
|
||||
// Initialization failed
|
||||
fprintf(stderr, "Unable to initialize glfw\n");
|
||||
return NVCV_ERR_INITIALIZATION;
|
||||
}
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
||||
window = glfwCreateWindow(width, height, title, /*GLFWmonitor */NULL, /*GLFWwindow*/NULL);
|
||||
if (!window) {
|
||||
// Window or OpenGL context creation failed
|
||||
fprintf(stderr, "Unable to create glfw window\n");
|
||||
BAIL(nvErr, NVCV_ERR_INITIALIZATION);
|
||||
}
|
||||
int winWidth, winHeight;
|
||||
glfwGetWindowSize(window, &winWidth, &winHeight);
|
||||
if (winWidth != width || winHeight != height) {
|
||||
fprintf(stderr, "getWindowSize(%u x %u) != (%u x %u)\n", winWidth, winHeight, width, height);
|
||||
}
|
||||
glfwMakeContextCurrent(window);
|
||||
#ifdef _MSC_VER
|
||||
if (!gladLoadGL()) {
|
||||
fprintf(stderr, "Unable to load GL\n");
|
||||
BAIL(nvErr, NVCV_ERR_INITIALIZATION);
|
||||
}
|
||||
fprintf(stderr, "OpenGL Version %d.%d loaded\n", GLVersion.major, GLVersion.minor);
|
||||
#endif // _MSC_VER
|
||||
*pWindow = window;
|
||||
|
||||
bail:
|
||||
return nvErr;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* CloseGLContext
|
||||
********************************************************************************/
|
||||
|
||||
static void CloseGLContext(GLFWwindow *window) {
|
||||
if (window)
|
||||
glfwDestroyWindow(window);
|
||||
glfwTerminate();
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* ComputeDualTopologyFromAdjacencies
|
||||
********************************************************************************/
|
||||
|
||||
static NvCV_Status ComputeDualTopologyFromAdjacencies(const SimpleFaceModelAdapter *fma, GLMesh *mesh) {
|
||||
union IVF {
|
||||
unsigned i;
|
||||
struct VF {
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
unsigned short face, vertex; // Vertex in most significant position
|
||||
#else // __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
unsigned short vertex, face; // Vertex in most significant position
|
||||
#endif // __BYTE_ORDER__
|
||||
} vf;
|
||||
bool operator<( const IVF& other) { return i < other.i; }
|
||||
bool operator==(const IVF& other) { return i == other.i; }
|
||||
};
|
||||
std::vector<IVF> topo;
|
||||
|
||||
topo.reserve(mesh->numVertices() * 6 * 2); // Assume valence-6, duplicated
|
||||
const unsigned short *adjVertices = const_cast<SimpleFaceModelAdapter*>(fma)->getAdjacentVertices(0),
|
||||
*adjFaces = const_cast<SimpleFaceModelAdapter*>(fma)->getAdjacentFaces(0);
|
||||
unsigned n = fma->getAdjacentVerticesSize();
|
||||
if (n != fma->getAdjacentFacesSize()) return NVCV_ERR_MISMATCH;
|
||||
for (unsigned ej = 0; ej < n; ej += 2) { // 2 adjacencies per edge
|
||||
for (unsigned vx = 0; vx < 2; ++vx) { // for every vertex on the edge
|
||||
for (unsigned fc = 0; fc < 2; ++fc) { // and every face on the edge
|
||||
IVF vf;
|
||||
vf.vf.vertex = adjVertices[ej + vx];
|
||||
vf.vf.face = adjFaces[ej + fc];
|
||||
if (vf.vf.vertex && vf.vf.face) { // if a real vertex and a real face
|
||||
--vf.vf.vertex; // convert from 1-based index ...
|
||||
--vf.vf.face; // ... to 0-based index
|
||||
topo.push_back(vf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
std::sort(topo.begin(), topo.end());
|
||||
topo.erase(std::unique(topo.begin(), topo.end()), topo.end());
|
||||
mesh->resizeDualIndices(unsigned(topo.size()));
|
||||
unsigned short *dual = mesh->getDualIndices(),
|
||||
*numFaces = mesh->getVertexFaceCounts();
|
||||
memset(numFaces, 0, mesh->numVertices() * sizeof(*numFaces));
|
||||
for (unsigned i = 0; i < topo.size(); ++i) {
|
||||
numFaces[topo[i].vf.vertex]++;
|
||||
dual[i] = topo[i].vf.face;
|
||||
}
|
||||
return NVCV_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* MakeMesh
|
||||
********************************************************************************/
|
||||
|
||||
NvCV_Status MakeMesh(const SimpleFaceModelAdapter *fma, GLMesh *mesh) {
|
||||
mesh->clear();
|
||||
mesh->addVertices(fma->getShapeMeanSize() / 3, const_cast<SimpleFaceModelAdapter*>(fma)->getShapeMean(0));
|
||||
mesh->addFaces(fma->getTriangleListSize() / 3, 3, const_cast<SimpleFaceModelAdapter*>(fma)->getTriangleList(0), 0, 0);
|
||||
NvCV_Status err = ComputeDualTopologyFromAdjacencies(fma, mesh); // This make vertex normal computation lightning fast
|
||||
if (NVCV_SUCCESS != err) return err;
|
||||
mesh->computeVertexNormals();
|
||||
if (fma->fm.partitions.size()) {
|
||||
std::vector<GLMesh::Partition> parts(fma->fm.partitions.size());
|
||||
for (unsigned i = unsigned(parts.size()); i--;) {
|
||||
const SimpleFaceModel::Partition& fr = fma->fm.partitions[i];
|
||||
GLMesh::Partition& to = parts[fr.partitionIndex];
|
||||
//to.partitionIndex = fr.partitionIndex; // to doesn't have a partitionIndex
|
||||
to.faceIndex = fr.faceIndex;
|
||||
to.numFaces = fr.numFaces;
|
||||
to.vertexIndex = fr.vertexIndex;
|
||||
to.numVertexIndices = fr.numVertexIndices;
|
||||
to.name = fr.name;
|
||||
to.materialName = fr.materialName;
|
||||
to.smooth = fr.smoothingGroup;
|
||||
}
|
||||
mesh->partitionMesh(unsigned(parts.size()), parts.data());
|
||||
}
|
||||
return NVCV_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
///// RENDER CONTEXT /////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define LAMBERTIAN_NUM_LIGHTS 2
|
||||
|
||||
class RenderContext {
|
||||
public:
|
||||
|
||||
RenderContext() {
|
||||
m_win = nullptr;
|
||||
}
|
||||
|
||||
~RenderContext() {
|
||||
if (m_win) CloseGLContext(m_win);
|
||||
m_lam.shutdown();
|
||||
m_txr.shutdown();
|
||||
}
|
||||
|
||||
NvCV_Status init() {
|
||||
if (0 != m_lam.startup())
|
||||
return NVCV_ERR_OPENGL;
|
||||
if (0 != m_txr.startup())
|
||||
return NVCV_ERR_OPENGL;
|
||||
return NVCV_SUCCESS;
|
||||
}
|
||||
|
||||
void setClearColor(float r, float g, float b, float a = 1.f) { glClearColor(r, g, b, a); }
|
||||
|
||||
void setClearColor(unsigned char r, unsigned char g, unsigned char b) {
|
||||
glClearColor(r * (1.f / 255.f), g * (1.f / 255.f), b * (1.f / 255.f), 1.f);
|
||||
}
|
||||
|
||||
NvCV_Status makeWindowContext(int wd, int ht, const char *title) {
|
||||
NvCV_Status err = MakeGLContext(wd, ht, title, &m_win);
|
||||
if (NVCV_SUCCESS == err) {
|
||||
m_width = wd;
|
||||
m_height = ht;
|
||||
glfwMakeContextCurrent(m_win);
|
||||
glViewport(0, 0, wd, ht);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glClearColor(0.f, 0.f, 0.f, 1.f);
|
||||
if (/*FLAG_orientation*/0) {
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace((/*FLAG_orientation*/0 > 0) ? GL_BACK : GL_FRONT);
|
||||
}
|
||||
else {
|
||||
glDisable(GL_CULL_FACE);
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
void computeInverseViewMatrix() {
|
||||
#if 0
|
||||
Vinv = glm::inverse(V);
|
||||
#else // Inversion is simple because we know that it is a rigid transform
|
||||
m_Vinv = glm::transpose(m_V);
|
||||
m_Vinv[3][0] = -(m_Vinv[0][0] * m_V[3][0] + m_Vinv[1][0] * m_V[3][1] + m_Vinv[2][0] * m_V[3][2]);
|
||||
m_Vinv[3][1] = -(m_Vinv[0][1] * m_V[3][0] + m_Vinv[1][1] * m_V[3][1] + m_Vinv[2][1] * m_V[3][2]);
|
||||
m_Vinv[3][2] = -(m_Vinv[0][2] * m_V[3][0] + m_Vinv[1][2] * m_V[3][1] + m_Vinv[2][2] * m_V[3][2]);
|
||||
m_Vinv[0][3] = 0.f; m_Vinv[1][3] = 0.f; m_Vinv[2][3] = 0.f; m_Vinv[3][3] = 1.f;
|
||||
#endif
|
||||
}
|
||||
|
||||
void setViewMatrix(const glm::mat4x4& viewMatrix) {
|
||||
m_V = viewMatrix;
|
||||
computeInverseViewMatrix();
|
||||
}
|
||||
|
||||
void setViewMatrix(const glm::vec3& fromPoint, const glm::vec3& toPoint, const glm::vec3& upVector) {
|
||||
m_V = glm::lookAt(fromPoint, toPoint, upVector);
|
||||
computeInverseViewMatrix();
|
||||
}
|
||||
|
||||
void setOrthoCamera(float hither, float yon) {
|
||||
m_P = glm::orthoLH_NO(m_width * -.5f, m_width * +.5f, m_height * -.5f, m_height * +.5f, hither, yon);
|
||||
}
|
||||
|
||||
void setOrthoCamera(float wd, float ht, float hither, float yon) {
|
||||
m_P = glm::orthoLH_NO(wd * -.5f, wd * +.5f, ht * -.5f, ht * +.5f, hither, yon);
|
||||
}
|
||||
|
||||
void setLights(const glm::vec4 locs[LAMBERTIAN_NUM_LIGHTS], const GLSpectrum3f colors[LAMBERTIAN_NUM_LIGHTS]) {
|
||||
memcpy(m_lightLoc, locs, sizeof(m_lightLoc));
|
||||
memcpy(m_lightColor, colors, sizeof(m_lightColor));
|
||||
}
|
||||
|
||||
void setViewOfBound(const GLMesh::BoundingSphere& bsph, const glm::vec3& lookAt, const glm::vec3& up, float vfov,
|
||||
float fracFill, float yDir = 1.f) {
|
||||
float r = bsph.radius() / fracFill,
|
||||
aspect = (float)m_width / (float)m_height,
|
||||
signZ = -yDir,
|
||||
dist;
|
||||
|
||||
if (vfov > 0) { // Perspective
|
||||
dist = r * .5f / tanf(vfov * .5f);
|
||||
m_P = glm::perspective(vfov, aspect, (dist - r) * 0.2f, (dist + r) * 2.0f);
|
||||
}
|
||||
else { // Orthographic
|
||||
float w = r,
|
||||
h = r;
|
||||
if (aspect < 1.f) h /= aspect; // Wide
|
||||
else w *= aspect; // Tall
|
||||
dist = r * 2.f;
|
||||
|
||||
m_P = glm::orthoLH_NO(-w, +w, -h, +h, (dist - r) * signZ, (dist + r) * signZ);
|
||||
}
|
||||
m_V = glm::lookAt(bsph.center() - glm::normalize(lookAt) * dist, bsph.center(), up);
|
||||
computeInverseViewMatrix();
|
||||
}
|
||||
|
||||
void setViewOfBound(const GLMesh::BoundingBox& bbox, const glm::vec3& lookAt, const glm::vec3& up, float vfov,
|
||||
float fracFill, float yDir = 1.f, float yOff = 0.f) {
|
||||
glm::vec3 boxSize = bbox.max() - bbox.min();
|
||||
glm::vec3 boxCenter = bbox.center();
|
||||
float borderFrac = ((1.f - fracFill) / fracFill),
|
||||
dx = boxSize.x * (1.f + borderFrac), // border on left and right
|
||||
dy = boxSize.y * (1.f + borderFrac) * (1.f - fabsf(yOff)),
|
||||
r = ((dx > dy) ? dx : dy), // radius of bounding sphere
|
||||
aspectGeom = dx / dy,
|
||||
aspectWind = (float)m_width / (float)m_height,
|
||||
signZ = -yDir,
|
||||
dist;
|
||||
|
||||
if (vfov > 0) { // Perspective
|
||||
dist = r * .5f / tanf(vfov * .5f);
|
||||
m_P = glm::perspective(vfov, aspectWind, dist - r, dist + r);
|
||||
}
|
||||
else { // Orthographic
|
||||
if (aspectGeom > aspectWind) dy *= aspectGeom / aspectWind;
|
||||
else dx *= aspectWind / aspectGeom;
|
||||
dist = r * 2.f;
|
||||
dx *= .5f;
|
||||
dy *= .5f;
|
||||
m_P = glm::orthoLH_NO(-dx, +dx, -dy, +dy, (dist - r) * signZ, (dist + r) * signZ);
|
||||
}
|
||||
boxCenter.y += boxSize.y * yOff;
|
||||
m_V = glm::lookAt(boxCenter - glm::normalize(lookAt) * dist, boxCenter, up);
|
||||
computeInverseViewMatrix();
|
||||
}
|
||||
|
||||
NvCV_Status renderPolyMesh(const GLMesh& mesh, const glm::mat4x4& M, const char *materialOverride = nullptr) {
|
||||
NvCV_Status nvErr = NVCV_SUCCESS;
|
||||
glm::mat4x4 VP = m_P * m_V;
|
||||
const GLSpectrum3f defaultDiffuse = { 0.77f, 0.63f, 0.55f },
|
||||
defaultAmbient = defaultDiffuse * 0.3f;
|
||||
|
||||
#ifdef DEBUG_RENDERING
|
||||
unsigned why = mesh.notRenderable(0);
|
||||
if (why) {
|
||||
if (FLAG_debug)
|
||||
printf("Mesh %p is not renderable: %s: %s\n", &mesh,
|
||||
((why & GLMesh::NOT_TRIMESH) ? "not a TriMesh" : ""),
|
||||
((why & GLMesh::COMPLEX_TOPOLOGY) ? "complex topology" : "")
|
||||
);
|
||||
return keErrGeometry;
|
||||
}
|
||||
#endif // DEBUG_RENDERING
|
||||
|
||||
// Set lights for all shaders
|
||||
m_lam.setLights(&m_lightLoc[0].x, m_lightColor[0].data()); // TODO: set this elsewhere
|
||||
|
||||
for (unsigned ix = 0, numPartitions = mesh.numPartitions(); ix < numPartitions; ++ix) {
|
||||
GLMesh::Partition pt;
|
||||
nvErr = mesh.getPartition(ix, pt);
|
||||
BAIL_IF_ERR(nvErr);
|
||||
const GLMaterial *mtl = m_mtlLib.getMaterial(materialOverride ? materialOverride : pt.materialName.c_str());
|
||||
|
||||
if (mesh.numNormals()) { // We should check for textures, too
|
||||
const GLSpectrum3f *difColor, *ambColor;
|
||||
if (mtl) {
|
||||
difColor = &mtl->diffuseColor;
|
||||
ambColor = &mtl->ambientColor;
|
||||
}
|
||||
else {
|
||||
difColor = &defaultDiffuse;
|
||||
ambColor = &defaultAmbient;
|
||||
}
|
||||
m_lam.drawTriMesh(mesh.numVertices(), &mesh.getVertices()->x, &mesh.getNormals()->x,
|
||||
pt.numVertexIndices, mesh.getVertexIndices() + pt.vertexIndex, &M[0][0], &VP[0][0],
|
||||
ambColor->data(), difColor->data());
|
||||
}
|
||||
}
|
||||
|
||||
bail:
|
||||
return nvErr;
|
||||
}
|
||||
|
||||
unsigned m_width, m_height; ///< The dimensions of the viewport.
|
||||
GLFWwindow *m_win; ///< The window context.
|
||||
GLMaterialLibrary m_mtlLib; ///< The material library.
|
||||
glm::mat4x4 m_V, m_Vinv; ///< The viewing matrix and its inverse.
|
||||
glm::mat4x4 m_P; ///< The projection matrix.
|
||||
glm::vec4 m_lightLoc[LAMBERTIAN_NUM_LIGHTS]; ///< The light locations.
|
||||
GLSpectrum3f m_lightColor[LAMBERTIAN_NUM_LIGHTS]; ///< The light colors.
|
||||
LambertianRenderer m_lam; ///< The Lambertian renderer.
|
||||
TextureRenderer m_txr; ///< The texture renderer.
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
///// OPENGL MESH RENDERER /////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class OpenGLMeshRenderer : public MeshRenderer {
|
||||
public:
|
||||
~OpenGLMeshRenderer();
|
||||
|
||||
static NvCV_Status initDispatch(MeshRenderer::Dispatch *dispatch);
|
||||
static NvCV_Status unload();
|
||||
|
||||
private:
|
||||
OpenGLMeshRenderer();
|
||||
SimpleFaceModelAdapter _sfma;
|
||||
RenderContext _ctx;
|
||||
GLMesh _mesh;
|
||||
glm::vec3 _ctrRot;
|
||||
|
||||
// C-style object-oriented member functions that are usually loaded from DLL, although in this implementation
|
||||
// the OpenGLMeshRenderer is compiled directly into the ExpressionApp, and the MeshRendererBroker is
|
||||
// automatically adding it to its portfolio of renderers without creating a separate DLL.
|
||||
static NvCV_Status create(MeshRenderer **han);
|
||||
static void destroy(MeshRenderer *han);
|
||||
static NvCV_Status name(const char **str);
|
||||
static NvCV_Status info(const char **str);
|
||||
static NvCV_Status read(MeshRenderer *han, const char *modelFile);
|
||||
static NvCV_Status init(MeshRenderer *han, unsigned width, unsigned height, const char *windowName);
|
||||
static NvCV_Status setCamera(MeshRenderer *han,
|
||||
const float locPt[3], const float lookVec[3], const float upVec[3], float vfov);
|
||||
static NvCV_Status render(MeshRenderer *han,
|
||||
const float exprs[53], const float qrot[4], const float tran[3], NvCVImage *result);
|
||||
NvCV_Status setFOV(float radians);
|
||||
};
|
||||
|
||||
NvCV_Status OpenGLMeshRenderer_InitDispatch(MeshRenderer::Dispatch *dispatch) {
|
||||
return OpenGLMeshRenderer::initDispatch(dispatch);
|
||||
}
|
||||
|
||||
NvCV_Status OpenGLMeshRenderer_Unload() {
|
||||
return OpenGLMeshRenderer::unload();
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* DeformModel
|
||||
********************************************************************************/
|
||||
|
||||
static NvCV_Status DeformModel(const SimpleFaceModel& model, const float *identCoeffs, const float *exprCoeffs, GLMesh *mesh) {
|
||||
unsigned size = unsigned(model.shapeMean.size()) * 3, // the number of floats in the mesh vector
|
||||
numCoeffs, i;
|
||||
float *const dst0 = &mesh->getVertices()->x, // begin
|
||||
*const dst1 = dst0 + size; // end
|
||||
float const *src;
|
||||
float *dst, c;
|
||||
|
||||
memcpy(dst0, model.shapeMean.data(), size * sizeof(*dst0)); // Initialize
|
||||
if (identCoeffs) {
|
||||
for (i = 0, numCoeffs = unsigned(model.shapeEigenValues.size()), src = model.shapeModes.data()->vec; i < numCoeffs; ++i, ++identCoeffs) {
|
||||
if ((c = *identCoeffs) != 0.f) {
|
||||
for (dst = dst0; dst != dst1;)
|
||||
*dst++ += *src++ * c;
|
||||
}
|
||||
else {
|
||||
src += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0, numCoeffs = unsigned(model.blendShapes.size()); i < numCoeffs; ++i, ++exprCoeffs) {
|
||||
if ((c = *exprCoeffs) != 0.f) {
|
||||
for (dst = dst0, src = model.blendShapes[i].shape.data()->vec; dst != dst1;)
|
||||
*dst++ += *src++ * c;
|
||||
}
|
||||
}
|
||||
mesh->computeVertexNormals();
|
||||
return NVCV_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
OpenGLMeshRenderer::OpenGLMeshRenderer() {
|
||||
/*NvCV_Status err =*/ (void)initDispatch(&this->m_dispatch);
|
||||
}
|
||||
|
||||
OpenGLMeshRenderer::~OpenGLMeshRenderer() {
|
||||
}
|
||||
|
||||
NvCV_Status OpenGLMeshRenderer::name(const char **str) {
|
||||
static const char name[] = "OpenGL";
|
||||
*str = name;
|
||||
return NVCV_SUCCESS;
|
||||
}
|
||||
|
||||
NvCV_Status OpenGLMeshRenderer::info(const char **str) {
|
||||
static const char info[] = "OpenGL renderer using local illumination";
|
||||
*str = info;
|
||||
return NVCV_SUCCESS;
|
||||
}
|
||||
|
||||
NvCV_Status OpenGLMeshRenderer::create(MeshRenderer **han) {
|
||||
*han = new OpenGLMeshRenderer();
|
||||
return NVCV_SUCCESS;
|
||||
}
|
||||
|
||||
void OpenGLMeshRenderer::destroy(MeshRenderer* /*han*/) {
|
||||
}
|
||||
|
||||
NvCV_Status OpenGLMeshRenderer::read(MeshRenderer *han, const char *modelFile) {
|
||||
OpenGLMeshRenderer *ren = static_cast<OpenGLMeshRenderer*>(han);
|
||||
size_t z = strlen(modelFile);
|
||||
if (z < 5) return NVCV_ERR_FILE;
|
||||
if (!strcasecmp(".nvf", modelFile + z - 4)) {
|
||||
FaceIOErr ioErr = ReadNVFFaceModel(modelFile, &ren->_sfma); // TODO clear _sfma first
|
||||
if (kIOErrNone != ioErr) {
|
||||
printf("Error: \"%s\": %s\n", modelFile, FaceIOErrorStringFromCode(ioErr));
|
||||
return NVCV_ERR_READ;
|
||||
}
|
||||
NvCV_Status nvErr;
|
||||
nvErr = MakeMesh(&ren->_sfma, &ren->_mesh);
|
||||
if (NVCV_SUCCESS != nvErr) return nvErr;
|
||||
|
||||
std::string mtlFile;
|
||||
mtlFile.assign(modelFile, 0, strlen(modelFile) - 3);
|
||||
mtlFile += "mtl";
|
||||
nvErr = ren->_ctx.m_mtlLib.read(mtlFile.c_str());
|
||||
unsigned why = ren->_mesh.notRenderable(0);
|
||||
if (why) {
|
||||
printf("Mesh \"%s\" is not renderable: %s: %s\n", modelFile,
|
||||
((why & GLMesh::NOT_TRIMESH) ? "not a TriMesh" : ""),
|
||||
((why & GLMesh::COMPLEX_TOPOLOGY) ? "complex topology" : "")
|
||||
);
|
||||
return NVCV_ERR_MISMATCH;
|
||||
}
|
||||
return NVCV_SUCCESS;
|
||||
}
|
||||
// else if (!strcasecmp(".obj", file + z - 4)) { read obj files }
|
||||
else {
|
||||
return NVCV_ERR_FILE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
NvCV_Status OpenGLMeshRenderer::init(MeshRenderer *han,
|
||||
unsigned width, unsigned height, const char *windowName) {
|
||||
OpenGLMeshRenderer *ren = static_cast<OpenGLMeshRenderer*>(han);
|
||||
static const GLSpectrum3f lightColor[LAMBERTIAN_NUM_LIGHTS] = { { 1.f, 1.f, 1.f }, { .8f, .1f, .1f } };
|
||||
static const glm::vec4 lightLoc[LAMBERTIAN_NUM_LIGHTS] = { { 0, 0, +1000, 0}, { 100, -200, -500, 0 } };
|
||||
NvCV_Status nvErr;
|
||||
|
||||
nvErr = ren->_ctx.makeWindowContext(width, height, windowName);
|
||||
nvErr = ren->_ctx.init();
|
||||
ren->_ctx.setClearColor(0.2f, 0.2f, 0.2f, 1.f);
|
||||
ren->_ctx.setLights(lightLoc, lightColor);
|
||||
ren->setFOV(0.f); // Default orthographic
|
||||
return NVCV_SUCCESS;
|
||||
}
|
||||
|
||||
NvCV_Status OpenGLMeshRenderer::setFOV(float fov) {
|
||||
if (0 == _mesh.numVertices())
|
||||
return NVCV_ERR_MODEL;
|
||||
GLMesh::BoundingBox bbox;
|
||||
_mesh.getBoundingBox(&bbox);
|
||||
_ctrRot = bbox.center();
|
||||
_ctrRot.y = bbox.min().y; // Assume that assets are designed with Y-up.
|
||||
float vShift = (_mesh.numVertices() > 10000) ? 0.15f : 0.0f; // Heuristic to determine whether there is a neck
|
||||
_ctx.setViewOfBound(bbox, glm::vec3(0.f, 0.f, -1.f), glm::vec3(0.f, +1.f, 0.f), fov, .9f, +1, vShift);
|
||||
return NVCV_SUCCESS;
|
||||
}
|
||||
|
||||
NvCV_Status OpenGLMeshRenderer::setCamera(MeshRenderer *han,
|
||||
const float locPt[3], const float lookVec[3], const float upVec[3], float vfov) {
|
||||
if (locPt || lookVec || upVec) {} // We don't accommodate these yet
|
||||
return static_cast<OpenGLMeshRenderer*>(han)->setFOV(vfov);
|
||||
}
|
||||
|
||||
NvCV_Status OpenGLMeshRenderer::render(MeshRenderer *han,
|
||||
const float exprs[53], const float qrot[4], const float* /*tran*/, NvCVImage *result) {
|
||||
OpenGLMeshRenderer *ren = static_cast<OpenGLMeshRenderer*>(han);
|
||||
NvCV_Status nvErr;
|
||||
glm::mat4x4 M;
|
||||
glm::quat q; // Convert quaternion from {x,y,z,w} --> GLM's {w,x,y,z}
|
||||
|
||||
if (NVCV_RGBA != result->pixelFormat)
|
||||
return NVCV_ERR_PIXELFORMAT;
|
||||
|
||||
if (qrot) { q.x = qrot[0]; q.y = qrot[1]; q.z = qrot[2]; q.w = qrot[3]; }
|
||||
else { q.x = 0.0f; q.y = 0.0f; q.z = 0.0f; q.w = 1.0f; }
|
||||
|
||||
#ifndef TRANSLATE_POSE
|
||||
M = glm::translate(glm::mat4x4(1.f), -ren->_ctrRot);
|
||||
M = glm::mat4_cast(q) * M;
|
||||
M = glm::translate(M, ren->_ctrRot);
|
||||
#else // TRANSLATE_POSE
|
||||
M = glm::mat4_cast(q);
|
||||
if (tran)
|
||||
M = glm::translate(M, *((const glm::vec3*)(trans)));
|
||||
#endif // TRANSLATE_POSE
|
||||
|
||||
nvErr = DeformModel(ren->_sfma.fm, nullptr, exprs, &ren->_mesh);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
nvErr = ren->_ctx.renderPolyMesh(ren->_mesh, M, NULL);
|
||||
glReadPixels(0, 0, result->width, result->height, GL_RGBA, GL_UNSIGNED_BYTE, result->pixels);
|
||||
GLenum glErr = glGetError();
|
||||
if (glErr)
|
||||
return NVCV_ERR_OPENGL;
|
||||
// GL returns an image upside-down, but we can use the NvCVImage_FlipY in the caller to flip it with no overhead
|
||||
return NVCV_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
NvCV_Status OpenGLMeshRenderer::initDispatch(MeshRenderer::Dispatch *dispatch) {
|
||||
dispatch->name = &OpenGLMeshRenderer::name;
|
||||
dispatch->info = &OpenGLMeshRenderer::info;
|
||||
dispatch->create = &OpenGLMeshRenderer::create;
|
||||
dispatch->destroy = &OpenGLMeshRenderer::destroy;
|
||||
dispatch->read = &OpenGLMeshRenderer::read;
|
||||
dispatch->init = &OpenGLMeshRenderer::init;
|
||||
dispatch->setCamera = &OpenGLMeshRenderer::setCamera;
|
||||
dispatch->render = &OpenGLMeshRenderer::render;
|
||||
return NVCV_SUCCESS;
|
||||
}
|
||||
|
||||
NvCV_Status OpenGLMeshRenderer::unload() {
|
||||
return NVCV_SUCCESS;
|
||||
}
|
||||
41
samples/ExpressionApp/BackEndOpenGL/OpenGLMeshRenderer.h
Normal file
41
samples/ExpressionApp/BackEndOpenGL/OpenGLMeshRenderer.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*###############################################################################
|
||||
#
|
||||
# Copyright 2021 NVIDIA Corporation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
###############################################################################*/
|
||||
|
||||
#ifndef __OPENGL_MESH_RENDERER__
|
||||
#define __OPENGL_MESH_RENDERER__
|
||||
|
||||
#include "MeshRenderer.h"
|
||||
|
||||
|
||||
/// Initialize the renderer dispatch table.
|
||||
/// @param[out] dispatch the dispatch table.
|
||||
/// @return NVCV_SUCCESS if successful.
|
||||
NvCV_Status OpenGLMeshRenderer_InitDispatch(MeshRenderer::Dispatch *dispatch);
|
||||
|
||||
/// Unload the OpenGL Mesh Renderer from memory.
|
||||
/// @note Any previously initialized dispatch tables will be invalid.
|
||||
/// @return NVCV_SUCCESS if successful.
|
||||
NvCV_Status OpenGLMeshRenderer_Unload();
|
||||
|
||||
|
||||
#endif // __OPENGL_MESH_RENDERER__
|
||||
245
samples/ExpressionApp/BackEndOpenGL/SimpleFaceModel.h
Normal file
245
samples/ExpressionApp/BackEndOpenGL/SimpleFaceModel.h
Normal file
@@ -0,0 +1,245 @@
|
||||
/*###############################################################################
|
||||
#
|
||||
# Copyright 2021 NVIDIA Corporation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
###############################################################################*/
|
||||
#ifndef __SIMPLE_FACE_MODEL__
|
||||
#define __SIMPLE_FACE_MODEL__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "FaceIO.h"
|
||||
#include "nvAR_defs.h"
|
||||
|
||||
/********************************************************************************
|
||||
* SimpleFaceModel
|
||||
********************************************************************************/
|
||||
|
||||
|
||||
struct SimpleFaceModel {
|
||||
std::vector<NvAR_Point3f> shapeMean;
|
||||
std::vector<NvAR_Vector3f> shapeModes; /* shapeMean.size() * numModes */
|
||||
std::vector<float> shapeEigenValues;
|
||||
std::vector<NvAR_Vector3u16> triangles;
|
||||
struct BlendShape {
|
||||
std::string name;
|
||||
std::vector<NvAR_Vector3f> shape;
|
||||
};
|
||||
std::vector<BlendShape> blendShapes;
|
||||
struct Partition {
|
||||
unsigned partitionIndex; ///< The index of the partition.
|
||||
unsigned faceIndex; ///< The index of the first face in the partition.
|
||||
unsigned numFaces; ///< The number of faces in the partition.
|
||||
unsigned vertexIndex; ///< The index of the first topological vertex in the partition.
|
||||
unsigned numVertexIndices; ///< The number of topological vertices in the partition.
|
||||
int smoothingGroup; ///< Smoothing group > 0; no smoothing == 0; undefined < 0.
|
||||
std::string name; ///< The name of the partition.
|
||||
std::string materialName; ///< The name of the material assigned to the partition.
|
||||
void set(unsigned partIx, unsigned firstFaceIndex, unsigned lastFaceIndex,
|
||||
unsigned firstVertexIndex, unsigned lastVertexIndex, int smooth,
|
||||
const char* partName = nullptr, const char* mtrlName = nullptr) {
|
||||
partitionIndex = partIx;
|
||||
smoothingGroup = smooth;
|
||||
faceIndex = firstFaceIndex;
|
||||
numFaces = lastFaceIndex - firstFaceIndex + 1;
|
||||
vertexIndex = firstVertexIndex;
|
||||
numVertexIndices = lastVertexIndex - firstVertexIndex + 1;
|
||||
if (partName) name = partName;
|
||||
if (mtrlName) materialName = mtrlName;
|
||||
}
|
||||
Partition(unsigned partIx, unsigned firstFaceIndex, unsigned lastFaceIndex,
|
||||
unsigned firstVertexIndex, unsigned lastVertexIndex, int smooth,
|
||||
const char* partName, const char* mtrlName) {
|
||||
set(partIx, firstFaceIndex, lastFaceIndex, firstVertexIndex, lastVertexIndex, smooth, partName, mtrlName);
|
||||
}
|
||||
Partition() { set(0, 0, 0, 0, 0, -1, nullptr, nullptr); }
|
||||
};
|
||||
std::vector<Partition> partitions;
|
||||
std::vector<unsigned short> ibugLandmarkMappings; /* 68 */
|
||||
const unsigned short ibugRightContour[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
|
||||
const unsigned short ibugLeftContour[8] = { 10, 11, 12, 13, 14, 15, 16, 17 };
|
||||
std::vector<unsigned short> modelRightContour;
|
||||
std::vector<unsigned short> modelLeftContour;
|
||||
std::vector<unsigned short> adjacentFaces;
|
||||
std::vector<unsigned short> adjacentVertices;
|
||||
std::vector<unsigned short> nvlmLandmarks;
|
||||
std::vector<unsigned short> nvlmRightContour;
|
||||
std::vector<unsigned short> nvlmLeftContour;
|
||||
|
||||
void appendMode(const NvAR_Point3f* pts) {
|
||||
size_t n = shapeMean.size(),
|
||||
off = shapeModes.size();
|
||||
shapeModes.resize(off + n);
|
||||
float *to = shapeModes[off].vec; // Delta mode vector
|
||||
const float *fr = &pts->x; // Mode points
|
||||
const float *mn = &shapeMean[0].x; // Mean points
|
||||
for (n *= 3; n--;) // 3D points
|
||||
*to++ = *fr++ - *mn++; // Delta shape
|
||||
}
|
||||
|
||||
void setBlendShape(unsigned i, const std::string& name, const NvAR_Point3f* pts) {
|
||||
size_t n = shapeMean.size();
|
||||
blendShapes[i].name = name;
|
||||
blendShapes[i].shape.resize(n);
|
||||
float *to = blendShapes[i].shape.data()->vec; // Delta mode vector
|
||||
const float *fr = &pts->x; // Blendshape points
|
||||
const float *mn = &shapeMean[0].x; // Mean points
|
||||
for (n *= 3; n--;) // 3D points
|
||||
*to++ = *fr++ - *mn++; // Delta shape
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* SimpleFaceModelAdapter
|
||||
********************************************************************************/
|
||||
|
||||
class SimpleFaceModelAdapter : public FaceIOAdapter {
|
||||
public:
|
||||
SimpleFaceModel fm;
|
||||
|
||||
uint32_t getShapeMeanSize() const override { return unsigned(fm.shapeMean.size()) * 3; }
|
||||
uint32_t getShapeModesSize() const override { return unsigned(fm.shapeModes.size()) * 3; }
|
||||
uint32_t getShapeNumModes() const override { return unsigned(fm.shapeModes.size() / fm.shapeMean.size()); }
|
||||
uint32_t getShapeEigenvaluesSize()const override { return unsigned(fm.shapeEigenValues.size()); }
|
||||
float* getShapeMean(uint32_t size) override { if (size) fm.shapeMean.resize(size / 3);
|
||||
return &fm.shapeMean.data()->x; };
|
||||
float* getShapeModes(uint32_t modeSize, uint32_t numModes) override {
|
||||
if (modeSize) fm.shapeModes.resize(modeSize / 3 * numModes); return fm.shapeModes.data()->vec; }
|
||||
float* getShapeEigenvalues(uint32_t numModes) override { if (numModes) fm.shapeEigenValues.resize(numModes);
|
||||
return fm.shapeEigenValues.data(); }
|
||||
|
||||
uint32_t getColorMeanSize() const override { return 0; }
|
||||
uint32_t getColorModesSize() const override { return 0; }
|
||||
uint32_t getColorNumModes() const override { return 0; }
|
||||
uint32_t getColorEigenvaluesSize() const override { return 0; }
|
||||
float* getColorMean(uint32_t /*size*/) override { return nullptr; }
|
||||
float* getColorModes(uint32_t /*modeSize*/, uint32_t /*numModes*/) override { return nullptr; }
|
||||
float* getColorEigenvalues(uint32_t /*numModes*/) override { return nullptr; }
|
||||
|
||||
void setTriangleListSize(uint32_t size) override { fm.triangles.resize(size / 3); }
|
||||
uint32_t getTriangleListSize() const override { return unsigned(fm.triangles.size()) * 3; }
|
||||
uint16_t* getTriangleList(uint32_t size) override { if (size) fm.triangles.resize(size / 3);
|
||||
return fm.triangles.data()->vec; }
|
||||
|
||||
void setTextureCoordinatesSize(uint32_t /*size*/) override {}
|
||||
uint32_t getTextureCoordinatesSize() const override { return 0; }
|
||||
float* getTextureCoordinates(uint32_t /*size*/) override { return nullptr; }
|
||||
|
||||
void setNumBlendShapes(uint32_t n) override { fm.blendShapes.resize(n); }
|
||||
void setBlendShapeName(uint32_t i, const char* name) override { fm.blendShapes[i].name = name; }
|
||||
uint32_t getNumBlendShapes() const override { return unsigned(fm.blendShapes.size()); }
|
||||
const char* getBlendShapeName(uint32_t i) const override { return fm.blendShapes[i].name.c_str(); }
|
||||
uint32_t getBlendShapeSize(uint32_t i) const override { return unsigned((fm.blendShapes[i].shape.size()) * 3); }
|
||||
float* getBlendShape(uint32_t i, uint32_t size) override { if (size) fm.blendShapes[i].shape.resize(size / 3);
|
||||
return fm.blendShapes[i].shape.data()->vec; }
|
||||
|
||||
void setIbugLandmarkMappingsSize(uint32_t n) override { fm.ibugLandmarkMappings.resize(n); }
|
||||
uint32_t getIbugLandmarkMappingsSize() const override { return unsigned(fm.ibugLandmarkMappings.size()); }
|
||||
uint16_t* getIbugLandmarkMappings(uint32_t size) override { if (size) fm.ibugLandmarkMappings.resize(size);
|
||||
return fm.ibugLandmarkMappings.data(); }
|
||||
void appendIbugLandmarkMapping(uint16_t i) override { fm.ibugLandmarkMappings.push_back(i); }
|
||||
void appendIbugLandmarkMapping(uint16_t i, uint16_t j) override { fm.ibugLandmarkMappings.push_back(i);
|
||||
fm.ibugLandmarkMappings.push_back(j); }
|
||||
|
||||
void setIbugRightContourSize(uint32_t /*n*/) override {}
|
||||
uint32_t getIbugRightContourSize() const override {
|
||||
return sizeof(fm.ibugRightContour) / sizeof(fm.ibugRightContour[0]); }
|
||||
uint16_t* getIbugRightContour(uint32_t /*size*/) override { return const_cast<uint16_t*>(fm.ibugRightContour); }
|
||||
void appendIbugRightContour(uint16_t /*i*/) override {}
|
||||
|
||||
void setIbugLeftContourSize(uint32_t /*n*/) override {}
|
||||
uint32_t getIbugLeftContourSize() const override { return sizeof(fm.ibugLeftContour)/sizeof(fm.ibugLeftContour[0]);}
|
||||
uint16_t* getIbugLeftContour(uint32_t /*size*/) override { return const_cast<uint16_t*>(fm.ibugLeftContour); }
|
||||
void appendIbugLeftContour(uint16_t /*i*/) override {}
|
||||
|
||||
void setModelRightContourSize(uint32_t n) override { fm.modelRightContour.resize(n); }
|
||||
uint32_t getModelRightContourSize() const override { return unsigned(fm.modelRightContour.size()); }
|
||||
uint16_t* getModelRightContour(uint32_t size) override { if (size) fm.modelRightContour.resize(size);
|
||||
return fm.modelRightContour.data(); }
|
||||
void appendModelRightContour(uint16_t i) override { fm.modelRightContour.push_back(i); }
|
||||
|
||||
void setModelLeftContourSize(uint32_t n) override { fm.modelLeftContour.resize(n); }
|
||||
uint32_t getModelLeftContourSize() const override { return unsigned(fm.modelLeftContour.size()); }
|
||||
uint16_t* getModelLeftContour(uint32_t size) override { if (size) fm.modelLeftContour.resize(size);
|
||||
return fm.modelLeftContour.data(); }
|
||||
void appendModelLeftContour(uint16_t i) override { fm.modelLeftContour.push_back(i); }
|
||||
|
||||
void setAdjacentFacesSize(uint32_t n) override { fm.adjacentFaces.resize(n); }
|
||||
uint32_t getAdjacentFacesSize() const override { return unsigned(fm.adjacentFaces.size()); }
|
||||
uint16_t* getAdjacentFaces(uint32_t size) override { if (size) fm.adjacentFaces.resize(size);
|
||||
return fm.adjacentFaces.data(); }
|
||||
void appendAdjacentFace(uint16_t i) override { fm.adjacentFaces.push_back(i); }
|
||||
void appendAdjacentFaces(uint16_t i, uint16_t j) override { fm.adjacentFaces.push_back(i);
|
||||
fm.adjacentFaces.push_back(j); }
|
||||
|
||||
void setAdjacentVerticesSize(uint32_t n) override { fm.adjacentVertices.resize(n); }
|
||||
uint32_t getAdjacentVerticesSize() const override { return unsigned(fm.adjacentVertices.size()); }
|
||||
uint16_t* getAdjacentVertices(uint32_t size) override { if (size) fm.adjacentVertices.resize(size);
|
||||
return fm.adjacentVertices.data(); }
|
||||
void appendAdjacentVertex(uint16_t i) override { fm.adjacentVertices.push_back(i); }
|
||||
void appendAdjacentVertices(uint16_t i, uint16_t j) override { fm.adjacentVertices.push_back(i);
|
||||
fm.adjacentVertices.push_back(j); }
|
||||
|
||||
void setNvlmLandmarksSize(uint32_t n) override { fm.nvlmLandmarks.resize(n); }
|
||||
uint32_t getNvlmLandmarksSize() const override { return (uint32_t)fm.nvlmLandmarks.size(); }
|
||||
uint16_t* getNvlmLandmarks(uint32_t size) override { if (size) fm.nvlmLandmarks.resize(size);
|
||||
return fm.nvlmLandmarks.data(); }
|
||||
void appendNvlmLandmark(uint16_t i) override { fm.nvlmLandmarks.push_back(i); }
|
||||
|
||||
void setNvlmRightContourSize(uint32_t n) override { fm.nvlmRightContour.resize(n); }
|
||||
uint32_t getNvlmRightContourSize() const override { return (uint32_t)fm.nvlmRightContour.size(); }
|
||||
uint16_t* getNvlmRightContour(uint32_t size) override { if (size) fm.nvlmRightContour.resize(size);
|
||||
return fm.nvlmRightContour.data(); }
|
||||
void appendNvlmRightContour(uint16_t i) override { fm.nvlmRightContour.push_back(i); }
|
||||
|
||||
void setNvlmLeftContourSize(uint32_t n) override { fm.nvlmLeftContour.resize(n); }
|
||||
uint32_t getNvlmLeftContourSize() const override { return (uint32_t)fm.nvlmLeftContour.size(); }
|
||||
uint16_t* getNvlmLeftContour(uint32_t size) override { if (size) fm.nvlmLeftContour.resize(size);
|
||||
return fm.nvlmLeftContour.data(); }
|
||||
void appendNvlmLeftContour(uint16_t i) override { fm.nvlmLeftContour.push_back(i); }
|
||||
|
||||
void setNumPartitions(uint32_t n) override { fm.partitions.resize(n); }
|
||||
void setPartitionName(uint32_t i, const char* name) override { fm.partitions.at(i).name = name; }
|
||||
void setPartitionMaterialName(uint32_t i, const char* name) override { fm.partitions.at(i).materialName = name;}
|
||||
void setPartition(uint32_t i, uint32_t faceIndex, uint32_t numFaces, uint32_t vertexIndex, uint32_t numVertices,
|
||||
int32_t smoothingGroup) override {
|
||||
fm.partitions.at(i).set(i, faceIndex, faceIndex + numFaces - 1, vertexIndex,
|
||||
vertexIndex + numVertices - 1, smoothingGroup);
|
||||
}
|
||||
uint32_t getNumPartitions() const override { return (uint32_t)fm.partitions.size(); }
|
||||
const char* getPartitionName(uint32_t i) const override { return fm.partitions.at(i).name.c_str(); }
|
||||
const char* getPartitionMaterialName(uint32_t i) const override { return fm.partitions.at(i).materialName.c_str(); }
|
||||
int16_t getPartition(uint32_t i, uint32_t* faceIndex, uint32_t* numFaces, uint32_t* vertexIndex,
|
||||
uint32_t* numVertices, int32_t* smoothingGroup) const override {
|
||||
const SimpleFaceModel::Partition& pt = fm.partitions.at(i);
|
||||
if (faceIndex) *faceIndex = pt.faceIndex;
|
||||
if (numFaces) *numFaces = pt.numFaces;
|
||||
if (vertexIndex) *vertexIndex = pt.vertexIndex;
|
||||
if (numVertices) *numVertices = pt.numVertexIndices;
|
||||
if (smoothingGroup) *smoothingGroup = pt.smoothingGroup;
|
||||
return (int16_t)pt.partitionIndex;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // __SIMPLE_FACE_MODEL__
|
||||
97
samples/ExpressionApp/CMakeLists.txt
Normal file
97
samples/ExpressionApp/CMakeLists.txt
Normal file
@@ -0,0 +1,97 @@
|
||||
######################
|
||||
# The Expression app #
|
||||
######################
|
||||
set(APP_SRCS
|
||||
ExpressionApp.cpp
|
||||
MeshRenderer.cpp MeshRenderer.h
|
||||
DirectoryIterator.cpp DirectoryIterator.h
|
||||
BackEndOpenGL/GLMaterial.cpp BackEndOpenGL/GLMaterial.h
|
||||
BackEndOpenGL/GLMesh.cpp BackEndOpenGL/GLMesh.h
|
||||
BackEndOpenGL/GLShaders.cpp BackEndOpenGL/GLShaders.h
|
||||
BackEndOpenGL/GLSpectrum.h
|
||||
BackEndOpenGL/SimpleFaceModel.h
|
||||
BackEndOpenGL/OpenGLMeshRenderer.cpp BackEndOpenGL/OpenGLMeshRenderer.h
|
||||
BackEndOpenGL/FaceIO.cpp BackEndOpenGL/FaceIO.h
|
||||
)
|
||||
if(WIN32)
|
||||
set(APP_SRCS ${APP_SRCS} nvARProxy.cpp nvCVImageProxy.cpp)
|
||||
find_package(OpenGL REQUIRED)
|
||||
endif(WIN32)
|
||||
|
||||
option(ENABLE_UI "Enable UI to adjust rigging" OFF) # ON still needs some more link debugging
|
||||
|
||||
if (${ENABLE_UI})
|
||||
set(APP_SRCS ${APP_SRCS}
|
||||
ExpressionAppUI.h
|
||||
ExpressionAppUI.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/imgui.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/imconfig.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/imgui_internal.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/imstb_textedit.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/imstb_rectpack.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/imstb_truetype.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/backends/imgui_impl_glfw.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/backends/imgui_impl_opengl3.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/backends/imgui_impl_opengl3_loader.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/misc/cpp/imgui_stdlib.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/imgui_tables.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/imgui_widgets.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/imgui.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/imgui_draw.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/backends/imgui_impl_glfw.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/backends/imgui_impl_opengl3.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/misc/cpp/imgui_stdlib.cpp
|
||||
)
|
||||
endif (${ENABLE_UI})
|
||||
|
||||
add_executable(ExpressionApp ${APP_SRCS})
|
||||
|
||||
target_include_directories(ExpressionApp PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/BackEndOpenGL
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../utils
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../external/glm/include
|
||||
${SDK_INCLUDES_PATH}
|
||||
)
|
||||
if (${ENABLE_UI})
|
||||
add_definitions("-D_ENABLE_UI")
|
||||
target_include_directories(ExpressionApp PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../external/nlohmann/json/single_include/nlohmann
|
||||
)
|
||||
endif (${ENABLE_UI})
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(ExpressionApp PUBLIC
|
||||
opencv346
|
||||
glfw3
|
||||
GLAD
|
||||
${OPENGL_gl_LIBRARY}
|
||||
)
|
||||
target_link_directories(ExpressionApp PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../external/GLAD/lib
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../external/GLFW/lib
|
||||
)
|
||||
target_include_directories(ExpressionApp PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../external/GLAD/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../external/GLFW/include
|
||||
)
|
||||
set(OPENCV_PATH_STR ${CMAKE_CURRENT_SOURCE_DIR}/../external/opencv/bin)
|
||||
set(PATH_STR "PATH=%PATH%" ${OPENCV_PATH_STR})
|
||||
set_target_properties(ExpressionApp PROPERTIES
|
||||
FOLDER SampleApps
|
||||
VS_DEBUGGER_ENVIRONMENT "${PATH_STR}"
|
||||
VS_DEBUGGER_COMMAND_ARGUMENTS "${CMD_ARG_STR}" )
|
||||
elseif(UNIX)
|
||||
#find_package(PNG REQUIRED)
|
||||
#find_package(JPEG REQUIRED)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -fpermissive")
|
||||
target_link_libraries(ExpressionApp PUBLIC
|
||||
nvARPose
|
||||
NVCVImage
|
||||
OpenCV
|
||||
glfw
|
||||
OpenGL
|
||||
dl
|
||||
)
|
||||
endif()
|
||||
169
samples/ExpressionApp/DirectoryIterator.cpp
Normal file
169
samples/ExpressionApp/DirectoryIterator.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
/*###############################################################################
|
||||
#
|
||||
# Copyright 2021 NVIDIA Corporation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
###############################################################################*/
|
||||
|
||||
#include "DirectoryIterator.h"
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
///// WINDOWS /////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#include <Windows.h>
|
||||
#include <string>
|
||||
|
||||
struct DirectoryIterator::Impl {
|
||||
HANDLE h;
|
||||
unsigned which;
|
||||
bool first;
|
||||
WIN32_FIND_DATAA data;
|
||||
};
|
||||
|
||||
DirectoryIterator::DirectoryIterator() {
|
||||
m_impl = new DirectoryIterator::Impl;
|
||||
m_impl->h = nullptr;
|
||||
}
|
||||
|
||||
DirectoryIterator::DirectoryIterator(const char *path, unsigned iterateWhat) : DirectoryIterator() {
|
||||
init(path, iterateWhat);
|
||||
}
|
||||
|
||||
DirectoryIterator::~DirectoryIterator() {
|
||||
if (m_impl) {
|
||||
if (m_impl->h) FindClose(m_impl->h);
|
||||
delete m_impl;
|
||||
}
|
||||
}
|
||||
|
||||
int DirectoryIterator::init(const char *path, unsigned iterateWhat) {
|
||||
std::string pathStar = path;
|
||||
pathStar += "\\*";
|
||||
if (nullptr == (m_impl->h = FindFirstFileA(pathStar.c_str(), &m_impl->data))) return -99; /* either dir or file */
|
||||
m_impl->which = iterateWhat ? iterateWhat : kTypeAll;
|
||||
m_impl->first = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DirectoryIterator::next(const char **pName, unsigned *type) {
|
||||
if (!pName) return -1;
|
||||
while (1) {
|
||||
if (m_impl->first) {
|
||||
m_impl->first = false;
|
||||
}
|
||||
else if (!FindNextFileA(m_impl->h, &m_impl->data)) {
|
||||
*pName = nullptr;
|
||||
if (type) *type = 0;
|
||||
return -99;
|
||||
}
|
||||
*pName = m_impl->data.cFileName;
|
||||
|
||||
if (0 != (m_impl->data.dwFileAttributes & (
|
||||
FILE_ATTRIBUTE_NORMAL |
|
||||
FILE_ATTRIBUTE_ARCHIVE |
|
||||
FILE_ATTRIBUTE_COMPRESSED |
|
||||
FILE_ATTRIBUTE_ENCRYPTED |
|
||||
FILE_ATTRIBUTE_HIDDEN |
|
||||
FILE_ATTRIBUTE_INTEGRITY_STREAM |
|
||||
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED |
|
||||
FILE_ATTRIBUTE_NO_SCRUB_DATA |
|
||||
FILE_ATTRIBUTE_READONLY |
|
||||
FILE_ATTRIBUTE_REPARSE_POINT |
|
||||
FILE_ATTRIBUTE_SPARSE_FILE |
|
||||
FILE_ATTRIBUTE_TEMPORARY
|
||||
))) {
|
||||
if (m_impl->which & kTypeFile) {
|
||||
if (type) *type = kTypeFile;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
else if (0 == (m_impl->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
if (m_impl->which & kTypeDirectory) {
|
||||
if (type) *type = kTypeDirectory;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
if (m_impl->which & kTypeSpecial) {
|
||||
if (type) *type = kTypeSpecial;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#else /* !_WIN32 == UNIX */
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
///// UNIX /////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#include <dirent.h>
|
||||
|
||||
struct DirectoryIterator::Impl {
|
||||
DIR *dp;
|
||||
unsigned which;
|
||||
};
|
||||
|
||||
DirectoryIterator::DirectoryIterator() {
|
||||
m_impl = new DirectoryIterator::Impl;
|
||||
m_impl->dp = nullptr;
|
||||
}
|
||||
|
||||
DirectoryIterator::DirectoryIterator(const char* path, unsigned iterateWhat) : DirectoryIterator() {
|
||||
init(path, iterateWhat);
|
||||
}
|
||||
|
||||
DirectoryIterator::~DirectoryIterator() {
|
||||
if (m_impl) {
|
||||
if (m_impl->dp) closedir(m_impl->dp);
|
||||
delete m_impl;
|
||||
}
|
||||
}
|
||||
|
||||
int DirectoryIterator::init(const char *path, unsigned iterateWhat) {
|
||||
if (nullptr == (m_impl->dp = opendir(path))) return -1;
|
||||
m_impl->which = iterateWhat ? iterateWhat : kTypeAll;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DirectoryIterator::next(const char **pName, unsigned *type) {
|
||||
struct dirent *entry;
|
||||
|
||||
if (type) *type = 0;
|
||||
if (!pName) return -1;
|
||||
while (nullptr != (entry = readdir(m_impl->dp))) {
|
||||
*pName = entry->d_name;
|
||||
switch (entry->d_type) {
|
||||
case DT_REG: if (m_impl->which & kTypeFile) { if (type) *type = kTypeFile; return 0; } break;
|
||||
case DT_DIR: if (m_impl->which & kTypeDirectory) { if (type) *type = kTypeDirectory; return 0; } break;
|
||||
default: if (m_impl->which & kTypeSpecial) { if (type) *type = kTypeSpecial; return 0; } break;
|
||||
}
|
||||
}
|
||||
*pName = nullptr;
|
||||
return -99;
|
||||
}
|
||||
|
||||
|
||||
#endif /* UNIX */
|
||||
68
samples/ExpressionApp/DirectoryIterator.h
Normal file
68
samples/ExpressionApp/DirectoryIterator.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*###############################################################################
|
||||
#
|
||||
# Copyright 2021 NVIDIA Corporation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
###############################################################################*/
|
||||
|
||||
#ifndef __DIRECTORY_ITERATOR_H
|
||||
#define __DIRECTORY_ITERATOR_H
|
||||
|
||||
class DirectoryIterator {
|
||||
public:
|
||||
enum {
|
||||
kTypeFile = 1,
|
||||
kTypeDirectory = 2,
|
||||
kTypeSpecial = 4,
|
||||
kTypeAll = (kTypeFile | kTypeDirectory | kTypeSpecial)
|
||||
};
|
||||
|
||||
/// Constructor
|
||||
DirectoryIterator();
|
||||
|
||||
/// Constructor
|
||||
/// @param[in] path The path of the directory to iterate.
|
||||
/// @param[in] iterateWhat The types of files to list.
|
||||
DirectoryIterator(const char *path, unsigned iterateWhat);
|
||||
|
||||
/// Destructor
|
||||
~DirectoryIterator();
|
||||
|
||||
/// Start looking in a particular directory.
|
||||
/// @param[in] path The path of the directory to iterate.
|
||||
/// @param[in] iterateWhat The types of files to list.
|
||||
/// @return 0 If successful,
|
||||
/// -1 If path was NULL,
|
||||
/// -99 If there are no files.
|
||||
int init(const char *path, unsigned iterateWhat);
|
||||
|
||||
/// Get the next file.
|
||||
/// @param pName[out] a place to store the name of the next file.
|
||||
/// @param type[out] a place to store the type of the next file.
|
||||
/// @return 0 If successful,
|
||||
/// -1 If path was NULL,
|
||||
/// -99 If there are no more files.
|
||||
int next(const char **pName, unsigned *type);
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
Impl *m_impl;
|
||||
};
|
||||
|
||||
#endif // __DIRECTORY_ITERATOR_H
|
||||
1288
samples/ExpressionApp/ExpressionApp.cpp
Normal file
1288
samples/ExpressionApp/ExpressionApp.cpp
Normal file
File diff suppressed because it is too large
Load Diff
BIN
samples/ExpressionApp/ExpressionApp.exe
Normal file
BIN
samples/ExpressionApp/ExpressionApp.exe
Normal file
Binary file not shown.
711
samples/ExpressionApp/ExpressionAppUI.cpp
Normal file
711
samples/ExpressionApp/ExpressionAppUI.cpp
Normal file
@@ -0,0 +1,711 @@
|
||||
/*###############################################################################
|
||||
#
|
||||
# Copyright(c) 2020 NVIDIA CORPORATION.All Rights Reserved.
|
||||
#
|
||||
# NVIDIA CORPORATION and its licensors retain all intellectual property
|
||||
# and proprietary rights in and to this software, related documentation
|
||||
# and any modifications thereto.Any use, reproduction, disclosure or
|
||||
# distribution of this software and related documentation without an express
|
||||
# license agreement from NVIDIA CORPORATION is strictly prohibited.
|
||||
#
|
||||
###############################################################################*/
|
||||
|
||||
#if _ENABLE_UI
|
||||
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
#include <json.hpp>
|
||||
#include <imgui_internal.h>
|
||||
#include "nvAR_defs.h"
|
||||
#include "ExpressionAppUI.h"
|
||||
|
||||
#define CTL(x) ((x) & 0x1F)
|
||||
|
||||
static std::map<int, std::string> exprMap = {
|
||||
{0 ,"browDown_L "},
|
||||
{1 ,"browDown_R "},
|
||||
{2 ,"browInnerUp_L "},
|
||||
{3 ,"browInnerUp_R "},
|
||||
{4 ,"browOuterUp_L "},
|
||||
{5 ,"browOuterUp_R "},
|
||||
{6 ,"cheekPuff_L "},
|
||||
{7 ,"cheekPuff_R "},
|
||||
{8 ,"cheekSquint_L "},
|
||||
{9 ,"cheekSquint_R "},
|
||||
{10 ,"eyeBlink_L "},
|
||||
{11 ,"eyeBlink_R "},
|
||||
{12 ,"eyeLookDown_L "},
|
||||
{13 ,"eyeLookDown_R "},
|
||||
{14 ,"eyeLookIn_L "},
|
||||
{15 ,"eyeLookIn_R "},
|
||||
{16 ,"eyeLookOut_L "},
|
||||
{17 ,"eyeLookOut_R "},
|
||||
{18 ,"eyeLookUp_L "},
|
||||
{19 ,"eyeLookUp_R "},
|
||||
{20 ,"eyeSquint_L "},
|
||||
{21 ,"eyeSquint_R "},
|
||||
{22 ,"eyeWide_L "},
|
||||
{23 ,"eyeWide_R "},
|
||||
{24 ,"jawForward "},
|
||||
{25 ,"jawLeft "},
|
||||
{26 ,"jawOpen "},
|
||||
{27 ,"jawRight "},
|
||||
{28 ,"mouthClose "},
|
||||
{29 ,"mouthDimple_L "},
|
||||
{30 ,"mouthDimple_R "},
|
||||
{31 ,"mouthFrown_L "},
|
||||
{32 ,"mouthFrown_R "},
|
||||
{33 ,"mouthFunnel "},
|
||||
{34 ,"mouthLeft "},
|
||||
{35 ,"mouthLowerDown_L"},
|
||||
{36 ,"mouthLowerDown_R"},
|
||||
{37 ,"mouthPress_L "},
|
||||
{38 ,"mouthPress_R "},
|
||||
{39 ,"mouthPucker "},
|
||||
{40 ,"mouthRight "},
|
||||
{41 ,"mouthRollLower "},
|
||||
{42 ,"mouthRollUpper "},
|
||||
{43 ,"mouthShrugLower "},
|
||||
{44 ,"mouthShrugUpper "},
|
||||
{45 ,"mouthSmile_L "},
|
||||
{46 ,"mouthSmile_R "},
|
||||
{47 ,"mouthStretch_L "},
|
||||
{48 ,"mouthStretch_R "},
|
||||
{49 ,"mouthUpperUp_L "},
|
||||
{50 ,"mouthUpperUp_R "},
|
||||
{51 ,"noseSneer_L "},
|
||||
{52 ,"noseSneer_R "}
|
||||
};
|
||||
|
||||
static const unsigned int browStartIndex = 0;
|
||||
static const unsigned int browEndIndex = 5;
|
||||
static const unsigned int cheekStartIndex = 6;
|
||||
static const unsigned int cheekEndIndex = 9;
|
||||
static const unsigned int eyeStartIndex = 10;
|
||||
static const unsigned int eyeEndIndex = 23;
|
||||
static const unsigned int jawStartIndex = 24;
|
||||
static const unsigned int jawEndIndex = 27;
|
||||
static const unsigned int mouthStartIndex = 28;
|
||||
static const unsigned int mouthEndIndex = 50;
|
||||
static const unsigned int noseStartIndex = 51;
|
||||
static const unsigned int noseEndIndex = 52;
|
||||
|
||||
static void glfw_error_callback(int error, const char* description) {
|
||||
printf("Glfw Error %d: %s\n", error, description);
|
||||
}
|
||||
|
||||
void ExpressionAppUI::init(int numExpr, int filter, int exprMode, int display, int showFPS) {
|
||||
keyboard_input_ = -1;
|
||||
filter_face_box_ = (filter & (NVAR_TEMPORAL_FILTER_FACE_BOX)) ? true : false;
|
||||
filter_face_landmark_ = (filter & (NVAR_TEMPORAL_FILTER_FACIAL_LANDMARKS)) ? true : false;
|
||||
filter_face_rot_pose_ = (filter & (NVAR_TEMPORAL_FILTER_FACE_ROTATIONAL_POSE)) ? true : false;
|
||||
filter_face_expr_ = (filter & (NVAR_TEMPORAL_FILTER_FACIAL_EXPRESSIONS)) ? true : false;
|
||||
filter_face_gaze_ = (filter & (NVAR_TEMPORAL_FILTER_FACIAL_GAZE)) ? true : false;
|
||||
filter_enhance_expr_ = (filter & (NVAR_TEMPORAL_FILTER_ENHANCE_EXPRESSIONS)) ? true : false;
|
||||
num_expressions_ = numExpr;
|
||||
show_expr_ = false;
|
||||
brow_expr_ = false;
|
||||
cheek_expr_ = false;
|
||||
eye_expr_ = false;
|
||||
jaw_expr_ = false;
|
||||
mouth_expr_ = false;
|
||||
nose_expr_ = false;
|
||||
curr_state_.expr_mode = exprMode;
|
||||
omniverse_interface_window_ = false;
|
||||
load_from_file_ = false;
|
||||
curr_state_.calibrate = false;
|
||||
curr_state_.uncalibrate = false;
|
||||
curr_state_.landmark_display = (DISPLAY_LM & display) ? true: false;
|
||||
curr_state_.mesh_display = (DISPLAY_MESH & display) ? true : false;
|
||||
curr_state_.image_display = (DISPLAY_IMAGE & display) ? true : false;
|
||||
curr_state_.bargraph_display = (DISPLAY_PLOT & display) ? true : false;
|
||||
curr_state_.expr.resize(numExpr, 0.0f);
|
||||
curr_state_.expr_offset.resize(numExpr, 0.0f);
|
||||
curr_state_.expr_scale.resize(numExpr, 1.0f);
|
||||
curr_state_.expr_exponent.resize(numExpr, 1.0f);
|
||||
curr_state_.global_parameter = 1.0f;
|
||||
internal_get_state_counter_ = 0;
|
||||
internal_set_state_counter_ = 0;
|
||||
curr_state_.input_filter = filter;
|
||||
curr_state_.show_fps = showFPS;
|
||||
show_filter_window_ = false;
|
||||
expr = 0;
|
||||
ui_state_ = curr_state_;
|
||||
ui_state_.expr.resize(numExpr, 0.0f);
|
||||
ui_state_.expr_offset.resize(numExpr, 0.0f);
|
||||
ui_state_.expr_scale.resize(numExpr, 1.0f);
|
||||
ui_state_.expr_exponent.resize(numExpr, 1.0f);
|
||||
file_name_ = "";
|
||||
ui_keep_running_ = true;
|
||||
ui_thread_ = std::thread([this]() { uiRenderThread();});
|
||||
}
|
||||
|
||||
void ExpressionAppUI::cleanup() {
|
||||
ui_keep_running_ = false;
|
||||
if (ui_thread_.joinable()) {
|
||||
ui_thread_.join();
|
||||
}
|
||||
ui_expression_list_.clear();
|
||||
}
|
||||
|
||||
void ExpressionAppUI::showMLPSetting() {
|
||||
ImGui::PushItemWidth(100);
|
||||
ImGui::InputInt("Expression Mode : 1 : Mesh Fitting , 2: MLP", &curr_state_.expr_mode);
|
||||
if (curr_state_.expr_mode < 1) {
|
||||
curr_state_.expr_mode = 1;
|
||||
}
|
||||
if (curr_state_.expr_mode > 2) {
|
||||
curr_state_.expr_mode = 2;
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::NewLine();
|
||||
ImGui::NewLine();
|
||||
}
|
||||
|
||||
void ExpressionAppUI::showFilterSetting() {
|
||||
if (!show_filter_window_) {
|
||||
if (ImGui::Button("Set Filters")) {
|
||||
show_filter_window_ = true;
|
||||
}
|
||||
}
|
||||
if (show_filter_window_) {
|
||||
if (ImGui::Button("Close Filter Settings")) {
|
||||
show_filter_window_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (show_filter_window_) {
|
||||
ImGui::SetNextWindowPos({ ImGui::GetCursorPosX() + 100 ,ImGui::GetCursorPosY() + 100 }, ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowContentSize(ImVec2(400, 400.0f));
|
||||
ImGui::Begin("Filter");
|
||||
curr_state_.input_filter = 0;
|
||||
ImGui::Checkbox("##NVAR_TEMPORAL_FILTER_FACE_BOX", &filter_face_box_); ImGui::SameLine();
|
||||
ImGui::Text("FILTER_FACE_BOX");
|
||||
ImGui::NewLine();
|
||||
ImGui::Checkbox("##NVAR_TEMPORAL_FILTER_FACIAL_LANDMARKS", &filter_face_landmark_); ImGui::SameLine();
|
||||
ImGui::Text("FILTER_FACIAL_LANDMARKS");
|
||||
ImGui::NewLine();
|
||||
ImGui::Checkbox("##NVAR_TEMPORAL_FILTER_FACE_ROTATIONAL_POSE", &filter_face_rot_pose_); ImGui::SameLine();
|
||||
ImGui::Text("FILTER_FACE_ROTATIONAL_POSE");
|
||||
ImGui::NewLine();
|
||||
ImGui::Checkbox("##NVAR_TEMPORAL_FILTER_FACIAL_EXPRESSIONS", &filter_face_expr_); ImGui::SameLine();
|
||||
ImGui::Text("FILTER_FACIAL_EXPRESSIONS");
|
||||
ImGui::NewLine();
|
||||
ImGui::Checkbox("##NVAR_TEMPORAL_FILTER_FACIAL_GAZE", &filter_face_gaze_); ImGui::SameLine();
|
||||
ImGui::Text("FILTER_FACIAL_GAZE");
|
||||
ImGui::NewLine();
|
||||
ImGui::Checkbox("##NVAR_TEMPORAL_FILTER_ENHANCE_EXPRESSIONS", &filter_enhance_expr_); ImGui::SameLine();
|
||||
ImGui::Text("FILTER_ENHANCE_EXPRESSIONS");
|
||||
ImGui::NewLine();
|
||||
ImGui::NewLine();
|
||||
|
||||
curr_state_.input_filter |= filter_face_box_ ? NVAR_TEMPORAL_FILTER_FACE_BOX : 0;
|
||||
curr_state_.input_filter |= filter_face_landmark_ ? NVAR_TEMPORAL_FILTER_FACIAL_LANDMARKS : 0;
|
||||
curr_state_.input_filter |= filter_face_rot_pose_ ? NVAR_TEMPORAL_FILTER_FACE_ROTATIONAL_POSE : 0;
|
||||
curr_state_.input_filter |= filter_face_expr_ ? NVAR_TEMPORAL_FILTER_FACIAL_EXPRESSIONS : 0;
|
||||
curr_state_.input_filter |= filter_face_gaze_ ? NVAR_TEMPORAL_FILTER_FACIAL_GAZE : 0;
|
||||
curr_state_.input_filter |= filter_enhance_expr_ ? NVAR_TEMPORAL_FILTER_ENHANCE_EXPRESSIONS : 0;
|
||||
|
||||
if (ImGui::Button("Close")) {
|
||||
show_filter_window_ = false;
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
ImGui::NewLine();
|
||||
ImGui::NewLine();
|
||||
}
|
||||
|
||||
void ExpressionAppUI::showExpressionWindow() {
|
||||
// Fill the list with curently active expressions
|
||||
|
||||
if ((1 << BROW) & expr) {
|
||||
for (int i = 0; i <= 5; i++) {
|
||||
ui_expression_list_.insert({ i });
|
||||
}
|
||||
}
|
||||
else {
|
||||
auto it = ui_expression_list_.find(browStartIndex);
|
||||
if (it != ui_expression_list_.end()) {
|
||||
auto begin = it;
|
||||
std::advance(it, (browEndIndex - browStartIndex + 1));
|
||||
ui_expression_list_.erase(begin, it);
|
||||
}
|
||||
}
|
||||
if ((1 << CHEEK) & expr) {
|
||||
for (int i = 6; i <= 9; i++) {
|
||||
ui_expression_list_.insert({ i });
|
||||
}
|
||||
}
|
||||
else {
|
||||
auto it = ui_expression_list_.find(cheekStartIndex);
|
||||
if (it != ui_expression_list_.end()) {
|
||||
auto begin = it;
|
||||
std::advance(it, (cheekEndIndex - cheekStartIndex + 1));
|
||||
ui_expression_list_.erase(begin, it);
|
||||
}
|
||||
}
|
||||
if ((1 << EYE) & expr) {
|
||||
for (int i = 10; i <= 23; i++) {
|
||||
ui_expression_list_.insert({ i });
|
||||
}
|
||||
}
|
||||
else {
|
||||
auto it = ui_expression_list_.find(eyeStartIndex);
|
||||
if (it != ui_expression_list_.end()) {
|
||||
auto begin = it;
|
||||
std::advance(it, (eyeEndIndex - eyeStartIndex + 1));
|
||||
ui_expression_list_.erase(begin, it);
|
||||
}
|
||||
}
|
||||
if ((1 << JAW) & expr) {
|
||||
for (int i = 24; i <= 27; i++) {
|
||||
ui_expression_list_.insert({ i });
|
||||
}
|
||||
}
|
||||
else {
|
||||
auto it = ui_expression_list_.find(jawStartIndex);
|
||||
if (it != ui_expression_list_.end()) {
|
||||
auto begin = it;
|
||||
std::advance(it, (jawEndIndex - jawStartIndex + 1));
|
||||
ui_expression_list_.erase(begin, it);
|
||||
}
|
||||
}
|
||||
if ((1 << MOUTH) & expr) {
|
||||
for (int i = 28; i <= 50; i++) {
|
||||
ui_expression_list_.insert({ i });
|
||||
}
|
||||
}
|
||||
else {
|
||||
auto it = ui_expression_list_.find(mouthStartIndex);
|
||||
if (it != ui_expression_list_.end()) {
|
||||
auto begin = it;
|
||||
std::advance(it, (mouthEndIndex - mouthStartIndex + 1));
|
||||
ui_expression_list_.erase(begin, it);
|
||||
}
|
||||
}
|
||||
if ((1 << NOSE) & expr) {
|
||||
for (int i = 51; i <= 52; i++) {
|
||||
ui_expression_list_.insert({ i });
|
||||
}
|
||||
}
|
||||
else {
|
||||
auto it = ui_expression_list_.find(noseStartIndex);
|
||||
if (it != ui_expression_list_.end()) {
|
||||
auto begin = it;
|
||||
std::advance(it, (noseEndIndex - noseStartIndex + 1));
|
||||
ui_expression_list_.erase(begin, it);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SetNextWindowContentSize(ImVec2(1080, 400.0f));
|
||||
ImGui::Begin("Expressions");
|
||||
ImGui::NewLine();
|
||||
ImGui::NewLine();
|
||||
ImGui::SliderFloat("Global Expression Parameter: Filter the effect of scaling and offset", &curr_state_.global_parameter, 0.0f, 1.0f);
|
||||
ImGui::NewLine();
|
||||
ImGui::NewLine();
|
||||
|
||||
expr = 0;
|
||||
|
||||
for (auto it = ui_expression_list_.begin(); it != ui_expression_list_.end(); it++) {
|
||||
ImGui::PushItemWidth(400);
|
||||
char overlay_buf[32];
|
||||
ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%.04f%%", curr_state_.expr[*it]);
|
||||
ImGui::ProgressBar(curr_state_.expr[*it], ImVec2(0.0f, 0.0f), overlay_buf);
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
int id = *it;
|
||||
ImGui::Text("%s", exprMap[id].c_str());
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 50);
|
||||
ImGui::PushItemWidth(100);
|
||||
ImGui::Text("Scale(0.0-2.0)");
|
||||
ImGui::SameLine();
|
||||
std::string scaleLabel = "##Scale:" + exprMap[*it];
|
||||
ImGui::SliderFloat(scaleLabel.c_str(), &curr_state_.expr_scale[*it], 0.0f, 2.0f);
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 10);
|
||||
ImGui::Text("Offset(-1.0 to 1.0)");
|
||||
ImGui::SameLine();
|
||||
std::string offsetLabel = "##Offset:" + exprMap[*it];
|
||||
ImGui::SliderFloat(offsetLabel.c_str(), &curr_state_.expr_offset[*it], -1.0f, 1.0f);
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 10);
|
||||
ImGui::Text("Exponent(0.0 to 2.0)");
|
||||
ImGui::SameLine();
|
||||
std::string expLabel = "##Exponent:" + exprMap[*it];
|
||||
ImGui::SliderFloat(expLabel.c_str(), &curr_state_.expr_exponent[*it], 0.0f, 2.0f);
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void ExpressionAppUI::showExpressionPane() {
|
||||
ImGui::Text("Expression Graph Options");
|
||||
ImGui::Checkbox("Brow", &brow_expr_); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
ImGui::Checkbox("Cheek", &cheek_expr_); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
ImGui::Checkbox("Eye", &eye_expr_); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
ImGui::Checkbox("Jaw", &jaw_expr_); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
ImGui::Checkbox("Mouth", &mouth_expr_); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
ImGui::Checkbox("Nose", &nose_expr_);
|
||||
|
||||
expr |= (brow_expr_) ? (1 << BROW) : 0;
|
||||
expr |= (cheek_expr_) ? (1 << CHEEK) : 0;
|
||||
expr |= (eye_expr_) ? (1 << EYE) : 0;
|
||||
expr |= (jaw_expr_) ? (1 << JAW) : 0;
|
||||
expr |= (mouth_expr_) ? (1 << MOUTH) : 0;
|
||||
expr |= (nose_expr_) ? (1 << NOSE) : 0;
|
||||
|
||||
if (expr) {
|
||||
show_expr_ = true;
|
||||
}
|
||||
else {
|
||||
if (ui_expression_list_.empty() == false) {
|
||||
ui_expression_list_.clear();
|
||||
}
|
||||
show_expr_ = false;
|
||||
}
|
||||
|
||||
if (show_expr_) {
|
||||
showExpressionWindow();
|
||||
}
|
||||
|
||||
ImGui::NewLine();
|
||||
ImGui::NewLine();
|
||||
}
|
||||
|
||||
void ExpressionAppUI::showCalibrationSetting() {
|
||||
if (ImGui::Button("Calibrate")) {
|
||||
curr_state_.calibrate = true;
|
||||
}
|
||||
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 50);
|
||||
if (ImGui::Button("Uncalibrate")) {
|
||||
curr_state_.uncalibrate = true;
|
||||
}
|
||||
ImGui::NewLine();
|
||||
}
|
||||
|
||||
|
||||
void ExpressionAppUI::showLandmarkOption() {
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 50);
|
||||
ImGui::Checkbox("Landmark", &curr_state_.landmark_display);
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("Mesh", &curr_state_.mesh_display);
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("Graph", &curr_state_.bargraph_display);
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("Image", &curr_state_.image_display);
|
||||
}
|
||||
|
||||
void ExpressionAppUI::showImageDisplaySettings() {
|
||||
ImGui::Text("Image Settings");
|
||||
showLandmarkOption();
|
||||
ImGui::NewLine();
|
||||
}
|
||||
|
||||
void ExpressionAppUI::showFPSSetting() {
|
||||
ImGui::Checkbox("Toggle FPS Display", &curr_state_.show_fps);
|
||||
ImGui::NewLine();
|
||||
}
|
||||
|
||||
void ExpressionAppUI::saveConfigToFile() {
|
||||
std::ofstream configFile;
|
||||
|
||||
std::string fileName = "ExpressionAppSettings.json";
|
||||
configFile.open(fileName.c_str());
|
||||
|
||||
nlohmann::json settings; {
|
||||
settings["MLP"] = curr_state_.expr_mode;
|
||||
settings["Filter"] = curr_state_.input_filter;
|
||||
settings["Expressions"] = curr_state_.expr;
|
||||
settings["ExpressionsOffset"] = curr_state_.expr_offset;
|
||||
settings["ExpressionsScale"] = curr_state_.expr_scale;
|
||||
settings["ExpressionsExponent"] = curr_state_.expr_exponent;
|
||||
settings["GlobalParameter"] = curr_state_.global_parameter;
|
||||
}
|
||||
|
||||
configFile << settings;
|
||||
|
||||
configFile.close();
|
||||
}
|
||||
|
||||
void ExpressionAppUI::loadConfgFromFile(const char* filePath) {
|
||||
std::ifstream configFile;
|
||||
std::string fileName;
|
||||
if (!filePath) {
|
||||
fileName = "ExpressionAppSettings.json";
|
||||
}
|
||||
else {
|
||||
fileName = filePath;
|
||||
}
|
||||
configFile.open(fileName.c_str());
|
||||
|
||||
if (configFile) {
|
||||
auto settings = nlohmann::json::parse(configFile); {
|
||||
curr_state_.expr_mode = settings["MLP"];
|
||||
curr_state_.input_filter = settings["Filter"];
|
||||
curr_state_.expr = settings["Expressions"].get<std::vector<float>>();
|
||||
curr_state_.expr_offset = settings["ExpressionsOffset"].get<std::vector<float>>();
|
||||
curr_state_.expr_scale = settings["ExpressionsScale"].get<std::vector<float>>();
|
||||
curr_state_.expr_exponent = settings["ExpressionsExponent"].get<std::vector<float>>();
|
||||
curr_state_.global_parameter = settings["GlobalParameter"];
|
||||
}
|
||||
}
|
||||
filter_face_box_ = (curr_state_.input_filter & NVAR_TEMPORAL_FILTER_FACE_BOX) ? true : false;
|
||||
filter_face_landmark_ = (curr_state_.input_filter & NVAR_TEMPORAL_FILTER_FACIAL_LANDMARKS) ? true : false;
|
||||
filter_face_rot_pose_ = (curr_state_.input_filter & NVAR_TEMPORAL_FILTER_FACE_ROTATIONAL_POSE) ? true : false;
|
||||
filter_face_expr_ = (curr_state_.input_filter & NVAR_TEMPORAL_FILTER_FACIAL_EXPRESSIONS) ? true : false;
|
||||
filter_face_gaze_ = (curr_state_.input_filter & NVAR_TEMPORAL_FILTER_FACIAL_GAZE) ? true : false;
|
||||
filter_enhance_expr_ = (curr_state_.input_filter & NVAR_TEMPORAL_FILTER_ENHANCE_EXPRESSIONS) ? true : false;
|
||||
}
|
||||
|
||||
void ExpressionAppUI::openFileLoadSettings() {
|
||||
if (load_from_file_) {
|
||||
ImGui::SetNextWindowContentSize(ImVec2(500, 100.0f));
|
||||
ImGui::Begin("Config Settings");
|
||||
ImGui::Text("Enter Full File name with path eg : C:\\sample.json (no double quotes)");
|
||||
ImGui::InputText("##FileName", &file_name_);
|
||||
ImGui::NewLine();
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 30);
|
||||
if (ImGui::Button("OK")) {
|
||||
loadConfgFromFile(file_name_.c_str());
|
||||
load_from_file_ = false;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Cancel")) {
|
||||
load_from_file_ = false;
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
}
|
||||
|
||||
void ExpressionAppUI::showSaveSettingsOption() {
|
||||
ImGui::NewLine();
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 10);
|
||||
if (ImGui::Button("SaveSettings")) {
|
||||
saveConfigToFile();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 50);
|
||||
|
||||
if (ImGui::Button("LoadSettings")) {
|
||||
loadConfgFromFile(NULL);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 50);
|
||||
|
||||
if (load_from_file_) {
|
||||
openFileLoadSettings();
|
||||
if (ImGui::Button("Close Settings Window")) {
|
||||
load_from_file_ = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (ImGui::Button("LoadSettingsFromFile")) {
|
||||
load_from_file_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExpressionAppUI::closeAppSettings() {
|
||||
ImGui::NewLine();
|
||||
ImGui::NewLine();
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 170);
|
||||
|
||||
if (ImGui::Button("App shutdown")) {
|
||||
curr_state_.kill_app_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ExpressionAppUI::CreateUIElements() {
|
||||
showMLPSetting();
|
||||
showFilterSetting();
|
||||
showExpressionPane();
|
||||
showCalibrationSetting();
|
||||
showImageDisplaySettings();
|
||||
showFPSSetting();
|
||||
showSaveSettingsOption();
|
||||
closeAppSettings();
|
||||
}
|
||||
|
||||
void ExpressionAppUI::stateQuerybyCore(unsigned int& displayMode, unsigned int& exprMode, unsigned int& filter, bool& calibrate, bool& uncalibrate, bool& showFPS,
|
||||
float& globalParam, std::vector<float>& expressionOffset, std::vector<float>& expressionScale, std::vector<float>& expressionExponent, bool& killApp) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(ui_mutex_);
|
||||
displayMode = ((ui_state_.landmark_display == true) ? DISPLAY_LM : 0) + ((ui_state_.mesh_display == true) ? DISPLAY_MESH : 0) + ((ui_state_.bargraph_display == true) ? DISPLAY_PLOT : 0) + ((ui_state_.image_display == true) ? DISPLAY_IMAGE : 0);;
|
||||
filter = ui_state_.input_filter;
|
||||
calibrate = ui_state_.calibrate;
|
||||
uncalibrate = ui_state_.uncalibrate;
|
||||
showFPS = ui_state_.show_fps;
|
||||
exprMode = ui_state_.expr_mode;
|
||||
globalParam = ui_state_.global_parameter;
|
||||
expressionOffset = ui_state_.expr_offset;
|
||||
expressionScale = ui_state_.expr_scale;
|
||||
expressionExponent = ui_state_.expr_exponent;
|
||||
killApp = ui_state_.kill_app_;
|
||||
}
|
||||
}
|
||||
|
||||
void ExpressionAppUI::stateSetbyCore(std::vector<float> expression,
|
||||
std::vector<float> expressionOffset, std::vector<float> expressionScale, std::vector<float> expressionExponent, bool isCalibrated, int key) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(ui_mutex_);
|
||||
ui_state_.expr = expression;
|
||||
ui_state_.expr_offset = expressionOffset;
|
||||
ui_state_.expr_scale = expressionScale;
|
||||
ui_state_.expr_exponent = expressionExponent;
|
||||
if ((internal_get_state_counter_ == internal_set_state_counter_) && (isCalibrated)) {
|
||||
ui_state_.calibrate = false;
|
||||
ui_state_.uncalibrate = false;
|
||||
}
|
||||
if (key >= 0) {
|
||||
keyboard_input_ = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExpressionAppUI::checkForKeyInput() {
|
||||
if (keyboard_input_ >= 0) {
|
||||
switch (keyboard_input_) {
|
||||
case 27 /*ESC*/:
|
||||
case 'q': case 'Q': curr_state_.kill_app_ = true; break; // Quit
|
||||
case 'i': curr_state_.image_display = !ui_state_.image_display; break;
|
||||
case 'l': curr_state_.landmark_display = !ui_state_.landmark_display; break;
|
||||
case 'm': curr_state_.mesh_display = !ui_state_.mesh_display; break;
|
||||
case 'n': curr_state_.calibrate = true; break;
|
||||
case 'p': curr_state_.bargraph_display = !ui_state_.bargraph_display; break;
|
||||
case 'f': curr_state_.show_fps = !ui_state_.show_fps; break;
|
||||
case '1': curr_state_.expr_mode = 1; break;
|
||||
case '2': curr_state_.expr_mode = 2; break;
|
||||
case 'L': case CTL('L'): filter_face_landmark_ = !filter_face_landmark_;
|
||||
curr_state_.input_filter ^= NVAR_TEMPORAL_FILTER_FACIAL_LANDMARKS; break;
|
||||
case 'N': case CTL('N'): curr_state_.uncalibrate = true;; break;
|
||||
case 'P': case CTL('P'): filter_face_rot_pose_ = !filter_face_rot_pose_;
|
||||
curr_state_.input_filter ^= NVAR_TEMPORAL_FILTER_FACE_ROTATIONAL_POSE; break;
|
||||
case 'E': case CTL('E'): filter_face_expr_ = !filter_face_expr_;
|
||||
curr_state_.input_filter ^= NVAR_TEMPORAL_FILTER_FACIAL_EXPRESSIONS; break;
|
||||
case 'G': case CTL('G'): filter_face_gaze_ = !filter_face_gaze_;
|
||||
curr_state_.input_filter ^= NVAR_TEMPORAL_FILTER_FACIAL_GAZE; break;
|
||||
case 'C': case CTL('C'): filter_enhance_expr_ = !filter_enhance_expr_;
|
||||
curr_state_.input_filter ^= NVAR_TEMPORAL_FILTER_ENHANCE_EXPRESSIONS; break;
|
||||
default: // No key
|
||||
break;
|
||||
}
|
||||
keyboard_input_ = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void ExpressionAppUI::setStateToLocal() {
|
||||
std::lock_guard<std::mutex> lock(ui_mutex_);
|
||||
ui_state_ = curr_state_;
|
||||
ui_state_.expr = curr_state_.expr;
|
||||
ui_state_.expr_exponent = curr_state_.expr_exponent;
|
||||
ui_state_.expr_offset = curr_state_.expr_offset;
|
||||
ui_state_.expr_scale = curr_state_.expr_scale;
|
||||
ui_state_.kill_app_ = curr_state_.kill_app_;
|
||||
internal_set_state_counter_ = internal_get_state_counter_;
|
||||
if (internal_get_state_counter_ > 100000) {
|
||||
internal_get_state_counter_ = internal_set_state_counter_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ExpressionAppUI::getStateFromLocal() {
|
||||
std::lock_guard<std::mutex> lock(ui_mutex_);
|
||||
curr_state_ = ui_state_;
|
||||
curr_state_.expr = ui_state_.expr;
|
||||
curr_state_.expr_exponent = ui_state_.expr_exponent;
|
||||
curr_state_.expr_offset = ui_state_.expr_offset;
|
||||
curr_state_.expr_scale = ui_state_.expr_scale;
|
||||
internal_get_state_counter_++;
|
||||
}
|
||||
|
||||
void ExpressionAppUI::uiRenderThread() {
|
||||
ImVec4 clear_color_;
|
||||
|
||||
glfwSetErrorCallback(glfw_error_callback);
|
||||
glfwInit();
|
||||
GLFWwindow* window = glfwCreateWindow(640, 540, "Expression App Interface", NULL, NULL);
|
||||
if (window == NULL) {
|
||||
GLenum err = glGetError();
|
||||
printf("Create window failed : %d", err);
|
||||
}
|
||||
glfwMakeContextCurrent(window);
|
||||
glfwSwapInterval(1); // Enable vsync
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
||||
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
|
||||
|
||||
ImGui::StyleColorsDark();
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
|
||||
style.WindowRounding = 0.0f;
|
||||
style.Colors[ImGuiCol_WindowBg].w = 1.0f;
|
||||
}
|
||||
// Setup Platform/Renderer backends
|
||||
ImGui_ImplGlfw_InitForOpenGL(window, true);
|
||||
ImGui_ImplOpenGL3_Init("#version 130");
|
||||
|
||||
setStateToLocal();
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(ui_mutex_);
|
||||
internal_get_state_counter_ = 0;
|
||||
internal_set_state_counter_ = 0;
|
||||
}
|
||||
|
||||
while (!glfwWindowShouldClose(window) && ui_keep_running_) {
|
||||
if (!ui_keep_running_) {
|
||||
break;
|
||||
}
|
||||
glfwPollEvents();
|
||||
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
ImGui_ImplGlfw_NewFrame();
|
||||
|
||||
ImGui::NewFrame();
|
||||
{
|
||||
ImGui::SetNextWindowContentSize(ImVec2(500, 500.0f));
|
||||
ImGui::Begin("Expression: Input Options");
|
||||
getStateFromLocal();
|
||||
|
||||
CreateUIElements();
|
||||
checkForKeyInput();
|
||||
setStateToLocal();
|
||||
ImGui::End();
|
||||
}
|
||||
ImGui::Render();
|
||||
int display_w, display_h;
|
||||
glfwGetFramebufferSize(window, &display_w, &display_h);
|
||||
glViewport(0, 0, display_w, display_h);
|
||||
glClearColor(clear_color_.x * clear_color_.w, clear_color_.y * clear_color_.w, clear_color_.z * clear_color_.w, clear_color_.w);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
|
||||
if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
|
||||
GLFWwindow* backup_current_context = glfwGetCurrentContext();
|
||||
ImGui::UpdatePlatformWindows();
|
||||
ImGui::RenderPlatformWindowsDefault();
|
||||
glfwMakeContextCurrent(backup_current_context);
|
||||
}
|
||||
|
||||
glfwSwapBuffers(window);
|
||||
}
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplGlfw_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
glfwDestroyWindow(window);
|
||||
|
||||
// TODO: call terminate if GL renderer is not being used
|
||||
// glfwTerminate();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
145
samples/ExpressionApp/ExpressionAppUI.h
Normal file
145
samples/ExpressionApp/ExpressionAppUI.h
Normal file
@@ -0,0 +1,145 @@
|
||||
/*###############################################################################
|
||||
#
|
||||
# Copyright(c) 2020 NVIDIA CORPORATION.All Rights Reserved.
|
||||
#
|
||||
# NVIDIA CORPORATION and its licensors retain all intellectual property
|
||||
# and proprietary rights in and to this software, related documentation
|
||||
# and any modifications thereto.Any use, reproduction, disclosure or
|
||||
# distribution of this software and related documentation without an express
|
||||
# license agreement from NVIDIA CORPORATION is strictly prohibited.
|
||||
#
|
||||
###############################################################################*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if _ENABLE_UI
|
||||
#include <set>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <imgui.h>
|
||||
#include <backends/imgui_impl_glfw.h>
|
||||
#include <backends/imgui_impl_opengl3.h>
|
||||
#include <misc/cpp/imgui_stdlib.h>
|
||||
|
||||
enum exprType {
|
||||
BROW = 1,
|
||||
CHEEK,
|
||||
EYE,
|
||||
JAW,
|
||||
MOUTH,
|
||||
NOSE
|
||||
};
|
||||
|
||||
enum {
|
||||
DISPLAY_MESH = (1 << 0),
|
||||
DISPLAY_IMAGE = (1 << 1),
|
||||
DISPLAY_PLOT = (1 << 2),
|
||||
DISPLAY_LM = (1 << 3)
|
||||
};
|
||||
|
||||
struct ExpressionState {
|
||||
int input_filter;
|
||||
float global_parameter;
|
||||
int expr_mode;
|
||||
unsigned long counter;
|
||||
bool calibrate;
|
||||
bool uncalibrate;
|
||||
bool landmark_display;
|
||||
bool mesh_display;
|
||||
bool image_display;
|
||||
bool bargraph_display;
|
||||
bool show_fps;
|
||||
bool kill_app_;
|
||||
std::vector<float> expr;
|
||||
std::vector<float> expr_scale;
|
||||
std::vector<float> expr_offset;
|
||||
std::vector<float> expr_exponent;
|
||||
ExpressionState() {
|
||||
input_filter = -1;
|
||||
counter = 0;
|
||||
global_parameter = 1.0f;
|
||||
expr_mode = 1;
|
||||
calibrate = false;
|
||||
uncalibrate = false;
|
||||
landmark_display = false;
|
||||
mesh_display = false;
|
||||
image_display = false;
|
||||
bargraph_display = false;
|
||||
show_fps = false;
|
||||
kill_app_ = false;
|
||||
}
|
||||
};
|
||||
|
||||
class ExpressionAppUI {
|
||||
public:
|
||||
//============= State Management =================
|
||||
void init(int numExpr, int filter, int exprMode, int display, int showFPS);
|
||||
void cleanup();
|
||||
|
||||
void stateQuerybyCore(unsigned int& displayMode, unsigned int& exprMode, unsigned int& filter, bool& calibrate, bool& uncalibrate, bool& showFPS,
|
||||
float& globalParam, std::vector<float>& expressionOffset, std::vector<float>& expressionScale, std::vector<float>& expressionExponent, bool& killApp);
|
||||
void stateSetbyCore(std::vector<float> expression,
|
||||
std::vector<float> expressionOffset, std::vector<float> expressionScale, std::vector<float> expressionExponent, bool isCalibrated = false, int key = -1);
|
||||
|
||||
private:
|
||||
|
||||
void uiRenderThread();
|
||||
void getStateFromLocal();
|
||||
void setStateToLocal();
|
||||
//============= UI calls ====================
|
||||
void CreateUIElements(); // main API to create UI compoenents
|
||||
void showMLPSetting();
|
||||
void showStreamingSetting();
|
||||
void showFilterSetting();
|
||||
void showExpressionPane();
|
||||
void showExpressionWindow();
|
||||
void showCalibrationSetting();
|
||||
void showImageDisplaySettings();
|
||||
void showLandmarkOption();
|
||||
void showFPSSetting();
|
||||
void showSaveSettingsOption();
|
||||
void saveConfigToFile();
|
||||
void loadConfgFromFile(const char* filePath = NULL);
|
||||
void openFileLoadSettings();
|
||||
void closeAppSettings();
|
||||
void checkForKeyInput();
|
||||
//================= Filter =======================
|
||||
bool filter_face_box_;
|
||||
bool filter_face_landmark_;
|
||||
bool filter_face_rot_pose_;
|
||||
bool filter_face_expr_;
|
||||
bool filter_face_gaze_;
|
||||
bool filter_enhance_expr_;
|
||||
|
||||
//================= Expression ===================
|
||||
bool show_expr_;
|
||||
bool brow_expr_;
|
||||
bool cheek_expr_;
|
||||
bool eye_expr_ ;
|
||||
bool jaw_expr_ ;
|
||||
bool mouth_expr_;
|
||||
bool nose_expr_;
|
||||
|
||||
std::set<int> ui_expression_list_;
|
||||
//=================================================
|
||||
std::atomic_bool omniverse_interface_window_;
|
||||
std::atomic_int keyboard_input_;
|
||||
bool load_from_file_;
|
||||
bool show_filter_window_;
|
||||
int expr;
|
||||
|
||||
ExpressionState ui_state_;
|
||||
ExpressionState curr_state_;
|
||||
std::atomic_bool ui_keep_running_;
|
||||
std::thread ui_thread_;
|
||||
std::mutex ui_mutex_;
|
||||
std::string file_name_;
|
||||
unsigned long internal_get_state_counter_;
|
||||
unsigned long internal_set_state_counter_;
|
||||
int32_t num_expressions_;
|
||||
};
|
||||
#endif
|
||||
332
samples/ExpressionApp/MeshRenderer.cpp
Normal file
332
samples/ExpressionApp/MeshRenderer.cpp
Normal file
@@ -0,0 +1,332 @@
|
||||
/*###############################################################################
|
||||
#
|
||||
# Copyright 2021 NVIDIA Corporation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
###############################################################################*/
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define _WINSOCKAPI_
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
#else // UNIX
|
||||
#include <dlfcn.h>
|
||||
typedef void *HMODULE;
|
||||
typedef void *HANDLE;
|
||||
typedef void *HINSTANCE;
|
||||
#endif // _WIN32 || UNIX
|
||||
|
||||
#include "MeshRenderer.h"
|
||||
#include "DirectoryIterator.h"
|
||||
#include "OpenGLMeshRenderer.h" // Eventually this will be discoverable
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define nvLoadLibrary(library) LoadLibrary(TEXT(library))
|
||||
#else // UNIX
|
||||
#define nvLoadLibrary(library) dlopen(library, RTLD_LAZY)
|
||||
#endif // _WIN32 || UNIX
|
||||
|
||||
|
||||
inline void* nvGetProcAddress(HINSTANCE handle, const char *proc) {
|
||||
if (nullptr == handle) return nullptr;
|
||||
#ifdef _WIN32
|
||||
return GetProcAddress(handle, proc);
|
||||
#else // UNIX
|
||||
return dlsym(handle, proc);
|
||||
#endif // _WIN32 || UNIX
|
||||
}
|
||||
|
||||
|
||||
inline int nvFreeLibrary(HINSTANCE handle) {
|
||||
if (nullptr == handle) return -1;
|
||||
#ifdef _WIN32
|
||||
return int(!FreeLibrary(handle)); // convert bool true to 0 int and 1 error code
|
||||
#else // UNIX
|
||||
return dlclose(handle); // 0 on success, error code otherwise
|
||||
#endif // _WIN32 || UNIX
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
///// Abstract class MeshRenderer /////
|
||||
///// This merely converts from a C++ to a C object call. /////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef DEBUG_CAST // We never instantiate MeshRenderer, only ClubMeshRenderer, so we don't need a dynamic cast.
|
||||
#define static_cast dynamic_cast // But #define this to prove it
|
||||
#endif // DEBUG_CAST
|
||||
|
||||
|
||||
NvCV_Status MeshRenderer::name(const char **str) const {
|
||||
return m_dispatch.name(str);
|
||||
}
|
||||
|
||||
|
||||
NvCV_Status MeshRenderer::info(const char **str) const {
|
||||
return m_dispatch.info(str);
|
||||
}
|
||||
|
||||
|
||||
void MeshRenderer::destroy() {
|
||||
m_dispatch.destroy(this);
|
||||
}
|
||||
|
||||
|
||||
NvCV_Status MeshRenderer::read(const char *modelFile) {
|
||||
return m_dispatch.read(this, modelFile);
|
||||
}
|
||||
|
||||
|
||||
NvCV_Status MeshRenderer::init(unsigned width, unsigned height, const char *windowName) {
|
||||
return m_dispatch.init(this, width, height, windowName);
|
||||
}
|
||||
|
||||
|
||||
NvCV_Status MeshRenderer::setCamera(const float locPt[3], const float lookVec[3], const float upVec[3], float vfov) {
|
||||
return m_dispatch.setCamera(this, locPt, lookVec, upVec, vfov);
|
||||
}
|
||||
|
||||
|
||||
NvCV_Status MeshRenderer::render(const float exprs[53], const float qrot[4], const float trans[3], NvCVImage *result) {
|
||||
return m_dispatch.render(this, exprs, qrot, trans, result);
|
||||
}
|
||||
|
||||
|
||||
MeshRenderer::Dispatch::Dispatch() {
|
||||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
///// MeshRendererBroker /////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class RendererInfo {
|
||||
public:
|
||||
std::string name, info, file;
|
||||
HMODULE module;
|
||||
MeshRenderer::Dispatch dispatch;
|
||||
RendererInfo() {
|
||||
memset(&dispatch, 0, sizeof(dispatch));
|
||||
module = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class MeshRendererBroker::Impl {
|
||||
public:
|
||||
static const char nameStr[], infoStr[], createStr[], destroyStr[], readStr[], initStr[], setCameraStr[], renderStr[];
|
||||
|
||||
std::string rendererDirectory;
|
||||
std::vector<RendererInfo> renderers;
|
||||
|
||||
NvCV_Status GetRenderers();
|
||||
NvCV_Status LoadRenderer(const char *name);
|
||||
NvCV_Status UnloadRenderer(const char *name);
|
||||
bool AlreadyHave(const char *name);
|
||||
~Impl() {
|
||||
for (RendererInfo& ri : renderers)
|
||||
(void)UnloadRenderer(ri.name.c_str());
|
||||
}
|
||||
};
|
||||
const char MeshRendererBroker::Impl::nameStr[] = "RendererName";
|
||||
const char MeshRendererBroker::Impl::infoStr[] = "RendererInfo";
|
||||
const char MeshRendererBroker::Impl::createStr[] = "RendererName";
|
||||
const char MeshRendererBroker::Impl::destroyStr[] = "RendererDestroy";
|
||||
const char MeshRendererBroker::Impl::readStr[] = "RendererReadModel";
|
||||
const char MeshRendererBroker::Impl::initStr[] = "RendererInit";
|
||||
const char MeshRendererBroker::Impl::setCameraStr[] = "RendererSetCamera";
|
||||
const char MeshRendererBroker::Impl::renderStr[] = "RendererRender";
|
||||
|
||||
|
||||
static bool HasDLLSuffix(const char *name) {
|
||||
static const char dllSuffix[] =
|
||||
#ifdef _WIN32
|
||||
".dll"
|
||||
#else // UNIX
|
||||
".so"
|
||||
#endif // _WIN32 || UNIX
|
||||
;
|
||||
constexpr unsigned suf_len = sizeof(dllSuffix) - 1; // Strings have a NULL terminator, are not part of the string
|
||||
unsigned name_len = unsigned(strlen(name));
|
||||
return name_len > suf_len && !strcmp(name + name_len - suf_len, dllSuffix);
|
||||
}
|
||||
|
||||
|
||||
bool MeshRendererBroker::Impl::AlreadyHave(const char* name) {
|
||||
for (const RendererInfo& ri : renderers)
|
||||
if (ri.name == name)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
NvCV_Status MeshRendererBroker::Impl::GetRenderers() {
|
||||
if (rendererDirectory.empty()) // Or should we pass in the directory as an argument?
|
||||
return NVCV_ERR_INITIALIZATION; // The renderer directory was not initialized.
|
||||
DirectoryIterator dit(rendererDirectory.c_str(), DirectoryIterator::kTypeFile);
|
||||
const char *fileName;
|
||||
unsigned type;
|
||||
while (0 == dit.next(&fileName, &type)) {
|
||||
if (!HasDLLSuffix(fileName))
|
||||
continue;
|
||||
std::string path = rendererDirectory + '/' + fileName;
|
||||
HINSTANCE lib = nvLoadLibrary(path.c_str());
|
||||
if (!lib)
|
||||
continue;
|
||||
typedef NvCV_Status(*GetStringFunc)(const char** str);
|
||||
GetStringFunc getString;
|
||||
const char *name = nullptr, *info = nullptr;
|
||||
if ((nullptr != (getString = reinterpret_cast<GetStringFunc>(nvGetProcAddress(lib, nameStr)))) &&
|
||||
(NVCV_SUCCESS == (*getString)(&name)) &&
|
||||
(nullptr != (getString = reinterpret_cast<GetStringFunc>(nvGetProcAddress(lib, infoStr)))) &&
|
||||
(NVCV_SUCCESS == (*getString)(&info)) &&
|
||||
!AlreadyHave(name)
|
||||
) {
|
||||
unsigned i = unsigned(renderers.size());
|
||||
renderers.resize(i + 1);
|
||||
RendererInfo& ri = renderers[i];
|
||||
ri.name.assign(name);
|
||||
ri.info.assign(info);
|
||||
ri.file.assign(path);
|
||||
}
|
||||
nvFreeLibrary(lib);
|
||||
}
|
||||
return NVCV_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
NvCV_Status MeshRendererBroker::Impl::LoadRenderer(const char *name) {
|
||||
for (RendererInfo& ri : renderers) {
|
||||
if (name == ri.name) {
|
||||
if (!ri.module) {
|
||||
ri.module = nvLoadLibrary(ri.file.c_str());
|
||||
// BE VERY CAREFUL WHEN CHANGING FUNCTION SIGNATURES, ESPECIALLY FOR WINDOWS!!!! THERE ARE NO CHECKS BELOW!!!!
|
||||
*((void**)&ri.dispatch.name) = nvGetProcAddress(ri.module, nameStr);
|
||||
*((void**)&ri.dispatch.info) = nvGetProcAddress(ri.module, infoStr);
|
||||
*((void**)&ri.dispatch.create) = nvGetProcAddress(ri.module, createStr);
|
||||
*((void**)&ri.dispatch.destroy) = nvGetProcAddress(ri.module, destroyStr);
|
||||
*((void**)&ri.dispatch.read) = nvGetProcAddress(ri.module, readStr);
|
||||
*((void**)&ri.dispatch.init) = nvGetProcAddress(ri.module, initStr);
|
||||
*((void**)&ri.dispatch.setCamera) = nvGetProcAddress(ri.module, setCameraStr);
|
||||
*((void**)&ri.dispatch.render) = nvGetProcAddress(ri.module, renderStr);
|
||||
}
|
||||
return NVCV_SUCCESS;
|
||||
}
|
||||
}
|
||||
return NVCV_ERR_FEATURENOTFOUND;
|
||||
}
|
||||
|
||||
|
||||
NvCV_Status MeshRendererBroker::Impl::UnloadRenderer(const char *name) {
|
||||
NvCV_Status err = NVCV_ERR_FEATURENOTFOUND;
|
||||
for (RendererInfo& ri : renderers) {
|
||||
if (name == ri.name) {
|
||||
err = !ri.module ? NVCV_SUCCESS : nvFreeLibrary(ri.module) ? NVCV_ERR_LIBRARY : NVCV_SUCCESS;
|
||||
ri.module = nullptr;
|
||||
memset(&ri.dispatch, 0, sizeof(ri.dispatch));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
MeshRendererBroker::MeshRendererBroker() {
|
||||
NvCV_Status err;
|
||||
m_impl = new Impl;
|
||||
|
||||
// Automatically register the OpenGL Renderer
|
||||
MeshRenderer::Dispatch disp;
|
||||
if (NVCV_SUCCESS == (err = OpenGLMeshRenderer_InitDispatch(&disp)))
|
||||
MeshRendererBroker::addRenderer(&disp);
|
||||
}
|
||||
|
||||
|
||||
MeshRendererBroker::~MeshRendererBroker() {
|
||||
delete m_impl;
|
||||
}
|
||||
|
||||
|
||||
NvCV_Status MeshRendererBroker::setRendererDirectory(const char *dir) {
|
||||
// Load more renderers from DLLs in the given directory
|
||||
m_impl->rendererDirectory = dir;
|
||||
return m_impl->GetRenderers();
|
||||
}
|
||||
|
||||
|
||||
NvCV_Status MeshRendererBroker::getMeshRendererList(std::vector<std::string>& list) {
|
||||
list.clear();
|
||||
list.resize(m_impl->renderers.size());
|
||||
for (size_t i = 0; i < list.size(); ++i)
|
||||
list[i] = m_impl->renderers[i].name;
|
||||
return list.size() ? NVCV_SUCCESS : NVCV_ERR_FEATURENOTFOUND;
|
||||
}
|
||||
|
||||
|
||||
NvCV_Status MeshRendererBroker::info(const char *renderer, const char **info) {
|
||||
if (!info)
|
||||
return NVCV_ERR_PARAMETER;
|
||||
for (const RendererInfo& ri : m_impl->renderers) {
|
||||
if (ri.name == renderer) {
|
||||
*info = ri.info.c_str();
|
||||
return NVCV_SUCCESS;
|
||||
}
|
||||
}
|
||||
*info = nullptr;
|
||||
return NVCV_ERR_FEATURENOTFOUND;
|
||||
}
|
||||
|
||||
|
||||
NvCV_Status MeshRendererBroker::create(const char *renderer, MeshRenderer **han) {
|
||||
if (!han)
|
||||
return NVCV_ERR_PARAMETER;
|
||||
for (const RendererInfo& ri : m_impl->renderers) {
|
||||
if (ri.name == renderer) {
|
||||
if (!ri.dispatch.create) {
|
||||
NvCV_Status err = m_impl->LoadRenderer(renderer);
|
||||
if (NVCV_SUCCESS != err)
|
||||
return err;
|
||||
}
|
||||
return ri.dispatch.create(han);
|
||||
}
|
||||
}
|
||||
*han = nullptr;
|
||||
return NVCV_ERR_FEATURENOTFOUND;
|
||||
}
|
||||
|
||||
|
||||
void MeshRendererBroker::addRenderer(MeshRenderer::Dispatch *disp) {
|
||||
unsigned n = unsigned(m_impl->renderers.size());
|
||||
m_impl->renderers.resize(n + 1);
|
||||
RendererInfo& ri = m_impl->renderers[n];
|
||||
ri.dispatch = *disp;
|
||||
const char *str;
|
||||
disp->name(&str); ri.name = str;
|
||||
disp->info(&str); ri.info = str;
|
||||
}
|
||||
149
samples/ExpressionApp/MeshRenderer.h
Normal file
149
samples/ExpressionApp/MeshRenderer.h
Normal file
@@ -0,0 +1,149 @@
|
||||
/*###############################################################################
|
||||
#
|
||||
# Copyright 2021 NVIDIA Corporation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
###############################################################################*/
|
||||
|
||||
#ifndef __MESH_RENDERER__
|
||||
#define __MESH_RENDERER__
|
||||
|
||||
#include "nvCVImage.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
/// Abstract class to provide methods and hide the implementation.
|
||||
class MeshRenderer {
|
||||
public:
|
||||
struct Dispatch {
|
||||
// We get these procs from the DLL
|
||||
NvCV_Status (*name)(const char **str);
|
||||
NvCV_Status (*info)(const char **str);
|
||||
NvCV_Status (*create)(MeshRenderer **han);
|
||||
void (*destroy)(MeshRenderer *han);
|
||||
NvCV_Status (*read)(MeshRenderer *han, const char *modelFile);
|
||||
NvCV_Status (*init)(MeshRenderer *han, unsigned width, unsigned height, const char *windowName);
|
||||
NvCV_Status (*setCamera)(MeshRenderer *han,
|
||||
const float locPt[3], const float lookVec[3], const float upVec[3], float vfov);
|
||||
NvCV_Status (*render)(MeshRenderer *han,
|
||||
const float exprs[53], const float qrot[4], const float trans[3], NvCVImage *result);
|
||||
Dispatch();
|
||||
~Dispatch() {}
|
||||
};
|
||||
|
||||
/// Destructor.
|
||||
void destroy();
|
||||
|
||||
/// Get the name of the renderer associated with the given handle.
|
||||
/// @param[out] str a place to store a pointer to the name of the mesh renderer.
|
||||
/// @return NVCV_SUCCESS if the specified mesh renderer was successfully instantiated.
|
||||
NvCV_Status name(const char **str) const;
|
||||
|
||||
/// Get information about the renderer.
|
||||
/// @param[out] str a place to store a pointer to the name of the mesh renderer.
|
||||
/// @return NVCV_SUCCESS if the specified mesh renderer was successfully instantiated.
|
||||
NvCV_Status info(const char **str) const;
|
||||
|
||||
/// Read the specified mesh model.
|
||||
/// If another model was already loaded, it will first be unloaded.
|
||||
/// If a relative path is specified, several places are searched.
|
||||
/// @param[in] modelFile the name of the file containing the desired mesh model.
|
||||
/// @return NVCV_SUCCESS if the model was read successfully.
|
||||
NvCV_Status read(const char *modelFile);
|
||||
|
||||
/// Initialize the rendering resources.
|
||||
/// @param[in] width The desired width of the rendered image.
|
||||
/// @param[in] height The desired height of the rendered image.
|
||||
/// @param[in] windowName The name given to the auxiliary window, if the renderer requires one.
|
||||
/// @return NVCV_SUCCESS if the renderer was successfully initialized.
|
||||
NvCV_Status init(unsigned width, unsigned height, const char *windowName);
|
||||
|
||||
/// Set the viewing parameters.
|
||||
/// @param[in] locPt the 3D point location of the camera.
|
||||
/// NULL implies the default location, derived from the rest pose of the model.
|
||||
/// @param[in] lookVec the 3D vector indicating the direction of view. This does not need to be normalized.
|
||||
/// NULL implies the default direction, derived from the rest pose of the model.
|
||||
/// @param[in] upVec the 3D vector pointing up. This does not need to be normalized.
|
||||
/// NULL implies the default up direction, derived from the rest pose of the model.
|
||||
/// @param[in] vfov the vertical field of view of the camera. Zero implies an orthographic camera.
|
||||
/// @return NVCV_SUCCESS if the camera was initialized successfully.
|
||||
NvCV_Status setCamera(const float locPt[3], const float lookVec[3], const float upVec[3], float vfov);
|
||||
|
||||
/// Render the mesh as deformed by the expression signals.
|
||||
/// @param[in] exprs the expression signals (53 of them).
|
||||
/// @param[in] qrot the rotation of the model as an xyzw quaternion.
|
||||
/// @param[in] trans the translation of the model as an xyz vector.
|
||||
/// @param[out] result the resultant rendered image.
|
||||
/// @note: This will appear upside-down.
|
||||
NvCV_Status render(const float exprs[53], const float qrot[4], const float trans[3], NvCVImage *result);
|
||||
|
||||
protected:
|
||||
MeshRenderer() {} ///< Never create a member of this class
|
||||
~MeshRenderer() {} ///< Instantiations are always subclasses
|
||||
|
||||
Dispatch m_dispatch;
|
||||
};
|
||||
|
||||
class MeshRendererBroker {
|
||||
public:
|
||||
|
||||
/// Constructor.
|
||||
MeshRendererBroker();
|
||||
|
||||
/// Destructor.
|
||||
~MeshRendererBroker();
|
||||
|
||||
/// Set the directory to be searched for additional renderers.
|
||||
/// @param[in] dir the directory to be searched for additional renderers.
|
||||
/// @return +NVCV_SUCCESS if the operation was successful.
|
||||
NvCV_Status setRendererDirectory(const char *dir);
|
||||
|
||||
/// Return a list of the available mesh renderers.
|
||||
/// @param[out] list pointer to a place to store the list of available renderers, separated by newlines.
|
||||
/// @return NVCV_SUCCESS if a list was successfully returned.
|
||||
NvCV_Status getMeshRendererList(std::vector<std::string>& list);
|
||||
|
||||
/// Retrieve the information about the selected renderer.
|
||||
/// @param[in] renderer the selected renderer.
|
||||
/// @param[out] info a place to store a pointer to the information about the selected renderer.
|
||||
/// @return NVCV_SUCCESS if the information was successfully retrieved;
|
||||
/// NVCV_ERR_FEATURENOTFOUND if the specified renderer was not found.
|
||||
/// @note This string is ephemeral. If persistency is desired, a copy must be made. The previous pointer is
|
||||
/// invalidated when this is called repeatedly
|
||||
NvCV_Status info(const char *renderer, const char **info);
|
||||
|
||||
/// Create an instance of the chosen mesh renderer.
|
||||
/// @param[in] renderer the desired renderer. NULL chooses the default renderer.
|
||||
/// @param[out] han a place to store a handle to the desired mesh renderer.
|
||||
/// @return NVCV_SUCCESS if the specified mesh renderer was successfully instantiated.
|
||||
/// NVCV_ERR_FEATURENOTFOUND if the specified renderer was not found.
|
||||
NvCV_Status create(const char *renderer, MeshRenderer **han);
|
||||
|
||||
/// Add a new renderer to the broker's portfolio.
|
||||
/// @param disp the renderer's dispatch table.
|
||||
void addRenderer(MeshRenderer::Dispatch *disp);
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
Impl *m_impl;
|
||||
};
|
||||
|
||||
#endif // __MESH_RENDERER__
|
||||
|
||||
19
samples/ExpressionApp/Readme.txt
Normal file
19
samples/ExpressionApp/Readme.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
ExpressionApp is a sample application using the AR SDK to extract face expression signals from video. These signals are
|
||||
used to control the expressions, pose and gaze of a 3D morphable face model. The application can either process
|
||||
real-time video from a webcam or offline videos from files. It illustrates the facial keypoints that are tracked, plots
|
||||
the expression signals that are derived, and renders an animated 3D avatar mesh.
|
||||
|
||||
The application runs either the Face3DReconstruction, or FaceExpression feature, depending on which expression mode is
|
||||
used. The expression mode is toggled using the '1' and '2' keys on the keyboard
|
||||
1 - Face3DReconstruction expression estimation
|
||||
2 - FaceExpression expression estimation (default, and recommended for avatar animation)
|
||||
|
||||
The FaceExpression mode is preferred for avatar animation. Note that Face3DReconstruction is demonstrated for its
|
||||
ability to track the face over time for AR effects. This feature enables identity face shape estimation on top of
|
||||
expression estimation and is better demonstrated in the FaceTrack sample application. The resulting expression weights
|
||||
from FaceExpression is more accurate than from Face3DReconstruction.
|
||||
|
||||
For details on command line arguments, execute ExpressionApp.exe --help.
|
||||
For more controls and configurations of the sample app, including expression definition and conversion to ARKit
|
||||
blendshapes, please read the SDK programming guide. It also contains information about how to control the GUI which can
|
||||
be enabled by running the application with the --show_ui argument.
|
||||
274
samples/ExpressionApp/nvARProxy.cpp
Normal file
274
samples/ExpressionApp/nvARProxy.cpp
Normal file
@@ -0,0 +1,274 @@
|
||||
/*###############################################################################
|
||||
#
|
||||
# Copyright 2020 NVIDIA Corporation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
###############################################################################*/
|
||||
#include <string>
|
||||
|
||||
#include "nvAR.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define _WINSOCKAPI_
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
typedef void* HMODULE;
|
||||
typedef void* HANDLE;
|
||||
typedef void* HINSTANCE;
|
||||
#endif
|
||||
|
||||
// Parameter string does not include the file extension
|
||||
#ifdef _WIN32
|
||||
#define nvLoadLibrary(library) LoadLibrary(TEXT(library ".dll"))
|
||||
#else
|
||||
#define nvLoadLibrary(library) dlopen("lib" library ".so", RTLD_LAZY)
|
||||
#endif
|
||||
|
||||
|
||||
inline void* nvGetProcAddress(HINSTANCE handle, const char* proc) {
|
||||
if (nullptr == handle) return nullptr;
|
||||
#ifdef _WIN32
|
||||
return GetProcAddress(handle, proc);
|
||||
#else
|
||||
return dlsym(handle, proc);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int nvFreeLibrary(HINSTANCE handle) {
|
||||
#ifdef _WIN32
|
||||
return FreeLibrary(handle);
|
||||
#else
|
||||
return dlclose(handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
HINSTANCE getNvARLib() {
|
||||
|
||||
TCHAR path[MAX_PATH], fullPath[MAX_PATH];
|
||||
bool bSDKPathSet = false;
|
||||
|
||||
extern char* g_nvARSDKPath;
|
||||
if (g_nvARSDKPath && g_nvARSDKPath[0]) {
|
||||
#ifndef UNICODE
|
||||
strncpy_s(fullPath, MAX_PATH, g_nvARSDKPath, MAX_PATH);
|
||||
#else
|
||||
size_t res = 0;
|
||||
mbstowcs_s(&res, fullPath, MAX_PATH, g_nvARSDKPath, MAX_PATH);
|
||||
#endif
|
||||
SetDllDirectory(fullPath);
|
||||
bSDKPathSet = true;
|
||||
}
|
||||
|
||||
if (!bSDKPathSet) {
|
||||
|
||||
// There can be multiple apps on the system,
|
||||
// some might include the SDK in the app package and
|
||||
// others might expect the SDK to be installed in Program Files
|
||||
GetEnvironmentVariable(TEXT("NV_AR_SDK_PATH"), path, MAX_PATH);
|
||||
if (_tcscmp(path, TEXT("USE_APP_PATH"))) {
|
||||
// App has not set environment variable to "USE_APP_PATH"
|
||||
// So pick up the SDK dll and dependencies from Program Files
|
||||
GetEnvironmentVariable(TEXT("ProgramFiles"), path, MAX_PATH);
|
||||
size_t max_len = sizeof(fullPath) / sizeof(TCHAR);
|
||||
_stprintf_s(fullPath, max_len, TEXT("%s\\NVIDIA Corporation\\NVIDIA AR SDK\\"), path);
|
||||
SetDllDirectory(fullPath);
|
||||
}
|
||||
}
|
||||
static const HINSTANCE NvArLib = nvLoadLibrary("nvARPose");
|
||||
return NvArLib;
|
||||
}
|
||||
|
||||
NvCV_Status NvAR_API NvAR_GetVersion(unsigned int* version) {
|
||||
static const auto funcPtr = (decltype(NvAR_GetVersion)*)nvGetProcAddress(getNvARLib(), "NvAR_GetVersion");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(version);
|
||||
}
|
||||
|
||||
NvCV_Status NvAR_API NvAR_Create(NvAR_FeatureID featureID, NvAR_FeatureHandle* handle) {
|
||||
static const auto funcPtr = (decltype(NvAR_Create)*)nvGetProcAddress(getNvARLib(), "NvAR_Create");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(featureID, handle);
|
||||
}
|
||||
|
||||
NvCV_Status NvAR_API NvAR_Destroy(NvAR_FeatureHandle handle) {
|
||||
static const auto funcPtr = (decltype(NvAR_Destroy)*)nvGetProcAddress(getNvARLib(), "NvAR_Destroy");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(handle);
|
||||
}
|
||||
|
||||
NvCV_Status NvAR_API NvAR_SetU32(NvAR_FeatureHandle handle, const char* name, unsigned int val) {
|
||||
static const auto funcPtr = (decltype(NvAR_SetU32)*)nvGetProcAddress(getNvARLib(), "NvAR_SetU32");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(handle, name, val);
|
||||
}
|
||||
|
||||
NvCV_Status NvAR_API NvAR_SetS32(NvAR_FeatureHandle handle, const char* name, int val) {
|
||||
static const auto funcPtr = (decltype(NvAR_SetS32)*)nvGetProcAddress(getNvARLib(), "NvAR_SetS32");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(handle, name, val);
|
||||
}
|
||||
|
||||
NvCV_Status NvAR_API NvAR_SetF32(NvAR_FeatureHandle handle, const char* name, float val) {
|
||||
static const auto funcPtr = (decltype(NvAR_SetF32)*)nvGetProcAddress(getNvARLib(), "NvAR_SetF32");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(handle, name, val);
|
||||
}
|
||||
|
||||
NvCV_Status NvAR_API NvAR_SetF64(NvAR_FeatureHandle handle, const char* name, double val) {
|
||||
static const auto funcPtr = (decltype(NvAR_SetF64)*)nvGetProcAddress(getNvARLib(), "NvAR_SetF64");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(handle, name, val);
|
||||
}
|
||||
|
||||
NvCV_Status NvAR_API NvAR_SetU64(NvAR_FeatureHandle handle, const char* name, unsigned long long val) {
|
||||
static const auto funcPtr = (decltype(NvAR_SetU64)*)nvGetProcAddress(getNvARLib(), "NvAR_SetU64");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(handle, name, val);
|
||||
}
|
||||
|
||||
NvCV_Status NvAR_API NvAR_SetObject(NvAR_FeatureHandle handle, const char* name, void* ptr, unsigned long typeSize) {
|
||||
static const auto funcPtr = (decltype(NvAR_SetObject)*)nvGetProcAddress(getNvARLib(), "NvAR_SetObject");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(handle, name, ptr, typeSize);
|
||||
}
|
||||
|
||||
NvCV_Status NvAR_API NvAR_SetString(NvAR_FeatureHandle handle, const char* name, const char* str) {
|
||||
static const auto funcPtr = (decltype(NvAR_SetString)*)nvGetProcAddress(getNvARLib(), "NvAR_SetString");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(handle, name, str);
|
||||
}
|
||||
|
||||
NvCV_Status NvAR_API NvAR_SetCudaStream(NvAR_FeatureHandle handle, const char* name, CUstream stream) {
|
||||
static const auto funcPtr = (decltype(NvAR_SetCudaStream)*)nvGetProcAddress(getNvARLib(), "NvAR_SetCudaStream");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(handle, name, stream);
|
||||
}
|
||||
|
||||
NvCV_Status NvAR_API NvAR_SetF32Array(NvAR_FeatureHandle handle, const char* name, float* val, int count) {
|
||||
static const auto funcPtr = (decltype(NvAR_SetF32Array)*)nvGetProcAddress(getNvARLib(), "NvAR_SetF32Array");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(handle, name, val, count);
|
||||
}
|
||||
|
||||
NvCV_Status NvAR_API NvAR_GetU32(NvAR_FeatureHandle handle, const char* name, unsigned int* val) {
|
||||
static const auto funcPtr = (decltype(NvAR_GetU32)*)nvGetProcAddress(getNvARLib(), "NvAR_GetU32");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(handle, name, val);
|
||||
}
|
||||
|
||||
NvCV_Status NvAR_API NvAR_GetS32(NvAR_FeatureHandle handle, const char* name, int* val) {
|
||||
static const auto funcPtr = (decltype(NvAR_GetS32)*)nvGetProcAddress(getNvARLib(), "NvAR_GetS32");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(handle, name, val);
|
||||
}
|
||||
|
||||
NvCV_Status NvAR_API NvAR_GetF32(NvAR_FeatureHandle handle, const char* name, float* val) {
|
||||
static const auto funcPtr = (decltype(NvAR_GetF32)*)nvGetProcAddress(getNvARLib(), "NvAR_GetF32");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(handle, name, val);
|
||||
}
|
||||
|
||||
NvCV_Status NvAR_API NvAR_GetF64(NvAR_FeatureHandle handle, const char* name, double* val) {
|
||||
static const auto funcPtr = (decltype(NvAR_GetF64)*)nvGetProcAddress(getNvARLib(), "NvAR_GetF64");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(handle, name, val);
|
||||
}
|
||||
|
||||
NvCV_Status NvAR_API NvAR_GetU64(NvAR_FeatureHandle handle, const char* name, unsigned long long* val) {
|
||||
static const auto funcPtr = (decltype(NvAR_GetU64)*)nvGetProcAddress(getNvARLib(), "NvAR_GetU64");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(handle, name, val);
|
||||
}
|
||||
|
||||
NvCV_Status NvAR_API NvAR_GetObject(NvAR_FeatureHandle handle, const char* name, const void** ptr, unsigned long typeSize) {
|
||||
static const auto funcPtr = (decltype(NvAR_GetObject)*)nvGetProcAddress(getNvARLib(), "NvAR_GetObject");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(handle, name, ptr, typeSize);
|
||||
}
|
||||
|
||||
NvCV_Status NvAR_API NvAR_GetString(NvAR_FeatureHandle handle, const char* name, const char** str) {
|
||||
static const auto funcPtr = (decltype(NvAR_GetString)*)nvGetProcAddress(getNvARLib(), "NvAR_GetString");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(handle, name, str);
|
||||
}
|
||||
|
||||
NvCV_Status NvAR_API NvAR_GetCudaStream(NvAR_FeatureHandle handle, const char* name, const CUstream* stream) {
|
||||
static const auto funcPtr = (decltype(NvAR_GetCudaStream)*)nvGetProcAddress(getNvARLib(), "NvAR_GetCudaStream");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(handle, name, stream);
|
||||
}
|
||||
|
||||
NvCV_Status NvAR_API NvAR_GetF32Array(NvAR_FeatureHandle handle, const char* name, const float** vals, int* count) {
|
||||
static const auto funcPtr = (decltype(NvAR_GetF32Array)*)nvGetProcAddress(getNvARLib(), "NvAR_GetF32Array");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(handle, name, vals, count);
|
||||
}
|
||||
|
||||
NvCV_Status NvAR_API NvAR_Run(NvAR_FeatureHandle handle) {
|
||||
static const auto funcPtr = (decltype(NvAR_Run)*)nvGetProcAddress(getNvARLib(), "NvAR_Run");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(handle);
|
||||
}
|
||||
|
||||
NvCV_Status NvAR_API NvAR_Load(NvAR_FeatureHandle handle) {
|
||||
static const auto funcPtr = (decltype(NvAR_Load)*)nvGetProcAddress(getNvARLib(), "NvAR_Load");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(handle);
|
||||
}
|
||||
|
||||
NvCV_Status NvAR_API NvAR_CudaStreamCreate(CUstream* stream) {
|
||||
static const auto funcPtr =
|
||||
(decltype(NvAR_CudaStreamCreate)*)nvGetProcAddress(getNvARLib(), "NvAR_CudaStreamCreate");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(stream);
|
||||
}
|
||||
|
||||
NvCV_Status NvAR_API NvAR_CudaStreamDestroy(CUstream stream) {
|
||||
static const auto funcPtr =
|
||||
(decltype(NvAR_CudaStreamDestroy)*)nvGetProcAddress(getNvARLib(), "NvAR_CudaStreamDestroy");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(stream);
|
||||
}
|
||||
341
samples/ExpressionApp/nvCVImageProxy.cpp
Normal file
341
samples/ExpressionApp/nvCVImageProxy.cpp
Normal file
@@ -0,0 +1,341 @@
|
||||
#if defined(linux) || defined(unix) || defined(__linux)
|
||||
#warning nvCVImageProxy.cpp not ported
|
||||
#else
|
||||
/*###############################################################################
|
||||
#
|
||||
# Copyright 2020 NVIDIA Corporation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
###############################################################################*/
|
||||
#include <string>
|
||||
#include "nvCVImage.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define _WINSOCKAPI_
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
#include "nvTransferD3D.h"
|
||||
#include "nvTransferD3D11.h"
|
||||
#else // !_WIN32
|
||||
#include <dlfcn.h>
|
||||
typedef void* HMODULE;
|
||||
typedef void* HANDLE;
|
||||
typedef void* HINSTANCE;
|
||||
#endif // _WIN32
|
||||
|
||||
// Parameter string does not include the file extension
|
||||
#ifdef _WIN32
|
||||
#define nvLoadLibrary(library) LoadLibrary(TEXT(library ".dll"))
|
||||
#else // !_WIN32
|
||||
#define nvLoadLibrary(library) dlopen("lib" library ".so", RTLD_LAZY)
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
inline void* nvGetProcAddress(HINSTANCE handle, const char* proc) {
|
||||
if (nullptr == handle) return nullptr;
|
||||
#ifdef _WIN32
|
||||
return GetProcAddress(handle, proc);
|
||||
#else // !_WIN32
|
||||
return dlsym(handle, proc);
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
inline int nvFreeLibrary(HINSTANCE handle) {
|
||||
#ifdef _WIN32
|
||||
return FreeLibrary(handle);
|
||||
#else
|
||||
return dlclose(handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
HINSTANCE getNvCVImageLib() {
|
||||
TCHAR path[MAX_PATH], tmpPath[MAX_PATH], fullPath[MAX_PATH];
|
||||
static HINSTANCE nvCVImageLib = NULL;
|
||||
static bool bSDKPathSet = false;
|
||||
if (!bSDKPathSet) {
|
||||
nvCVImageLib = nvLoadLibrary("NVCVImage");
|
||||
if (nvCVImageLib) bSDKPathSet = true;
|
||||
}
|
||||
if (!bSDKPathSet) {
|
||||
// There can be multiple apps on the system,
|
||||
// some might include the SDK in the app package and
|
||||
// others might expect the SDK to be installed in Program Files
|
||||
GetEnvironmentVariable(TEXT("NV_VIDEO_EFFECTS_PATH"), path, MAX_PATH);
|
||||
GetEnvironmentVariable(TEXT("NV_AR_SDK_PATH"), tmpPath, MAX_PATH);
|
||||
if (_tcscmp(path, TEXT("USE_APP_PATH")) && _tcscmp(tmpPath, TEXT("USE_APP_PATH"))) {
|
||||
// App has not set environment variable to "USE_APP_PATH"
|
||||
// So pick up the SDK dll and dependencies from Program Files
|
||||
GetEnvironmentVariable(TEXT("ProgramFiles"), path, MAX_PATH);
|
||||
size_t max_len = sizeof(fullPath) / sizeof(TCHAR);
|
||||
_stprintf_s(fullPath, max_len, TEXT("%s\\NVIDIA Corporation\\NVIDIA Video Effects\\"), path);
|
||||
SetDllDirectory(fullPath);
|
||||
nvCVImageLib = nvLoadLibrary("NVCVImage");
|
||||
if (!nvCVImageLib) {
|
||||
_stprintf_s(fullPath, max_len, TEXT("%s\\NVIDIA Corporation\\NVIDIA AR SDK\\"), path);
|
||||
SetDllDirectory(fullPath);
|
||||
nvCVImageLib = nvLoadLibrary("NVCVImage");
|
||||
}
|
||||
}
|
||||
bSDKPathSet = true;
|
||||
}
|
||||
return nvCVImageLib;
|
||||
}
|
||||
|
||||
NvCV_Status NvCV_API NvCVImage_Init(NvCVImage* im, unsigned width, unsigned height, int pitch, void* pixels,
|
||||
NvCVImage_PixelFormat format, NvCVImage_ComponentType type, unsigned isPlanar,
|
||||
unsigned onGPU) {
|
||||
static const auto funcPtr = (decltype(NvCVImage_Init)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_Init");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(im, width, height, pitch, pixels, format, type, isPlanar, onGPU);
|
||||
}
|
||||
|
||||
void NvCV_API NvCVImage_InitView(NvCVImage* subImg, NvCVImage* fullImg, int x, int y, unsigned width,
|
||||
unsigned height) {
|
||||
static const auto funcPtr = (decltype(NvCVImage_InitView)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_InitView");
|
||||
|
||||
if (nullptr != funcPtr) funcPtr(subImg, fullImg, x, y, width, height);
|
||||
}
|
||||
|
||||
NvCV_Status NvCV_API NvCVImage_Alloc(NvCVImage* im, unsigned width, unsigned height, NvCVImage_PixelFormat format,
|
||||
NvCVImage_ComponentType type, unsigned isPlanar, unsigned onGPU, unsigned alignment) {
|
||||
static const auto funcPtr = (decltype(NvCVImage_Alloc)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_Alloc");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(im, width, height, format, type, isPlanar, onGPU, alignment);
|
||||
}
|
||||
|
||||
NvCV_Status NvCV_API NvCVImage_Realloc(NvCVImage* im, unsigned width, unsigned height,
|
||||
NvCVImage_PixelFormat format, NvCVImage_ComponentType type,
|
||||
unsigned isPlanar, unsigned onGPU, unsigned alignment) {
|
||||
static const auto funcPtr = (decltype(NvCVImage_Realloc)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_Realloc");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(im, width, height, format, type, isPlanar, onGPU, alignment);
|
||||
}
|
||||
|
||||
void NvCV_API NvCVImage_Dealloc(NvCVImage* im) {
|
||||
static const auto funcPtr = (decltype(NvCVImage_Dealloc)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_Dealloc");
|
||||
|
||||
if (nullptr != funcPtr) funcPtr(im);
|
||||
}
|
||||
|
||||
void NvCV_API NvCVImage_DeallocAsync(NvCVImage* im, CUstream_st* stream) {
|
||||
static const auto funcPtr = (decltype(NvCVImage_DeallocAsync)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_DeallocAsync");
|
||||
|
||||
if (nullptr != funcPtr) funcPtr(im, stream);
|
||||
}
|
||||
|
||||
NvCV_Status NvCV_API NvCVImage_Create(unsigned width, unsigned height, NvCVImage_PixelFormat format,
|
||||
NvCVImage_ComponentType type, unsigned isPlanar, unsigned onGPU,
|
||||
unsigned alignment, NvCVImage** out) {
|
||||
static const auto funcPtr = (decltype(NvCVImage_Create)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_Create");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(width, height, format, type, isPlanar, onGPU, alignment, out);
|
||||
}
|
||||
|
||||
void NvCV_API NvCVImage_Destroy(NvCVImage* im) {
|
||||
static const auto funcPtr = (decltype(NvCVImage_Destroy)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_Destroy");
|
||||
|
||||
if (nullptr != funcPtr) funcPtr(im);
|
||||
}
|
||||
|
||||
void NvCV_API NvCVImage_ComponentOffsets(NvCVImage_PixelFormat format, int* rOff, int* gOff, int* bOff, int* aOff,
|
||||
int* yOff) {
|
||||
static const auto funcPtr =
|
||||
(decltype(NvCVImage_ComponentOffsets)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_ComponentOffsets");
|
||||
|
||||
if (nullptr != funcPtr) funcPtr(format, rOff, gOff, bOff, aOff, yOff);
|
||||
}
|
||||
|
||||
NvCV_Status NvCV_API NvCVImage_Transfer(const NvCVImage* src, NvCVImage* dst, float scale, CUstream_st* stream,
|
||||
NvCVImage* tmp) {
|
||||
static const auto funcPtr = (decltype(NvCVImage_Transfer)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_Transfer");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(src, dst, scale, stream, tmp);
|
||||
}
|
||||
|
||||
NvCV_Status NvCV_API NvCVImage_TransferRect(const NvCVImage *src, const NvCVRect2i *srcRect, NvCVImage *dst,
|
||||
const NvCVPoint2i *dstPt, float scale, struct CUstream_st *stream, NvCVImage *tmp) {
|
||||
static const auto funcPtr = (decltype(NvCVImage_TransferRect)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_TransferRect");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(src, srcRect, dst, dstPt, scale, stream, tmp);
|
||||
}
|
||||
|
||||
NvCV_Status NvCV_API NvCVImage_TransferFromYUV(const void *y, int yPixBytes, int yPitch, const void *u, const void *v,
|
||||
int uvPixBytes, int uvPitch, NvCVImage_PixelFormat yuvFormat, NvCVImage_ComponentType yuvType, unsigned yuvColorSpace,
|
||||
unsigned yuvMemSpace, NvCVImage *dst, const NvCVRect2i *dstRect, float scale, struct CUstream_st *stream, NvCVImage *tmp) {
|
||||
static const auto funcPtr = (decltype(NvCVImage_TransferFromYUV)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_TransferFromYUV");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(y, yPixBytes, yPitch, u, v, uvPixBytes, uvPitch, yuvFormat, yuvType, yuvColorSpace, yuvMemSpace, dst,
|
||||
dstRect, scale, stream, tmp);
|
||||
}
|
||||
|
||||
NvCV_Status NvCV_API NvCVImage_TransferToYUV(const NvCVImage *src, const NvCVRect2i *srcRect,
|
||||
const void *y, int yPixBytes, int yPitch, const void *u, const void *v, int uvPixBytes, int uvPitch,
|
||||
NvCVImage_PixelFormat yuvFormat, NvCVImage_ComponentType yuvType, unsigned yuvColorSpace, unsigned yuvMemSpace,
|
||||
float scale, struct CUstream_st *stream, NvCVImage *tmp) {
|
||||
static const auto funcPtr = (decltype(NvCVImage_TransferToYUV)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_TransferToYUV");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(src, srcRect, y, yPixBytes, yPitch, u, v, uvPixBytes, uvPitch, yuvFormat, yuvType, yuvColorSpace, yuvMemSpace, scale, stream, tmp);
|
||||
}
|
||||
|
||||
NvCV_Status NvCV_API NvCVImage_MapResource(NvCVImage *im, struct CUstream_st *stream) {
|
||||
static const auto funcPtr = (decltype(NvCVImage_MapResource)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_MapResource");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(im, stream);
|
||||
}
|
||||
|
||||
NvCV_Status NvCV_API NvCVImage_UnmapResource(NvCVImage *im, struct CUstream_st *stream) {
|
||||
static const auto funcPtr = (decltype(NvCVImage_UnmapResource)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_UnmapResource");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(im, stream);
|
||||
}
|
||||
|
||||
#if RTX_CAMERA_IMAGE == 0
|
||||
NvCV_Status NvCV_API NvCVImage_Composite(const NvCVImage* fg, const NvCVImage* bg, const NvCVImage* mat, NvCVImage* dst,
|
||||
struct CUstream_st *stream) {
|
||||
static const auto funcPtr = (decltype(NvCVImage_Composite)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_Composite");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(fg, bg, mat, dst, stream);
|
||||
}
|
||||
#else // RTX_CAMERA_IMAGE == 1
|
||||
NvCV_Status NvCV_API NvCVImage_Composite(const NvCVImage* fg, const NvCVImage* bg, const NvCVImage* mat, NvCVImage* dst) {
|
||||
static const auto funcPtr = (decltype(NvCVImage_Composite)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_Composite");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(fg, bg, mat, dst);
|
||||
}
|
||||
#endif // RTX_CAMERA_IMAGE
|
||||
|
||||
NvCV_Status NvCV_API NvCVImage_CompositeRect(
|
||||
const NvCVImage *fg, const NvCVPoint2i *fgOrg,
|
||||
const NvCVImage *bg, const NvCVPoint2i *bgOrg,
|
||||
const NvCVImage *mat, unsigned mode,
|
||||
NvCVImage *dst, const NvCVPoint2i *dstOrg,
|
||||
struct CUstream_st *stream) {
|
||||
static const auto funcPtr = (decltype(NvCVImage_CompositeRect)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_CompositeRect");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(fg, fgOrg, bg, bgOrg, mat, mode, dst, dstOrg, stream);
|
||||
}
|
||||
|
||||
#if RTX_CAMERA_IMAGE == 0
|
||||
NvCV_Status NvCV_API NvCVImage_CompositeOverConstant(const NvCVImage *src, const NvCVImage *mat,
|
||||
const void *bgColor, NvCVImage *dst, struct CUstream_st *stream) {
|
||||
static const auto funcPtr =
|
||||
(decltype(NvCVImage_CompositeOverConstant)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_CompositeOverConstant");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(src, mat, bgColor, dst, stream);
|
||||
}
|
||||
#else // RTX_CAMERA_IMAGE == 1
|
||||
NvCV_Status NvCV_API NvCVImage_CompositeOverConstant(const NvCVImage *src, const NvCVImage *mat,
|
||||
const unsigned char bgColor[3], NvCVImage *dst) {
|
||||
static const auto funcPtr =
|
||||
(decltype(NvCVImage_CompositeOverConstant)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_CompositeOverConstant");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(src, mat, bgColor, dst);
|
||||
}
|
||||
#endif // RTX_CAMERA_IMAGE
|
||||
|
||||
|
||||
NvCV_Status NvCV_API NvCVImage_FlipY(const NvCVImage *src, NvCVImage *dst) {
|
||||
static const auto funcPtr = (decltype(NvCVImage_FlipY)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_FlipY");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(src, dst);
|
||||
}
|
||||
|
||||
NvCV_Status NvCV_API NvCVImage_Sharpen(float sharpness, const NvCVImage *src, NvCVImage *dst,
|
||||
struct CUstream_st *stream, NvCVImage *tmp) {
|
||||
static const auto funcPtr = (decltype(NvCVImage_Sharpen)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_Sharpen");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(sharpness, src, dst, stream, tmp);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport) const char* __cdecl
|
||||
#else
|
||||
const char*
|
||||
#endif // _WIN32 or linux
|
||||
NvCV_GetErrorStringFromCode(NvCV_Status code) {
|
||||
static const auto funcPtr =
|
||||
(decltype(NvCV_GetErrorStringFromCode)*)nvGetProcAddress(getNvCVImageLib(), "NvCV_GetErrorStringFromCode");
|
||||
|
||||
if (nullptr == funcPtr) return "Cannot find nvCVImage DLL or its dependencies";
|
||||
return funcPtr(code);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef _WIN32 // Direct 3D
|
||||
|
||||
NvCV_Status NvCV_API NvCVImage_InitFromD3D11Texture(NvCVImage *im, struct ID3D11Texture2D *tx) {
|
||||
static const auto funcPtr = (decltype(NvCVImage_InitFromD3D11Texture)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_InitFromD3D11Texture");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(im, tx);
|
||||
}
|
||||
|
||||
NvCV_Status NvCV_API NvCVImage_ToD3DFormat(NvCVImage_PixelFormat format, NvCVImage_ComponentType type, unsigned layout, DXGI_FORMAT *d3dFormat) {
|
||||
static const auto funcPtr = (decltype(NvCVImage_ToD3DFormat)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_ToD3DFormat");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(format, type, layout, d3dFormat);
|
||||
}
|
||||
|
||||
NvCV_Status NvCV_API NvCVImage_FromD3DFormat(DXGI_FORMAT d3dFormat, NvCVImage_PixelFormat *format, NvCVImage_ComponentType *type, unsigned char *layout) {
|
||||
static const auto funcPtr = (decltype(NvCVImage_FromD3DFormat)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_FromD3DFormat");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(d3dFormat, format, type, layout);
|
||||
}
|
||||
|
||||
#ifdef __dxgicommon_h__
|
||||
|
||||
NvCV_Status NvCV_API NvCVImage_ToD3DColorSpace(unsigned char nvcvColorSpace, DXGI_COLOR_SPACE_TYPE *pD3dColorSpace) {
|
||||
static const auto funcPtr = (decltype(NvCVImage_ToD3DColorSpace)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_ToD3DColorSpace");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(nvcvColorSpace, pD3dColorSpace);
|
||||
}
|
||||
|
||||
NvCV_Status NvCV_API NvCVImage_FromD3DColorSpace(DXGI_COLOR_SPACE_TYPE d3dColorSpace, unsigned char *pNvcvColorSpace) {
|
||||
static const auto funcPtr = (decltype(NvCVImage_FromD3DColorSpace)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_FromD3DColorSpace");
|
||||
|
||||
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
|
||||
return funcPtr(d3dColorSpace, pNvcvColorSpace);
|
||||
}
|
||||
|
||||
#endif // __dxgicommon_h__
|
||||
|
||||
#endif // _WIN32 Direct 3D
|
||||
|
||||
#endif // enabling for this file
|
||||
3
samples/ExpressionApp/run.bat
Normal file
3
samples/ExpressionApp/run.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
SETLOCAL
|
||||
SET PATH=%PATH%;..\..\samples\external\opencv\bin;..\..\bin;
|
||||
ExpressionApp.exe
|
||||
@@ -7,11 +7,14 @@ set(SOURCE_FILES FaceEngine.cpp
|
||||
|
||||
set(HEADER_FILES FaceEngine.h)
|
||||
|
||||
set(SOURCE_FILES ${SOURCE_FILES} ../../nvar/src/nvARProxy.cpp ../../nvar/src/nvCVImageProxy.cpp)
|
||||
if(MSVC)
|
||||
set(SOURCE_FILES ${SOURCE_FILES} ../../nvar/src/nvARProxy.cpp ../../nvar/src/nvCVImageProxy.cpp)
|
||||
|
||||
# Set Visual Studio source filters
|
||||
source_group("Source Files" FILES ${SOURCE_FILES})
|
||||
source_group("Header Files" FILES ${HEADER_FILES})
|
||||
endif(MSVC)
|
||||
|
||||
# Set Visual Studio source filters
|
||||
source_group("Source Files" FILES ${SOURCE_FILES})
|
||||
source_group("Header Files" FILES ${HEADER_FILES})
|
||||
|
||||
add_executable(FaceTrack ${SOURCE_FILES} ${HEADER_FILES})
|
||||
target_include_directories(FaceTrack PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
@@ -19,13 +22,25 @@ target_include_directories(FaceTrack PUBLIC
|
||||
${SDK_INCLUDES_PATH}
|
||||
)
|
||||
|
||||
target_link_libraries(FaceTrack PUBLIC
|
||||
opencv346
|
||||
utils_sample
|
||||
)
|
||||
set(OPENCV_PATH_STR ${CMAKE_CURRENT_SOURCE_DIR}/../external/opencv/bin)
|
||||
set(PATH_STR "PATH=%PATH%" ${OPENCV_PATH_STR})
|
||||
set_target_properties(FaceTrack PROPERTIES
|
||||
FOLDER SampleApps
|
||||
VS_DEBUGGER_ENVIRONMENT "${PATH_STR}"
|
||||
VS_DEBUGGER_COMMAND_ARGUMENTS "${CMD_ARG_STR}" )
|
||||
if(MSVC)
|
||||
target_link_libraries(FaceTrack PUBLIC
|
||||
opencv346
|
||||
utils_sample
|
||||
)
|
||||
set(OPENCV_PATH_STR ${CMAKE_CURRENT_SOURCE_DIR}/../external/opencv/bin)
|
||||
set(PATH_STR "PATH=%PATH%" ${OPENCV_PATH_STR})
|
||||
set_target_properties(FaceTrack PROPERTIES
|
||||
FOLDER SampleApps
|
||||
VS_DEBUGGER_ENVIRONMENT "${PATH_STR}"
|
||||
VS_DEBUGGER_COMMAND_ARGUMENTS "${CMD_ARG_STR}" )
|
||||
elseif(UNIX)
|
||||
find_package(PNG REQUIRED)
|
||||
find_package(JPEG REQUIRED)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
|
||||
target_link_libraries(FaceTrack PUBLIC
|
||||
nvARPose
|
||||
NVCVImage
|
||||
OpenCV
|
||||
utils_sample
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -71,7 +71,7 @@ int FaceEngine::getNumExpressionCoefficients() {
|
||||
}
|
||||
|
||||
|
||||
FaceEngine::Err FaceEngine::createFeatures(const char* modelPath, unsigned int _batchSize) {
|
||||
FaceEngine::Err FaceEngine::createFeatures(const char* modelPath, unsigned int _batchSize, unsigned int mode) {
|
||||
FaceEngine::Err err = FaceEngine::Err::errNone;
|
||||
|
||||
NvCV_Status cuErr = NvAR_CudaStreamCreate(&stream);
|
||||
@@ -85,7 +85,7 @@ FaceEngine::Err FaceEngine::createFeatures(const char* modelPath, unsigned int _
|
||||
printf("ERROR: An error has occurred while initializing Face Detection\n");
|
||||
}
|
||||
} else if (appMode == landmarkDetection) {
|
||||
err = createLandmarkDetectionFeature(modelPath, _batchSize, stream);
|
||||
err = createLandmarkDetectionFeature(modelPath, _batchSize, stream, mode);
|
||||
if (err != Err::errNone) {
|
||||
printf("ERROR: An error has occurred while initializing Landmark Detection\n");
|
||||
}
|
||||
@@ -117,7 +117,7 @@ FaceEngine::Err FaceEngine::createFaceDetectionFeature(const char* modelPath, CU
|
||||
nvErr = NvAR_SetCudaStream(faceDetectHandle, NvAR_Parameter_Config(CUDAStream), str);
|
||||
BAIL_IF_NVERR(nvErr, err, FaceEngine::Err::errParameter);
|
||||
|
||||
nvErr = NvAR_SetU32(faceDetectHandle, NvAR_Parameter_Config(Temporal), bStabilizeFace);
|
||||
nvErr = NvAR_SetU32(faceDetectHandle, NvAR_Parameter_Config(Temporal), (bStabilizeFace ? -1 : 0));
|
||||
BAIL_IF_NVERR(nvErr, err, FaceEngine::Err::errParameter);
|
||||
|
||||
nvErr = NvAR_Load(faceDetectHandle);
|
||||
@@ -128,7 +128,7 @@ bail:
|
||||
}
|
||||
|
||||
FaceEngine::Err FaceEngine::createLandmarkDetectionFeature(const char* modelPath, unsigned int _batchSize,
|
||||
CUstream str) {
|
||||
CUstream str, unsigned int mode) {
|
||||
FaceEngine::Err err = FaceEngine::Err::errNone;
|
||||
NvCV_Status nvErr;
|
||||
|
||||
@@ -151,7 +151,7 @@ FaceEngine::Err FaceEngine::createLandmarkDetectionFeature(const char* modelPath
|
||||
nvErr = NvAR_SetU32(landmarkDetectHandle, NvAR_Parameter_Config(BatchSize), batchSize);
|
||||
BAIL_IF_NVERR(nvErr, err, FaceEngine::Err::errParameter);
|
||||
|
||||
nvErr = NvAR_SetU32(landmarkDetectHandle, NvAR_Parameter_Config(Temporal), bStabilizeFace);
|
||||
nvErr = NvAR_SetU32(landmarkDetectHandle, NvAR_Parameter_Config(Temporal), (bStabilizeFace ? -1 : 0));
|
||||
BAIL_IF_NVERR(nvErr, err, FaceEngine::Err::errParameter);
|
||||
|
||||
nvErr = NvAR_SetU32(landmarkDetectHandle, NvAR_Parameter_Config(Landmarks_Size), numLandmarks);
|
||||
@@ -160,6 +160,9 @@ FaceEngine::Err FaceEngine::createLandmarkDetectionFeature(const char* modelPath
|
||||
nvErr = NvAR_SetU32(landmarkDetectHandle, NvAR_Parameter_Config(LandmarksConfidence_Size), numLandmarks);
|
||||
BAIL_IF_NVERR(nvErr, err, FaceEngine::Err::errParameter);
|
||||
|
||||
nvErr = NvAR_SetU32(landmarkDetectHandle, NvAR_Parameter_Config(Mode), mode);
|
||||
BAIL_IF_NVERR(nvErr, err, FaceEngine::Err::errParameter);
|
||||
|
||||
nvErr = NvAR_Load(landmarkDetectHandle);
|
||||
BAIL_IF_NVERR(nvErr, err, FaceEngine::Err::errInitialization);
|
||||
|
||||
@@ -297,8 +300,20 @@ FaceEngine::Err FaceEngine::initFaceFittingIOParams(NvCVImage* inBuf) {
|
||||
FaceEngine::Err err = FaceEngine::Err::errNone;
|
||||
|
||||
face_mesh = new NvAR_FaceMesh();
|
||||
face_mesh->vertices = nullptr; //new NvAR_Vector3f[FACE_MODEL_NUM_VERTICES];
|
||||
face_mesh->tvi = nullptr; // new NvAR_Vector3u16[FACE_MODEL_NUM_INDICES];
|
||||
|
||||
unsigned int num_vertices, num_triangles;
|
||||
nvErr = NvAR_GetU32(faceFitHandle, NvAR_Parameter_Config(VertexCount), &num_vertices);
|
||||
BAIL_IF_NVERR(nvErr, err, FaceEngine::Err::errParameter);
|
||||
|
||||
nvErr = NvAR_GetU32(faceFitHandle, NvAR_Parameter_Config(TriangleCount), &num_triangles);
|
||||
BAIL_IF_NVERR(nvErr, err, FaceEngine::Err::errParameter);
|
||||
|
||||
face_mesh->num_vertices = num_vertices;
|
||||
face_mesh->num_triangles = num_triangles;
|
||||
m_vertices.assign(num_vertices, {0.f, 0.f, 0.f});
|
||||
m_triangles.assign(num_triangles, { 0, 0, 0 });
|
||||
face_mesh->vertices = m_vertices.data();
|
||||
face_mesh->tvi = m_triangles.data();
|
||||
rendering_params = new NvAR_RenderingParams();
|
||||
|
||||
nvErr = NvAR_SetObject(faceFitHandle, NvAR_Parameter_Input(Image), inBuf, sizeof(NvCVImage));
|
||||
@@ -419,14 +434,6 @@ void FaceEngine::releaseFaceFittingIOParams() {
|
||||
rendering_params = nullptr;
|
||||
}
|
||||
if (face_mesh) {
|
||||
if (face_mesh->vertices) {
|
||||
delete[] face_mesh->vertices;
|
||||
face_mesh->vertices = nullptr;
|
||||
}
|
||||
if (face_mesh->tvi) {
|
||||
delete[] face_mesh->tvi;
|
||||
face_mesh->tvi = nullptr;
|
||||
}
|
||||
delete face_mesh;
|
||||
face_mesh = nullptr;
|
||||
}
|
||||
@@ -557,34 +564,27 @@ static bool IntersectRectWithImage(const cv::Rect& srcRect, const cv::Mat& src,
|
||||
}
|
||||
#endif // UNUSED
|
||||
|
||||
void FaceEngine::DrawPose(const cv::Mat& src, const NvAR_Quaternion* pose) {
|
||||
float R[3][3];
|
||||
set_rotation_from_quaternion(pose, R[0]);
|
||||
float radius = 100.f;
|
||||
float x1 = radius * R[1][0];
|
||||
float y1 = radius * R[2][0];
|
||||
float x2 = radius * R[1][1];
|
||||
float y2 = radius * R[2][1];
|
||||
float x3 = radius * R[1][2] * -1.f;
|
||||
float y3 = radius * R[2][2] * -1.f;
|
||||
void FaceEngine::DrawPose(const cv::Mat& src, const NvAR_Quaternion* pose) const {
|
||||
const float vector_scale = 50.0f;
|
||||
const int thickness = 2;
|
||||
float rot_mat[3][3];
|
||||
set_rotation_from_quaternion(pose, rot_mat[0]);
|
||||
const auto avg_landmark_pos = GetAverageLandmarkPositionInGlSpace();
|
||||
|
||||
int nose_tip = 0;
|
||||
const char* kNoseTipName = "nose-tip";
|
||||
nose_tip = FindLandmarkIndexFromName(numLandmarks, kNoseTipName);
|
||||
cv::Point p0 = {static_cast<int>(avg_landmark_pos[0]), static_cast<int>(avg_landmark_pos[1])};
|
||||
cv::Point px = p0 + cv::Point(std::lround(rot_mat[0][0] * vector_scale), std::lround(rot_mat[0][1] * vector_scale));
|
||||
cv::Point py = p0 + cv::Point(std::lround(rot_mat[1][0] * vector_scale), std::lround(rot_mat[1][1] * vector_scale));
|
||||
cv::Point pz = p0 + cv::Point(std::lround(rot_mat[2][0] * vector_scale), std::lround(rot_mat[2][1] * vector_scale));
|
||||
|
||||
int width = src.cols;
|
||||
int height = src.rows;
|
||||
NvAR_Point2f cxy = *(facial_landmarks.data() + nose_tip);
|
||||
float cx1 = (float)std::min(std::max(0, int(cxy.x + x1)), width - 1);
|
||||
float cy1 = (float)std::min(std::max(0, int(cxy.y + y1)), height - 1);
|
||||
float cx2 = (float)std::min(std::max(0, int(cxy.x + x2)), width - 1);
|
||||
float cy2 = (float)std::min(std::max(0, int(cxy.y + y2)), height - 1);
|
||||
float cx3 = (float)std::min(std::max(0, int(cxy.x + x3)), width - 1);
|
||||
float cy3 = (float)std::min(std::max(0, int(cxy.y + y3)), height - 1);
|
||||
// Convert from OpenGL to OpenCV space
|
||||
p0.y = src.rows - 1 - p0.y;
|
||||
px.y = src.rows - 1 - px.y;
|
||||
py.y = src.rows - 1 - py.y;
|
||||
pz.y = src.rows - 1 - pz.y;
|
||||
|
||||
cv::line(src, cv::Point((int)cxy.x, (int)cxy.y), cv::Point((int)cx1, (int)cy1), cv::Scalar(0, 0, 255), 2);
|
||||
cv::line(src, cv::Point((int)cxy.x, (int)cxy.y), cv::Point((int)cx2, (int)cy2), cv::Scalar(0, 255, 0), 2);
|
||||
cv::line(src, cv::Point((int)cxy.x, (int)cxy.y), cv::Point((int)cx3, (int)cy3), cv::Scalar(255, 0, 0), 2);
|
||||
cv::line(src, p0, px, CV_RGB(255, 0, 0), thickness);
|
||||
cv::line(src, p0, py, CV_RGB(0, 255, 0), thickness);
|
||||
cv::line(src, p0, pz, CV_RGB(0, 0, 255), thickness);
|
||||
}
|
||||
|
||||
NvCV_Status FaceEngine::findLandmarks() {
|
||||
@@ -618,6 +618,18 @@ NvAR_Point2f* FaceEngine::getLandmarks() { return facial_landmarks.data(); }
|
||||
|
||||
float* FaceEngine::getLandmarksConfidence() { return facial_landmarks_confidence.data(); }
|
||||
|
||||
std::array<float, 2> FaceEngine::GetAverageLandmarkPositionInGlSpace() const {
|
||||
std::array<float, 2> res = { 0.0f, 0.0f };
|
||||
for (const auto& landmark : facial_landmarks) {
|
||||
res[0] += landmark.x;
|
||||
res[1] += landmark.y;
|
||||
}
|
||||
res[0] /= facial_landmarks.size();
|
||||
res[1] /= facial_landmarks.size();
|
||||
res[1] = input_image_height - res[1]; //Convert y coordinate from CV to GL space
|
||||
return res;
|
||||
}
|
||||
|
||||
float FaceEngine::getAverageLandmarksConfidence() {
|
||||
float average_confidence = 0.0f;
|
||||
float* keypoints_landmarks_confidence = getLandmarksConfidence();
|
||||
@@ -686,13 +698,18 @@ void FaceEngine::setFaceStabilization(bool _bStabilizeFace) { bStabilizeFace = _
|
||||
|
||||
FaceEngine::Err FaceEngine::setNumLandmarks(int n) {
|
||||
FaceEngine::Err err = errNone;
|
||||
for (auto const& info : LANDMARKS_INFO) {
|
||||
#ifdef _WIN32 // Keep Updated Thresholds for Windows Only
|
||||
for (auto const& info : LANDMARKS_INFO)
|
||||
#else
|
||||
for (auto const& info : LANDMARKS_INFO_UNIX)
|
||||
#endif
|
||||
{
|
||||
if (n == info.numPoints) {
|
||||
numLandmarks = info.numPoints;
|
||||
confidenceThreshold = info.confidence_threshold;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
err = errGeneral;
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -110,8 +110,14 @@ class FaceEngine {
|
||||
enum Err { errNone, errGeneral, errRun, errInitialization, errRead, errEffect, errParameter };
|
||||
int input_image_width, input_image_height, input_image_pitch;
|
||||
const LandmarksProperties LANDMARKS_INFO[2] = {
|
||||
{ 68, 15.0f }, // number of landmark points, confidence threshold value
|
||||
{ 126, 15.0f}, //
|
||||
};
|
||||
|
||||
// Keep Older Confidence Threshold for Linux Models.
|
||||
const LandmarksProperties LANDMARKS_INFO_UNIX[2] = {
|
||||
{ 68, 10.0f }, // number of landmark points, confidence threshold value
|
||||
{ 126, 5.0f}
|
||||
{ 126, 5.0f}, //
|
||||
};
|
||||
|
||||
void setInputImageWidth(int width) { input_image_width = width; }
|
||||
@@ -121,9 +127,9 @@ class FaceEngine {
|
||||
int getInputImagePitch() { return input_image_pitch = input_image_width * 3 * sizeof(unsigned char); }
|
||||
void setFaceModel(const char *faceModel) { face_model = faceModel; }
|
||||
|
||||
Err createFeatures(const char* modelPath, unsigned int _batchSize = 1);
|
||||
Err createFeatures(const char* modelPath, unsigned int _batchSize = 1, unsigned int mode = 0);
|
||||
Err createFaceDetectionFeature(const char* modelPath, CUstream stream);
|
||||
Err createLandmarkDetectionFeature(const char* modelPath, unsigned int batchSize, CUstream stream);
|
||||
Err createLandmarkDetectionFeature(const char* modelPath, unsigned int batchSize, CUstream stream, unsigned int mode = 0);
|
||||
Err createFaceFittingFeature(const char* modelPath, CUstream stream);
|
||||
void destroyFeatures();
|
||||
void destroyFaceDetectionFeature();
|
||||
@@ -161,7 +167,8 @@ class FaceEngine {
|
||||
int getNumExpressionCoefficients();
|
||||
Err setNumLandmarks(int);
|
||||
int getNumLandmarks() { return numLandmarks; }
|
||||
void DrawPose(const cv::Mat& src, const NvAR_Quaternion* pose);
|
||||
void DrawPose(const cv::Mat& src, const NvAR_Quaternion* pose) const;
|
||||
std::array<float, 2> GetAverageLandmarkPositionInGlSpace() const;
|
||||
|
||||
NvCVImage inputImageBuffer{}, tmpImage{}, outputImageBuffer{};
|
||||
NvAR_FeatureHandle faceDetectHandle{}, landmarkDetectHandle{}, faceFitHandle{};
|
||||
@@ -169,6 +176,8 @@ class FaceEngine {
|
||||
std::vector<float> facial_landmarks_confidence;
|
||||
std::vector<NvAR_Quaternion> facial_pose;
|
||||
NvAR_FaceMesh* face_mesh{};
|
||||
std::vector<NvAR_Vector3f> m_vertices;
|
||||
std::vector<NvAR_Vector3u16> m_triangles;
|
||||
NvAR_RenderingParams* rendering_params{};
|
||||
std::vector<float> shapeEigenvalues, expressionCoefficients;
|
||||
CUstream stream{};
|
||||
@@ -180,7 +189,7 @@ class FaceEngine {
|
||||
int numLandmarks;
|
||||
float confidenceThreshold;
|
||||
std::string face_model;
|
||||
|
||||
|
||||
bool bStabilizeFace;
|
||||
bool bUseOTAU;
|
||||
char *fdOTAModelPath, *ldOTAModelPath;
|
||||
|
||||
@@ -38,6 +38,13 @@
|
||||
#include "nvAR_defs.h"
|
||||
#include "opencv2/opencv.hpp"
|
||||
|
||||
#if CV_MAJOR_VERSION >= 4
|
||||
#define CV_CAP_PROP_FRAME_WIDTH cv::CAP_PROP_FRAME_WIDTH
|
||||
#define CV_CAP_PROP_FRAME_HEIGHT cv::CAP_PROP_FRAME_HEIGHT
|
||||
#define CV_CAP_PROP_FPS cv::CAP_PROP_FPS
|
||||
#define CV_CAP_PROP_FRAME_COUNT cv::CAP_PROP_FRAME_COUNT
|
||||
#endif
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.1415926535897932385
|
||||
#endif /* M_PI */
|
||||
@@ -66,7 +73,7 @@
|
||||
********************************************************************************/
|
||||
|
||||
bool FLAG_debug = false, FLAG_verbose = false, FLAG_temporal = true, FLAG_captureOutputs = false,
|
||||
FLAG_offlineMode = false, FLAG_isNumLandmarks126 = false;
|
||||
FLAG_offlineMode = false, FLAG_isNumLandmarks126 = false; unsigned int FLAG_landmarkMode = 0;
|
||||
std::string FLAG_outDir, FLAG_inFile, FLAG_outFile, FLAG_modelPath, FLAG_landmarks, FLAG_proxyWireframe,
|
||||
FLAG_captureCodec = "avc1", FLAG_camRes, FLAG_faceModel;
|
||||
unsigned int FLAG_appMode = 2;
|
||||
@@ -93,7 +100,8 @@ static void Usage() {
|
||||
" --face_model=<file> specify the name of the face model\n"
|
||||
" --wireframe_mesh=<path> specify the path to a proxy wireframe mesh\n"
|
||||
" --app_mode[=(0|1|2)] App mode. 0: Face detection, 1: Landmark detection, 2: Face fitting "
|
||||
"(Default)."
|
||||
"(Default).\n"
|
||||
" --landmark_mode Select Landmark Detection Model. 0: Performance (Default), 1: Quality\n"
|
||||
" --benchmarks[=<pattern>] run benchmarks\n");
|
||||
}
|
||||
|
||||
@@ -197,7 +205,8 @@ static int ParseMyArgs(int argc, char **argv) {
|
||||
GetFlagArgVal("landmarks", arg, &FLAG_landmarks) || GetFlagArgVal("model_path", arg, &FLAG_modelPath) ||
|
||||
GetFlagArgVal("wireframe_mesh", arg, &FLAG_proxyWireframe) ||
|
||||
GetFlagArgVal("face_model", arg, &FLAG_faceModel) ||
|
||||
GetFlagArgVal("app_mode", arg, &FLAG_appMode) || GetFlagArgVal("temporal", arg, &FLAG_temporal))) {
|
||||
GetFlagArgVal("app_mode", arg, &FLAG_appMode) || GetFlagArgVal("temporal", arg, &FLAG_temporal) ||
|
||||
GetFlagArgVal("landmark_mode", arg, &FLAG_landmarkMode))) {
|
||||
continue;
|
||||
} else if (GetFlagArgVal("help", arg, &help)) {
|
||||
Usage();
|
||||
@@ -227,10 +236,11 @@ enum {
|
||||
#if 1
|
||||
class MyTimer {
|
||||
public:
|
||||
void start() { t0 = std::chrono::high_resolution_clock::now(); } /**< Start the timer. */
|
||||
void pause() { dt = std::chrono::high_resolution_clock::now() - t0; } /**< Pause the timer. */
|
||||
void resume() { t0 = std::chrono::high_resolution_clock::now() - dt; } /**< Resume the timer. */
|
||||
void stop() { pause(); } /**< Stop the timer. */
|
||||
MyTimer() { dt = dt.zero(); } /**< Clear the duration to 0. */
|
||||
void start() { t0 = std::chrono::high_resolution_clock::now(); } /**< Start the timer. */
|
||||
void pause() { dt = std::chrono::high_resolution_clock::now() - t0; } /**< Pause the timer. */
|
||||
void resume() { t0 = std::chrono::high_resolution_clock::now() - dt; } /**< Resume the timer. */
|
||||
void stop() { pause(); } /**< Stop the timer. */
|
||||
double elapsedTimeFloat() const {
|
||||
return std::chrono::duration<double>(dt).count();
|
||||
} /**< Report the elapsed time as a float. */
|
||||
@@ -297,7 +307,7 @@ class DoApp {
|
||||
~DoApp();
|
||||
|
||||
void stop();
|
||||
Err initFaceEngine(const char *modelPath = nullptr, bool isLandmarks126 = false);
|
||||
Err initFaceEngine(const char *modelPath = nullptr, bool isLandmarks126 = false, int mode = 0);
|
||||
Err initCamera(const char *camRes = nullptr);
|
||||
Err initOfflineMode(const char *inputFilename = nullptr, const char *outputFilename = nullptr);
|
||||
Err acquireFrame();
|
||||
@@ -327,6 +337,7 @@ class DoApp {
|
||||
int frameIndex;
|
||||
static const char windowTitle[];
|
||||
double frameTime;
|
||||
const int batchSize = 1;
|
||||
// std::chrono::high_resolution_clock::time_point frameTimer;
|
||||
MyTimer frameTimer;
|
||||
cv::VideoWriter capturedVideo;
|
||||
@@ -390,20 +401,21 @@ void DoApp::processKey(int key) {
|
||||
}
|
||||
}
|
||||
|
||||
DoApp::Err DoApp::initFaceEngine(const char *modelPath, bool isNumLandmarks126) {
|
||||
|
||||
DoApp::Err DoApp::initFaceEngine(const char *modelPath, bool isNumLandmarks126, int mode) {
|
||||
if (!cap.isOpened()) return errVideo;
|
||||
|
||||
int numLandmarkPoints = isNumLandmarks126 ? 126 : 68;
|
||||
face_ar_engine.setNumLandmarks(numLandmarkPoints);
|
||||
|
||||
nvErr = face_ar_engine.createFeatures(modelPath);
|
||||
nvErr = face_ar_engine.createFeatures(modelPath, batchSize, mode);
|
||||
if (nvErr != FaceEngine::Err::errNone) {
|
||||
if (nvErr == FaceEngine::Err::errInitialization && face_ar_engine.appMode == FaceEngine::mode::faceMeshGeneration) {
|
||||
showFaceFitErrorMessage();
|
||||
printf("WARNING: face fitting has failed, trying to initialize Landmark Detection\n");
|
||||
face_ar_engine.destroyFeatures();
|
||||
face_ar_engine.setAppMode(FaceEngine::mode::landmarkDetection);
|
||||
nvErr = face_ar_engine.createFeatures(modelPath);
|
||||
nvErr = face_ar_engine.createFeatures(modelPath, batchSize, mode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,7 +449,7 @@ void DoApp::stop() {
|
||||
|
||||
void DoApp::showFaceFitErrorMessage() {
|
||||
cv::Mat errBox = cv::Mat::zeros(120, 640, CV_8UC3);
|
||||
cv::putText(errBox, cv::String("Warning: Face Fitting needs face_model0.nvf in the path --model_path"), cv::Point(20, 20),
|
||||
cv::putText(errBox, cv::String("Warning: Face Fitting needs face_model2.nvf in the path --model_path"), cv::Point(20, 20),
|
||||
cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(255, 255, 255), 1);
|
||||
cv::putText(errBox, cv::String("or in NVAR_MODEL_DIR environment variable."), cv::Point(20, 40), cv::FONT_HERSHEY_SIMPLEX,
|
||||
0.5, cv::Scalar(255, 255, 255), 1);
|
||||
@@ -607,8 +619,8 @@ void DoApp::DrawFaceMesh(const cv::Mat &src, NvAR_FaceMesh *face_mesh) {
|
||||
NvAR_FaceMesh wfMesh{nullptr, 0, nullptr, 0};
|
||||
wfMesh.num_vertices = face_mesh->num_vertices;
|
||||
wfMesh.vertices = face_mesh->vertices;
|
||||
wfMesh.num_tri_idx = proxyWireframe.size();
|
||||
wfMesh_tvi_data.resize(wfMesh.num_tri_idx);
|
||||
wfMesh.num_triangles = proxyWireframe.size();
|
||||
wfMesh_tvi_data.resize(wfMesh.num_triangles);
|
||||
wfMesh.tvi = wfMesh_tvi_data.data();
|
||||
|
||||
for (int i = 0; i < proxyWireframe.size(); i++) {
|
||||
@@ -1088,7 +1100,12 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
BAIL_IF_ERR(doErr);
|
||||
|
||||
doErr = app.initFaceEngine(FLAG_modelPath.c_str(), FLAG_isNumLandmarks126);
|
||||
if ((FLAG_landmarkMode < 0) | (FLAG_landmarkMode > 1)){
|
||||
doErr = DoApp::errParameter;
|
||||
printf("ERROR: %s, Please Select Either Mode 0 or 1! \n", app.errorStringFromCode(doErr));
|
||||
}
|
||||
|
||||
doErr = app.initFaceEngine(FLAG_modelPath.c_str(), FLAG_isNumLandmarks126, FLAG_landmarkMode);
|
||||
BAIL_IF_ERR(doErr);
|
||||
|
||||
if (!FLAG_proxyWireframe.empty()) app.setProxyWireframe(FLAG_proxyWireframe.c_str());
|
||||
|
||||
Binary file not shown.
@@ -9,43 +9,4 @@ the keyboard
|
||||
2 - Facial landmark tracking
|
||||
3 - 3D mesh tracking
|
||||
|
||||
For more controls and configurations of the sample app, please read the SDK programming guide.
|
||||
|
||||
3D mesh tracking feature requires a 3D Morphable Face Model (3DMM).
|
||||
NVIDIA AR SDK does not include a 3DMM. Therefore, if you are using the 3D mesh tracking feature, you must configure NVIDIA AR SDK with 3DMM.
|
||||
Note: To configure NVIDIA AR SDK with 3DMM, you can use the Surrey Face Model, as described in the steps below, or your own model.
|
||||
The sample app can still be used in mode 1 and 2 without this file.
|
||||
|
||||
NVIDIA AR SDK provides the ConvertSurreyFaceModel.exe utility to convert 3DMM files to the NVIDIA .nvf format that is required by the SDK.
|
||||
To generate the face model file face_model0.nvf required for 3D mesh tracking:
|
||||
|
||||
1) Download the following Surrey Face Model files from the eos project page on Github:
|
||||
sfm_shape_3448.bin
|
||||
expression_blendshapes_3448.bin
|
||||
sfm_3448_edge_topology.json
|
||||
sfm_model_contours.json
|
||||
ibug_to_sfm.txt
|
||||
|
||||
2) Convert the files that you downloaded to the NVIDIA .nvf format.
|
||||
|
||||
tools\ConvertSurreyFaceModel.exe
|
||||
--shape=<path>/sfm_shape_3448.bin
|
||||
--blend_shape=<path>/expression_blendshapes_3448.bin
|
||||
--topology=<path>/sfm_3448_edge_topology.json
|
||||
--contours=<path>/sfm_model_contours.json
|
||||
--ibug=<path>/ibug_to_sfm.txt
|
||||
--out=<output-path>/face_model0.nvf
|
||||
|
||||
path
|
||||
The full or relative path to the folder that contains the Surrey Face Model files that you downloaded.
|
||||
Either the forward slash (/) or back slash (\) can be used as a separator between path elements.
|
||||
|
||||
output-path
|
||||
The full or relative path to the folder where you want the output .nvf format file to be written.
|
||||
Either the forward slash (/) or back slash (\) can be used as a separator between path elements.
|
||||
|
||||
The ConvertSurreyFaceModel.exe file is distributed in the https://github.com/nvidia/MAXINE-AR-SDK repo.
|
||||
|
||||
3) The sample application provided with NVIDIA AR SDK requires that the model file be named face_model0.nvf.
|
||||
Place the face_model0.nvf file in the model folder. By default the models folder is your_sdk_install_path/models
|
||||
where all models (including *.trtpkg files) are installed, for example: C:\Program Files\NVIDIA Corporation\NVIDIA AR SDK\models.
|
||||
For more controls and configurations of the sample app, please read the SDK programming guide.
|
||||
51
samples/GazeRedirect/CMakeLists.txt
Normal file
51
samples/GazeRedirect/CMakeLists.txt
Normal file
@@ -0,0 +1,51 @@
|
||||
set(SOURCE_FILES GazeEngine.cpp
|
||||
GazeRedirect.cpp
|
||||
../utils/RenderingUtils.cpp
|
||||
../utils/FeatureVertexName.cpp
|
||||
../utils/FeatureVertexName.h
|
||||
)
|
||||
set(HEADER_FILES GazeEngine.h )
|
||||
if(MSVC)
|
||||
set(SOURCE_FILES ${SOURCE_FILES} ../../nvar/src/nvARProxy.cpp ../../nvar/src/nvCVImageProxy.cpp)
|
||||
set(HEADER_FILES ${HEADER_FILES} ../utils/RenderingUtils.h)
|
||||
endif(MSVC)
|
||||
|
||||
# Set Visual Studio source filters
|
||||
source_group("Source Files" FILES ${SOURCE_FILES})
|
||||
source_group("Header Files" FILES ${HEADER_FILES})
|
||||
|
||||
add_executable(GazeRedirect ${SOURCE_FILES} ${HEADER_FILES})
|
||||
target_include_directories(GazeRedirect PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_include_directories(GazeRedirect PUBLIC
|
||||
${SDK_INCLUDES_PATH}
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
set(ARSDK_PATH_STR ${CMAKE_CURRENT_SOURCE_DIR}/../../bin)
|
||||
set(OPENCV_PATH_STR ${CMAKE_CURRENT_SOURCE_DIR}/../external/opencv/bin)
|
||||
set(PATH_STR "PATH=%PATH%" ${OPENCV_PATH_STR})
|
||||
set(CMD_ARG_STR "--model_path=\"${CMAKE_CURRENT_SOURCE_DIR}/../../bin/models\"")
|
||||
target_link_libraries (GazeRedirect PUBLIC
|
||||
${OPENGL_gl_LIBRARY}
|
||||
opencv346
|
||||
utils_sample
|
||||
)
|
||||
|
||||
set_target_properties(GazeRedirect PROPERTIES
|
||||
FOLDER SampleApps
|
||||
VS_DEBUGGER_ENVIRONMENT "${PATH_STR}"
|
||||
VS_DEBUGGER_COMMAND_ARGUMENTS "${CMD_ARG_STR}"
|
||||
)
|
||||
elseif(UNIX)
|
||||
find_package(PNG REQUIRED)
|
||||
find_package(JPEG REQUIRED)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
|
||||
target_link_libraries(GazeRedirect PUBLIC
|
||||
nvARPose
|
||||
NVCVImage
|
||||
OpenCV
|
||||
utils_sample
|
||||
)
|
||||
endif(MSVC)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive")
|
||||
453
samples/GazeRedirect/GazeEngine.cpp
Normal file
453
samples/GazeRedirect/GazeEngine.cpp
Normal file
@@ -0,0 +1,453 @@
|
||||
/*###############################################################################
|
||||
#
|
||||
# Copyright 2020 NVIDIA Corporation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
###############################################################################*/
|
||||
#include <iostream>
|
||||
#include "GazeEngine.h"
|
||||
#include "RenderingUtils.h"
|
||||
|
||||
bool CheckResult(NvCV_Status nvErr, unsigned line) {
|
||||
if (NVCV_SUCCESS == nvErr) return true;
|
||||
std::cout << "ERROR: " << NvCV_GetErrorStringFromCode(nvErr) << ", line " << line << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
GazeEngine::Err GazeEngine::acquireGazeRedirection(cv::Mat& frame, cv::Mat& outputFrame) {
|
||||
GazeEngine::Err err = GazeEngine::Err::errNone;
|
||||
NvCV_Status nvErr;
|
||||
if (!frame.empty()) {
|
||||
NvCVImage fxSrcChunkyCPU;
|
||||
(void)NVWrapperForCVMat(&frame, &fxSrcChunkyCPU);
|
||||
nvErr = NvCVImage_Transfer(&fxSrcChunkyCPU, &inputImageBuffer, 1.0f, stream, &tmpImage);
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errGeneral);
|
||||
}
|
||||
nvErr = NvAR_Run(gazeRedirectHandle);
|
||||
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errRun);
|
||||
|
||||
if (bGazeRedirect) {
|
||||
// Redirection is taking place. The feature has an output redirected image
|
||||
NvCVImage fxDstChunkyCPU;
|
||||
(void)NVWrapperForCVMat(&outputFrame, &fxDstChunkyCPU);
|
||||
nvErr = NvCVImage_Transfer(&outputImageBuffer, &fxDstChunkyCPU, 1.0f, stream, &tmpImage);
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errGeneral);
|
||||
} else {
|
||||
// Redirection is not taking place. There is no output image, therefore clone the input frame to output.
|
||||
outputFrame = frame.clone();
|
||||
}
|
||||
|
||||
if (getAverageLandmarksConfidence() < confidenceThreshold) return GazeEngine::Err::errRun;
|
||||
bail:
|
||||
if (err != Err::errNone) {
|
||||
printf("ERROR: An error has occured while running the Gaze Redirection \n");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
NvAR_RenderingParams* GazeEngine::getRenderingParams() { return rendering_params; }
|
||||
|
||||
GazeEngine::Err GazeEngine::createGazeRedirectionFeature(const char* modelPath, unsigned int batchsize) {
|
||||
GazeEngine::Err err = GazeEngine::Err::errNone;
|
||||
NvCV_Status cuErr = NvAR_CudaStreamCreate(&stream);
|
||||
|
||||
if (NVCV_SUCCESS != cuErr) {
|
||||
printf("Cannot create a cuda stream: %s\n", NvCV_GetErrorStringFromCode(cuErr));
|
||||
return errInitialization;
|
||||
}
|
||||
NvCV_Status nvErr;
|
||||
nvErr = NvAR_Create(NvAR_Feature_GazeRedirection, &gazeRedirectHandle);
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errEffect);
|
||||
if (bUseOTAU && (!modelPath || !modelPath[0])) {
|
||||
nvErr = NvAR_SetString(gazeRedirectHandle, NvAR_Parameter_Config(ModelDir), this->fdOTAModelPath);
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errParameter);
|
||||
} else {
|
||||
nvErr = NvAR_SetString(gazeRedirectHandle, NvAR_Parameter_Config(ModelDir), modelPath);
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errParameter);
|
||||
}
|
||||
nvErr = NvAR_SetU32(gazeRedirectHandle, NvAR_Parameter_Config(Landmarks_Size), numLandmarks); // TODO: Check if nonzero??
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errParameter);
|
||||
// Temporal flag set to -1 = 0xffffffff: turn on all filtering
|
||||
nvErr = NvAR_SetU32(gazeRedirectHandle, NvAR_Parameter_Config(Temporal), (bStabilizeFace ? -1 : 0));
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errParameter);
|
||||
nvErr = NvAR_SetU32(gazeRedirectHandle, NvAR_Parameter_Config(GazeRedirect), bGazeRedirect);
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errParameter);
|
||||
nvErr = NvAR_SetCudaStream(gazeRedirectHandle, NvAR_Parameter_Config(CUDAStream), stream);
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errParameter);
|
||||
nvErr = NvAR_SetU32(gazeRedirectHandle, NvAR_Parameter_Config(EyeSizeSensitivity), eyeSizeSensitivity);
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errParameter);
|
||||
nvErr = NvAR_Load(gazeRedirectHandle);
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errInitialization);
|
||||
bail:
|
||||
if (err != Err::errNone) {
|
||||
printf("ERROR: An error has occured while initializing Gaze Redirection\n");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
GazeEngine::Err GazeEngine::initGazeRedirectionIOParams() {
|
||||
GazeEngine::Err err = GazeEngine::Err::errNone;
|
||||
unsigned int OUTPUT_SIZE_KPTS, OUTPUT_GAZE_SIZE = 2, HEAD_TRANSLATION_SIZE = 3;
|
||||
|
||||
NvCV_Status nvErr = NvCVImage_Alloc(&inputImageBuffer, input_image_width, input_image_height, NVCV_BGR, NVCV_U8,
|
||||
NVCV_CHUNKY, NVCV_GPU, 1);
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errInitialization);
|
||||
nvErr = NvAR_SetObject(gazeRedirectHandle, NvAR_Parameter_Input(Image), &inputImageBuffer, sizeof(NvCVImage));
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errParameter);
|
||||
if (bGazeRedirect) {
|
||||
// Redirection is set. Allocate output image buffer.
|
||||
nvErr = NvCVImage_Alloc(&outputImageBuffer, input_image_width, input_image_height, NVCV_BGR, NVCV_U8, NVCV_CHUNKY,
|
||||
NVCV_GPU, 1);
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errInitialization);
|
||||
nvErr = NvAR_SetObject(gazeRedirectHandle, NvAR_Parameter_Output(Image), &outputImageBuffer, sizeof(NvCVImage));
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errParameter);
|
||||
}
|
||||
nvErr = NvAR_SetS32(gazeRedirectHandle, NvAR_Parameter_Input(Width), input_image_width);
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errParameter);
|
||||
|
||||
nvErr = NvAR_SetS32(gazeRedirectHandle, NvAR_Parameter_Input(Height), input_image_height);
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errParameter);
|
||||
|
||||
nvErr = NvAR_GetU32(gazeRedirectHandle, NvAR_Parameter_Config(Landmarks_Size), &OUTPUT_SIZE_KPTS);
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errParameter);
|
||||
|
||||
facial_landmarks.assign(batchSize * OUTPUT_SIZE_KPTS, {0.f, 0.f});
|
||||
nvErr = NvAR_SetObject(gazeRedirectHandle, NvAR_Parameter_Output(Landmarks), facial_landmarks.data(),
|
||||
sizeof(NvAR_Point2f));
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errParameter);
|
||||
|
||||
gaze_output_landmarks.assign(batchSize * num_output_landmarks , { 0.f, 0.f });
|
||||
nvErr = NvAR_SetObject(gazeRedirectHandle, NvAR_Parameter_Output(GazeOutputLandmarks), gaze_output_landmarks.data(),
|
||||
sizeof(NvAR_Point2f));
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errParameter);
|
||||
|
||||
facial_landmarks_confidence.assign(batchSize * OUTPUT_SIZE_KPTS, 0.f);
|
||||
nvErr = NvAR_SetF32Array(gazeRedirectHandle, NvAR_Parameter_Output(LandmarksConfidence),
|
||||
facial_landmarks_confidence.data(), batchSize * OUTPUT_SIZE_KPTS);
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errParameter);
|
||||
|
||||
nvErr = NvAR_SetF32Array(gazeRedirectHandle, NvAR_Parameter_Output(OutputGazeVector), gaze_angles_vector,
|
||||
batchSize * OUTPUT_GAZE_SIZE);
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errParameter);
|
||||
|
||||
nvErr = NvAR_SetF32Array(gazeRedirectHandle, NvAR_Parameter_Output(OutputHeadTranslation), head_translation,
|
||||
batchSize * HEAD_TRANSLATION_SIZE);
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errParameter);
|
||||
|
||||
nvErr = NvAR_SetObject(gazeRedirectHandle, NvAR_Parameter_Output(HeadPose), &head_pose, sizeof(NvAR_Quaternion));
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errParameter);
|
||||
|
||||
nvErr =
|
||||
NvAR_SetObject(gazeRedirectHandle, NvAR_Parameter_Output(GazeDirection), &gaze_direction, sizeof(NvAR_Point3f));
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errParameter);
|
||||
|
||||
output_bbox_data.assign(batchSize, {0.f, 0.f, 0.f, 0.f});
|
||||
output_bboxes.boxes = output_bbox_data.data();
|
||||
output_bboxes.max_boxes = (uint8_t)batchSize;
|
||||
output_bboxes.num_boxes = (uint8_t)batchSize;
|
||||
nvErr = NvAR_SetObject(gazeRedirectHandle, NvAR_Parameter_Output(BoundingBoxes), &output_bboxes, sizeof(NvAR_BBoxes));
|
||||
BAIL_IF_NVERR(nvErr, err, GazeEngine::Err::errParameter);
|
||||
|
||||
bail:
|
||||
if (err != Err::errNone) {
|
||||
printf("ERROR: An error has occured while setting input, output parmeters for Gaze Redirection\n");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
void GazeEngine::destroyGazeRedirectionFeature() {
|
||||
if (stream) {
|
||||
NvAR_CudaStreamDestroy(stream);
|
||||
stream = 0;
|
||||
}
|
||||
output_bbox_data.clear();
|
||||
facial_landmarks.clear();
|
||||
facial_landmarks_confidence.clear();
|
||||
NvCVImage_Dealloc(&inputImageBuffer);
|
||||
NvCVImage_Dealloc(&outputImageBuffer);
|
||||
if (rendering_params) {
|
||||
delete rendering_params;
|
||||
rendering_params = nullptr;
|
||||
}
|
||||
if (gazeRedirectHandle) {
|
||||
(void)NvAR_Destroy(gazeRedirectHandle);
|
||||
gazeRedirectHandle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned GazeEngine::findFaceBoxes() {
|
||||
NvCV_Status nvErr = NvAR_Run(faceDetectHandle);
|
||||
if (NVCV_SUCCESS != nvErr) return 0;
|
||||
return (unsigned)output_bboxes.num_boxes;
|
||||
}
|
||||
|
||||
NvAR_Rect* GazeEngine::getLargestBox() {
|
||||
NvAR_Rect *box, *bigBox, *lastBox;
|
||||
float maxArea, area;
|
||||
for (lastBox = (box = &output_bboxes.boxes[0]) + output_bboxes.num_boxes, bigBox = nullptr, maxArea = 0;
|
||||
box != lastBox; ++box) {
|
||||
if (maxArea < (area = box->width * box->height)) {
|
||||
maxArea = area;
|
||||
bigBox = box;
|
||||
}
|
||||
}
|
||||
return bigBox;
|
||||
}
|
||||
|
||||
NvAR_BBoxes* GazeEngine::getBoundingBoxes() { return &output_bboxes; }
|
||||
|
||||
void GazeEngine::enlargeAndSquarifyImageBox(float enlarge, NvAR_Rect& box, int FLAG_variant) {
|
||||
NvAR_Vector2f size = {box.width * .5f, box.height * .5f};
|
||||
NvAR_Point2f center = {box.x + size.x, box.y + size.y};
|
||||
float t;
|
||||
|
||||
size.x *= (1.f + enlarge);
|
||||
size.y *= (1.f + enlarge);
|
||||
|
||||
if (!(FLAG_variant & 1)) /* Default: enforce square bounding box */
|
||||
{
|
||||
if (size.x < size.y) /* Make square */
|
||||
size.x = size.y;
|
||||
else
|
||||
size.y = size.x;
|
||||
}
|
||||
|
||||
if (center.x < size.x) /* Shift box into image left-right */
|
||||
center.x = size.x;
|
||||
else if (center.x > (t = input_image_width - size.x))
|
||||
center.x = t;
|
||||
|
||||
if (center.y < size.y) /* Shift box into image up-down */
|
||||
center.y = size.y;
|
||||
else if (center.y > (t = input_image_height - size.y))
|
||||
center.y = t;
|
||||
|
||||
// TODO: Above we assume that the box is smaller than the image.
|
||||
|
||||
box.width = roundf(size.x * 2.f); /* Integral box */
|
||||
box.height = roundf(size.y * 2.f);
|
||||
box.x = roundf(center.x - box.width * .5f);
|
||||
box.y = roundf(center.y - box.height * .5f);
|
||||
}
|
||||
|
||||
void GazeEngine::DrawPose(const cv::Mat& src, const NvAR_Quaternion* pose) const {
|
||||
const float vector_scale = 50.0f;
|
||||
const int thickness = 2;
|
||||
float rot_mat[3][3];
|
||||
set_rotation_from_quaternion(pose, rot_mat[0]);
|
||||
const auto avg_landmark_pos = GetAverageLandmarkPositionInGlSpace();
|
||||
|
||||
cv::Point p0 = {static_cast<int>(avg_landmark_pos[0]), static_cast<int>(avg_landmark_pos[1])};
|
||||
cv::Point px = p0 + cv::Point(std::lround(rot_mat[0][0] * vector_scale), std::lround(rot_mat[0][1] * vector_scale));
|
||||
cv::Point py = p0 + cv::Point(std::lround(rot_mat[1][0] * vector_scale), std::lround(rot_mat[1][1] * vector_scale));
|
||||
cv::Point pz = p0 + cv::Point(std::lround(rot_mat[2][0] * vector_scale), std::lround(rot_mat[2][1] * vector_scale));
|
||||
|
||||
// Convert from OpenGL to OpenCV space
|
||||
p0.y = src.rows - 1 - p0.y;
|
||||
px.y = src.rows - 1 - px.y;
|
||||
py.y = src.rows - 1 - py.y;
|
||||
pz.y = src.rows - 1 - pz.y;
|
||||
|
||||
cv::line(src, p0, px, CV_RGB(255, 0, 0), thickness);
|
||||
cv::line(src, p0, py, CV_RGB(0, 255, 0), thickness);
|
||||
cv::line(src, p0, pz, CV_RGB(0, 0, 255), thickness);
|
||||
}
|
||||
|
||||
std::array<float, 2> GazeEngine::GetAverageLandmarkPositionInGlSpace() const{
|
||||
std::array<float, 2> res = { 0.0f, 0.0f };
|
||||
for (const auto& landmark : facial_landmarks) {
|
||||
res[0] += landmark.x;
|
||||
res[1] += landmark.y;
|
||||
}
|
||||
res[0] /= facial_landmarks.size();
|
||||
res[1] /= facial_landmarks.size();
|
||||
res[1] = input_image_height - res[1]; //Convert y coordinate from CV to GL space
|
||||
return res;
|
||||
}
|
||||
|
||||
void GazeEngine::DrawEstimatedGaze(const cv::Mat& src) {
|
||||
// Get the largest bounding box of the face.
|
||||
NvAR_Rect* pFaceBox = getLargestBox();
|
||||
|
||||
std::vector<cv::Point3f> gaze_direction_3d;
|
||||
const float distance = 50;
|
||||
// Create opencv Point3f objects from direction points
|
||||
cv::Point3f gaze_direction_origin(gaze_direction[0].x, gaze_direction[0].y, gaze_direction[0].z);
|
||||
cv::Point3f gaze_direction_target;
|
||||
// Compute target point at a fixed distance from the gaze origin in the estimated gaze direction.
|
||||
gaze_direction_target.x = gaze_direction[0].x + distance * gaze_direction[1].x;
|
||||
gaze_direction_target.y = gaze_direction[0].y - distance * gaze_direction[1].y;
|
||||
gaze_direction_target.z = gaze_direction[0].z - distance * gaze_direction[1].z;
|
||||
|
||||
// Compute 2D projections of the origin and target.
|
||||
gaze_direction_3d.push_back(gaze_direction_origin);
|
||||
gaze_direction_3d.push_back(gaze_direction_target);
|
||||
|
||||
// Intialize camera matrix and coefficiennts for projecting into the image plane.
|
||||
float fx = (float)src.cols, fy = (float)src.cols, cx = (float)src.cols / 2.f, cy = (float) src.rows / 2.f;
|
||||
float camera_data[9] = {fx, 0.f, cx, 0.f, fy, cy, 0.f, 0.f, 1.f};
|
||||
cv::Mat cam_matrix(3, 3, CV_32F, camera_data);
|
||||
cv::Mat distCoeffs(5, 1, cv::DataType<double>::type); // Distortion vector
|
||||
distCoeffs.at<double>(0) = 0;
|
||||
distCoeffs.at<double>(1) = 0;
|
||||
distCoeffs.at<double>(2) = 0;
|
||||
distCoeffs.at<double>(3) = 0;
|
||||
distCoeffs.at<double>(4) = 0;
|
||||
|
||||
cv::Mat rVec(3, 1, cv::DataType<double>::type); // Rotation vector
|
||||
rVec.at<double>(0) = 0;
|
||||
rVec.at<double>(1) = 0;
|
||||
rVec.at<double>(2) = 0;
|
||||
|
||||
cv::Mat tVec(3, 1, cv::DataType<double>::type); // Translation vector
|
||||
tVec.at<double>(0) = 0;
|
||||
tVec.at<double>(1) = 0;
|
||||
tVec.at<double>(2) = 0;
|
||||
|
||||
std::vector<cv::Point2f> gaze_direction_2d;
|
||||
cv::projectPoints(gaze_direction_3d, rVec, tVec, cam_matrix, distCoeffs, gaze_direction_2d);
|
||||
|
||||
// Plot the original and target points on the image plane.
|
||||
cv::line(src,
|
||||
cv::Point((int)(gaze_direction_2d[0].x),
|
||||
(int)(gaze_direction_2d[0].y)),
|
||||
cv::Point((int)(gaze_direction_2d[1].x),
|
||||
(int)(gaze_direction_2d[1].y)),
|
||||
cv::Scalar(0, 0, 255), 2);
|
||||
}
|
||||
|
||||
NvCV_Status GazeEngine::findLandmarks() {
|
||||
NvCV_Status nvErr;
|
||||
|
||||
nvErr = NvAR_Run(landmarkDetectHandle);
|
||||
if (NVCV_SUCCESS != nvErr) {
|
||||
return nvErr;
|
||||
}
|
||||
|
||||
if (getAverageLandmarksConfidence() < confidenceThreshold) {
|
||||
return NVCV_ERR_GENERAL;
|
||||
} else {
|
||||
average_poses(getPose(), batchSize);
|
||||
NvAR_Point2f *pt, *endPt;
|
||||
int i = 0;
|
||||
for (endPt = (pt = getLandmarks()) + numLandmarks; pt != endPt; ++pt, i += 2) {
|
||||
for (int j = 1; j < batchSize; j++) {
|
||||
pt->x += pt[j * numLandmarks].x;
|
||||
pt->y += pt[j * numLandmarks].y;
|
||||
}
|
||||
// average batch of inferences to generate final result landmark points
|
||||
pt->x /= batchSize;
|
||||
pt->y /= batchSize;
|
||||
}
|
||||
}
|
||||
return NVCV_SUCCESS;
|
||||
}
|
||||
|
||||
NvAR_Point2f* GazeEngine::getLandmarks() { return facial_landmarks.data(); }
|
||||
|
||||
NvAR_Point2f* GazeEngine::getGazeOutputLandmarks() { return gaze_output_landmarks.data(); }
|
||||
|
||||
NvAR_Point3f* GazeEngine::getGazeDirectionPoints() { return gaze_direction; }
|
||||
|
||||
float* GazeEngine::getLandmarksConfidence() { return facial_landmarks_confidence.data(); }
|
||||
|
||||
float GazeEngine::getAverageLandmarksConfidence() {
|
||||
float average_confidence = 0.0f;
|
||||
float* keypoints_landmarks_confidence = getLandmarksConfidence();
|
||||
for (int i = 0; i < batchSize * numLandmarks; i++) {
|
||||
average_confidence += keypoints_landmarks_confidence[i];
|
||||
}
|
||||
average_confidence /= batchSize * numLandmarks;
|
||||
return average_confidence;
|
||||
}
|
||||
|
||||
NvAR_Quaternion* GazeEngine::getPose() { return &head_pose; }
|
||||
float* GazeEngine::getHeadTranslation() { return head_translation; }
|
||||
float* GazeEngine::getGazeVector() { return gaze_angles_vector; }
|
||||
|
||||
unsigned GazeEngine::findLargestFaceBox(NvAR_Rect& faceBox, int variant) {
|
||||
unsigned n;
|
||||
NvAR_Rect* pFaceBox;
|
||||
|
||||
n = findFaceBoxes();
|
||||
if (n >= 1) {
|
||||
pFaceBox = getLargestBox();
|
||||
if (nullptr == pFaceBox) {
|
||||
faceBox.x = faceBox.y = faceBox.width = faceBox.height = 0.0f;
|
||||
} else {
|
||||
faceBox = *pFaceBox;
|
||||
}
|
||||
enlargeAndSquarifyImageBox(.2f, faceBox, variant);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
unsigned GazeEngine::acquireFaceBox(cv::Mat& src, NvAR_Rect& faceBox, int variant) {
|
||||
unsigned n = 0;
|
||||
NvCVImage fxSrcChunkyCPU;
|
||||
(void)NVWrapperForCVMat(&src, &fxSrcChunkyCPU);
|
||||
NvCV_Status cvErr = NvCVImage_Transfer(&fxSrcChunkyCPU, &inputImageBuffer, 1.0f, stream, &tmpImage);
|
||||
|
||||
if (NVCV_SUCCESS != cvErr) {
|
||||
return n;
|
||||
}
|
||||
|
||||
n = findLargestFaceBox(faceBox, variant);
|
||||
return n;
|
||||
}
|
||||
|
||||
unsigned GazeEngine::acquireFaceBoxAndLandmarks(cv::Mat& src, NvAR_Point2f* refMarks, NvAR_Rect& faceBox) {
|
||||
unsigned n = 0;
|
||||
NvCVImage fxSrcChunkyCPU;
|
||||
(void)NVWrapperForCVMat(&src, &fxSrcChunkyCPU);
|
||||
NvCV_Status cvErr = NvCVImage_Transfer(&fxSrcChunkyCPU, &inputImageBuffer, 1.0f, stream, &tmpImage);
|
||||
|
||||
if (NVCV_SUCCESS != cvErr) {
|
||||
return n;
|
||||
}
|
||||
|
||||
if (findLandmarks() != NVCV_SUCCESS) return 0;
|
||||
faceBox = output_bboxes.boxes[0];
|
||||
n = 1;
|
||||
memcpy(refMarks, getLandmarks(), sizeof(NvAR_Point2f) * numLandmarks);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void GazeEngine::setFaceStabilization(bool _bStabilizeFace) { bStabilizeFace = _bStabilizeFace; }
|
||||
void GazeEngine::setGazeRedirect(bool _bGazeRedirect) {
|
||||
// If this variable is set, gaze redirection occurs in addition to estimation.
|
||||
bGazeRedirect = _bGazeRedirect;
|
||||
}
|
||||
|
||||
GazeEngine::Err GazeEngine::setNumLandmarks(int n) {
|
||||
GazeEngine::Err err = errNone;
|
||||
for (auto const& info : LANDMARKS_INFO) {
|
||||
if (n == info.numPoints) {
|
||||
numLandmarks = info.numPoints;
|
||||
confidenceThreshold = info.confidence_threshold;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
err = errGeneral;
|
||||
return err;
|
||||
}
|
||||
|
||||
void GazeEngine::setEyeSizeSensitivity(unsigned _eyeSizeSensitivity) { eyeSizeSensitivity = _eyeSizeSensitivity; }
|
||||
205
samples/GazeRedirect/GazeEngine.h
Normal file
205
samples/GazeRedirect/GazeEngine.h
Normal file
@@ -0,0 +1,205 @@
|
||||
/*###############################################################################
|
||||
#
|
||||
# Copyright 2020 NVIDIA Corporation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
###############################################################################*/
|
||||
#ifndef __GAZE_ENGINE__
|
||||
#define __GAZE_ENGINE__
|
||||
|
||||
#include <random>
|
||||
#include "FeatureVertexName.h"
|
||||
#include "nvAR.h"
|
||||
#include "nvCVOpenCV.h"
|
||||
|
||||
class KalmanFilter1D {
|
||||
private:
|
||||
float Q_; // Covariance of the process noise
|
||||
float xhat_; // Current prediction
|
||||
float xhatminus_; // Previous prediction
|
||||
float P_; // Estimated accuracy of xhat_
|
||||
float Pminus_; // Previous P_
|
||||
float K_; // Kalman gain
|
||||
float R_; // Covariance of the observation noise
|
||||
bool bFirstUse;
|
||||
|
||||
public:
|
||||
KalmanFilter1D() { reset(); }
|
||||
|
||||
KalmanFilter1D(float Q, float R) { reset(Q, R); }
|
||||
|
||||
void reset() {
|
||||
R_ = 0.005f * 0.005f;
|
||||
Q_ = 1e-5f;
|
||||
xhat_ = 0.0f;
|
||||
xhatminus_ = 0.0f;
|
||||
P_ = 1;
|
||||
bFirstUse = true;
|
||||
Pminus_ = 0.0f;
|
||||
K_ = 0.0f;
|
||||
}
|
||||
|
||||
void reset(float Q, float R) {
|
||||
reset();
|
||||
Q_ = Q;
|
||||
R_ = R;
|
||||
}
|
||||
|
||||
float update(float val) {
|
||||
if (bFirstUse) {
|
||||
xhat_ = val;
|
||||
bFirstUse = false;
|
||||
}
|
||||
|
||||
xhatminus_ = xhat_;
|
||||
Pminus_ = P_ + Q_;
|
||||
K_ = Pminus_ / (Pminus_ + R_);
|
||||
xhat_ = xhatminus_ + K_ * (val - xhatminus_);
|
||||
P_ = (1 - K_) * Pminus_;
|
||||
|
||||
return xhat_;
|
||||
}
|
||||
};
|
||||
|
||||
bool CheckResult(NvCV_Status nvErr, unsigned line);
|
||||
|
||||
#define BAIL_IF_ERR(err) \
|
||||
do { \
|
||||
if (0 != (err)) { \
|
||||
goto bail; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BAIL_IF_NVERR(nvErr, err, code) \
|
||||
do { \
|
||||
if (!CheckResult(nvErr, __LINE__)) { \
|
||||
err = code; \
|
||||
goto bail; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
typedef struct LandmarksProperties {
|
||||
int numPoints;
|
||||
float confidence_threshold;
|
||||
} LandmarksProperties;
|
||||
|
||||
/********************************************************************************
|
||||
* GazeEngine
|
||||
********************************************************************************/
|
||||
|
||||
class GazeEngine {
|
||||
public:
|
||||
enum Err { errNone, errGeneral, errRun, errInitialization, errRead, errEffect, errParameter };
|
||||
int input_image_width, input_image_height, input_image_pitch;
|
||||
const LandmarksProperties LANDMARKS_INFO[2] = {{68, 15.0f}, // number of landmark points, confidence threshold value
|
||||
{126, 5.0f}};
|
||||
|
||||
void setInputImageWidth(int width) { input_image_width = width; }
|
||||
void setInputImageHeight(int height) { input_image_height = height; }
|
||||
|
||||
Err createGazeRedirectionFeature(const char* modelPath, unsigned int _batchSize = 1);
|
||||
void destroyGazeRedirectionFeature();
|
||||
Err initGazeRedirectionIOParams();
|
||||
|
||||
unsigned findFaceBoxes();
|
||||
NvAR_Rect* getLargestBox();
|
||||
NvCV_Status findLandmarks();
|
||||
NvAR_BBoxes* getBoundingBoxes();
|
||||
|
||||
/**
|
||||
* Landmarks corresponding to facial keypoints
|
||||
*
|
||||
* @returns Pointer to the landmarks array
|
||||
*/
|
||||
NvAR_Point2f* getLandmarks();
|
||||
|
||||
/**
|
||||
* Output landmarks corresponding to the redirected eyes from the gaze redirection network
|
||||
*
|
||||
* @returns Pointer to the landmarks array
|
||||
*/
|
||||
NvAR_Point2f* getGazeOutputLandmarks();
|
||||
|
||||
NvAR_Quaternion* getPose();
|
||||
float* getHeadTranslation();
|
||||
float* getGazeVector();
|
||||
float* getLandmarksConfidence();
|
||||
float getAverageLandmarksConfidence();
|
||||
void enlargeAndSquarifyImageBox(float enlarge, NvAR_Rect& box, int FLAG_variant);
|
||||
unsigned findLargestFaceBox(NvAR_Rect& faceBox, int variant = 0);
|
||||
unsigned acquireFaceBox(cv::Mat& src, NvAR_Rect& faceBox, int variant = 0);
|
||||
unsigned acquireFaceBoxAndLandmarks(cv::Mat& src, NvAR_Point2f* refMarks, NvAR_Rect& faceBox);
|
||||
Err acquireGazeRedirection(cv::Mat& frame, cv::Mat& outputFrame);
|
||||
NvAR_RenderingParams* getRenderingParams();
|
||||
void setFaceStabilization(bool);
|
||||
Err setNumLandmarks(int);
|
||||
void setGazeRedirect(bool _bGazeRedirect);
|
||||
void setEyeSizeSensitivity(unsigned);
|
||||
int getNumLandmarks() { return numLandmarks; }
|
||||
int getNumGazeOutputLandmarks() { return num_output_landmarks; }
|
||||
void DrawPose(const cv::Mat& src, const NvAR_Quaternion* pose) const;
|
||||
std::array<float, 2> GetAverageLandmarkPositionInGlSpace() const;
|
||||
void DrawEstimatedGaze(const cv::Mat& src);
|
||||
NvAR_Point3f* getGazeDirectionPoints();
|
||||
|
||||
NvCVImage inputImageBuffer{}, tmpImage{}, outputImageBuffer{};
|
||||
|
||||
NvAR_FeatureHandle faceDetectHandle{}, landmarkDetectHandle{}, gazeRedirectHandle{};
|
||||
std::vector<NvAR_Point2f> facial_landmarks;
|
||||
std::vector<NvAR_Point2f> gaze_output_landmarks;
|
||||
std::vector<float> facial_landmarks_confidence;
|
||||
NvAR_Point3f gaze_direction[2] = {{0.f, 0.f, 0.f}};
|
||||
NvAR_Quaternion head_pose;
|
||||
float gaze_angles_vector[2] = {0.f};
|
||||
float head_translation[3] = {0.f};
|
||||
NvAR_RenderingParams* rendering_params{};
|
||||
CUstream stream{};
|
||||
std::vector<NvAR_Rect> output_bbox_data;
|
||||
std::vector<float> output_bbox_conf_data;
|
||||
NvAR_BBoxes output_bboxes{};
|
||||
int batchSize;
|
||||
std::mt19937 ran;
|
||||
int numLandmarks;
|
||||
int num_output_landmarks;
|
||||
int eyeSizeSensitivity;
|
||||
float confidenceThreshold;
|
||||
std::string face_model;
|
||||
|
||||
bool bStabilizeFace;
|
||||
bool bUseOTAU;
|
||||
bool bGazeRedirect;
|
||||
char *fdOTAModelPath, *ldOTAModelPath;
|
||||
|
||||
GazeEngine() {
|
||||
batchSize = 1;
|
||||
bStabilizeFace = true;
|
||||
bGazeRedirect = true;
|
||||
numLandmarks = LANDMARKS_INFO[0].numPoints;
|
||||
num_output_landmarks = 12;
|
||||
confidenceThreshold = LANDMARKS_INFO[0].confidence_threshold;
|
||||
input_image_width = 640;
|
||||
input_image_height = 480;
|
||||
input_image_pitch = 3 * input_image_width * sizeof(unsigned char); // RGB
|
||||
bUseOTAU = false;
|
||||
fdOTAModelPath = NULL;
|
||||
ldOTAModelPath = NULL;
|
||||
eyeSizeSensitivity = 3;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
858
samples/GazeRedirect/GazeRedirect.cpp
Normal file
858
samples/GazeRedirect/GazeRedirect.cpp
Normal file
@@ -0,0 +1,858 @@
|
||||
/*###############################################################################
|
||||
#
|
||||
# Copyright 2020 NVIDIA Corporation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
# this software and associated documentation files (the "Software"), to deal in
|
||||
# the Software without restriction, including without limitation the rights to
|
||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
# the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
###############################################################################*/
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <fstream>
|
||||
|
||||
#include "GazeEngine.h"
|
||||
#include "RenderingUtils.h"
|
||||
#include "nvAR.h"
|
||||
#include "nvAR_defs.h"
|
||||
#include "opencv2/opencv.hpp"
|
||||
|
||||
#if CV_MAJOR_VERSION >= 4
|
||||
#define CV_CAP_PROP_FRAME_WIDTH cv::CAP_PROP_FRAME_WIDTH
|
||||
#define CV_CAP_PROP_FRAME_HEIGHT cv::CAP_PROP_FRAME_HEIGHT
|
||||
#define CV_CAP_PROP_FPS cv::CAP_PROP_FPS
|
||||
#define CV_CAP_PROP_FRAME_COUNT cv::CAP_PROP_FRAME_COUNT
|
||||
#endif
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.1415926535897932385
|
||||
#endif /* M_PI */
|
||||
#ifndef M_2PI
|
||||
#define M_2PI 6.2831853071795864769
|
||||
#endif /* M_2PI */
|
||||
#ifndef M_PI_2
|
||||
#define M_PI_2 1.5707963267948966192
|
||||
#endif /* M_PI_2 */
|
||||
#define F_PI ((float)M_PI)
|
||||
#define F_PI_2 ((float)M_PI_2)
|
||||
#define F_2PI ((float)M_2PI)
|
||||
#define DEGREES_PER_RADIAN (180.0 / M_PI)
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define strcasecmp _stricmp
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#define BAIL(err, code) \
|
||||
do { \
|
||||
err = code; \
|
||||
goto bail; \
|
||||
} while (0)
|
||||
|
||||
/********************************************************************************
|
||||
* Command-line arguments
|
||||
********************************************************************************/
|
||||
|
||||
bool FLAG_debug = false, FLAG_verbose = false, FLAG_temporal = true, FLAG_captureOutputs = false,
|
||||
FLAG_drawVisualization = true, FLAG_offlineMode = false, FLAG_isNumLandmarks126 = false,
|
||||
FLAG_splitScreenView = true, FLAG_displayLandmarks = false, FLAG_gazeRedirect=true;
|
||||
std::string FLAG_outDir, FLAG_inFile, FLAG_outFile, FLAG_modelPath, FLAG_landmarks, FLAG_captureCodec = "avc1",
|
||||
FLAG_camRes = "480";
|
||||
unsigned FLAG_camID = 0;
|
||||
unsigned FLAG_eyeSizeSensitivity = 3;
|
||||
|
||||
/********************************************************************************
|
||||
* Usage
|
||||
********************************************************************************/
|
||||
|
||||
static void Usage() {
|
||||
printf(
|
||||
"GazeRedirect [<args> ...]\n"
|
||||
"where <args> is\n"
|
||||
" --verbose[=(true|false)] report interesting info\n"
|
||||
" --debug[=(true|false)] report debugging info\n"
|
||||
" --temporal[=(true|false)] temporally optimize face rect and landmarks\n"
|
||||
" --capture_outputs[=(true|false)] enables video/image capture and writing face detection/landmark outputs\n"
|
||||
" --offline_mode[=(true|false)] disables webcam, reads video from file and writes output video results\n"
|
||||
" --cam_res=[WWWx]HHH specify resolution as height or width x height\n"
|
||||
" --cam_id=<id> by default 0, specify int ID of camera in case of multiple cameras \n"
|
||||
" --codec=<fourcc> FOURCC code for the desired codec (default H264)\n"
|
||||
" --in=<file> specify the input file\n"
|
||||
" --out=<file> specify the output file\n"
|
||||
" --model_path=<path> specify the directory containing the TRT models\n"
|
||||
" --landmarks_126[=(true|false)] set the number of facial landmark points to 126, otherwise default to 68\n"
|
||||
" --eyesize_sensitivity set the eye size sensitivity parameter, an integer value between 2 and 6 (default 3)\n"
|
||||
" --split_screen_view split the screen to view original image side-by-side with the gaze redirected image, default to split. \n"
|
||||
" --draw_visualization draw the landmarks, display gaze estimation and head rotation, default to true\n"
|
||||
" --redirect_gaze redirection of the eyes in addition to estimating gaze, default to true\n"
|
||||
"(Default)."
|
||||
" --benchmarks[=<pattern>] run benchmarks\n");
|
||||
}
|
||||
|
||||
static bool GetFlagArgVal(const char *flag, const char *arg, const char **val) {
|
||||
if (*arg != '-') {
|
||||
return false;
|
||||
}
|
||||
while (*++arg == '-') {
|
||||
continue;
|
||||
}
|
||||
const char *s = strchr(arg, '=');
|
||||
if (s == NULL) {
|
||||
if (strcmp(flag, arg) != 0) {
|
||||
return false;
|
||||
}
|
||||
*val = NULL;
|
||||
return true;
|
||||
}
|
||||
unsigned n = (unsigned)(s - arg);
|
||||
if ((strlen(flag) != n) || (strncmp(flag, arg, n) != 0)) {
|
||||
return false;
|
||||
}
|
||||
*val = s + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool GetFlagArgVal(const char *flag, const char *arg, std::string *val) {
|
||||
const char *valStr;
|
||||
if (!GetFlagArgVal(flag, arg, &valStr)) return false;
|
||||
val->assign(valStr ? valStr : "");
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool GetFlagArgVal(const char *flag, const char *arg, bool *val) {
|
||||
const char *valStr;
|
||||
bool success = GetFlagArgVal(flag, arg, &valStr);
|
||||
if (success) {
|
||||
*val = (valStr == NULL || strcasecmp(valStr, "true") == 0 || strcasecmp(valStr, "on") == 0 ||
|
||||
strcasecmp(valStr, "yes") == 0 || strcasecmp(valStr, "1") == 0);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool GetFlagArgVal(const char *flag, const char *arg, long *val) {
|
||||
const char *valStr;
|
||||
bool success = GetFlagArgVal(flag, arg, &valStr);
|
||||
if (success) {
|
||||
*val = strtol(valStr, NULL, 10);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool GetFlagArgVal(const char *flag, const char *arg, unsigned *val) {
|
||||
long longVal;
|
||||
bool success = GetFlagArgVal(flag, arg, &longVal);
|
||||
if (success) {
|
||||
*val = (unsigned)longVal;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
* StringToFourcc
|
||||
********************************************************************************/
|
||||
|
||||
static int StringToFourcc(const std::string &str) {
|
||||
union chint {
|
||||
int i;
|
||||
char c[4];
|
||||
};
|
||||
chint x = {0};
|
||||
for (int n = (str.size() < 4) ? (int)str.size() : 4; n--;) x.c[n] = str[n];
|
||||
return x.i;
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
* ParseMyArgs
|
||||
********************************************************************************/
|
||||
|
||||
static int ParseMyArgs(int argc, char **argv) {
|
||||
// query NVAR_MODEL_DIR environment variable first before checking the command line arguments
|
||||
const char *modelPath = getenv("NVAR_MODEL_DIR");
|
||||
if (modelPath) {
|
||||
FLAG_modelPath = modelPath;
|
||||
}
|
||||
|
||||
int errs = 0;
|
||||
for (--argc, ++argv; argc--; ++argv) {
|
||||
bool help;
|
||||
const char *arg = *argv;
|
||||
if (arg[0] != '-') {
|
||||
continue;
|
||||
} else if ((arg[1] == '-') &&
|
||||
(GetFlagArgVal("verbose", arg, &FLAG_verbose) || GetFlagArgVal("debug", arg, &FLAG_debug) ||
|
||||
GetFlagArgVal("in", arg, &FLAG_inFile) || GetFlagArgVal("out", arg, &FLAG_outFile) ||
|
||||
GetFlagArgVal("offline_mode", arg, &FLAG_offlineMode) ||
|
||||
GetFlagArgVal("landmarks_126", arg, &FLAG_isNumLandmarks126) ||
|
||||
GetFlagArgVal("capture_outputs", arg, &FLAG_captureOutputs) ||
|
||||
GetFlagArgVal("cam_res", arg, &FLAG_camRes) || GetFlagArgVal("codec", arg, &FLAG_captureCodec) ||
|
||||
GetFlagArgVal("cam_id", arg, &FLAG_camID) ||
|
||||
GetFlagArgVal("landmarks", arg, &FLAG_landmarks) || GetFlagArgVal("model_path", arg, &FLAG_modelPath) ||
|
||||
GetFlagArgVal("eyesize_sensitivity", arg, &FLAG_eyeSizeSensitivity) ||
|
||||
GetFlagArgVal("split_screen_view", arg, &FLAG_splitScreenView) ||
|
||||
GetFlagArgVal("temporal", arg, &FLAG_temporal) ||
|
||||
GetFlagArgVal("draw_visualization", arg, &FLAG_drawVisualization) ||
|
||||
GetFlagArgVal("redirect_gaze", arg, &FLAG_gazeRedirect))) {
|
||||
continue;
|
||||
} else if (GetFlagArgVal("help", arg, &help)) {
|
||||
Usage();
|
||||
} else if (arg[1] != '-') {
|
||||
for (++arg; *arg; ++arg) {
|
||||
if (*arg == 'v') {
|
||||
FLAG_verbose = true;
|
||||
} else {
|
||||
// printf("Unknown flag: \"-%c\"\n", *arg);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
// printf("Unknown flag: \"%s\"\n", arg);
|
||||
}
|
||||
}
|
||||
return errs;
|
||||
}
|
||||
|
||||
enum {
|
||||
myErrNone = 0,
|
||||
myErrShader = -1,
|
||||
myErrProgram = -2,
|
||||
myErrTexture = -3,
|
||||
};
|
||||
|
||||
#if 1
|
||||
class MyTimer {
|
||||
public:
|
||||
MyTimer() { dt = dt.zero(); } /**< Clear the duration to 0. */
|
||||
void start() { t0 = std::chrono::high_resolution_clock::now(); } /**< Start the timer. */
|
||||
void pause() { dt = std::chrono::high_resolution_clock::now() - t0; } /**< Pause the timer. */
|
||||
void resume() { t0 = std::chrono::high_resolution_clock::now() - dt; } /**< Resume the timer. */
|
||||
void stop() { pause(); } /**< Stop the timer. */
|
||||
double elapsedTimeFloat() const {
|
||||
return std::chrono::duration<double>(dt).count();
|
||||
} /**< Report the elapsed time as a float. */
|
||||
private:
|
||||
std::chrono::high_resolution_clock::time_point t0;
|
||||
std::chrono::high_resolution_clock::duration dt;
|
||||
};
|
||||
#endif
|
||||
|
||||
std::string getCalendarTime() {
|
||||
// Get the current time
|
||||
std::chrono::system_clock::time_point currentTimePoint = std::chrono::system_clock::now();
|
||||
// Convert to time_t from time_point
|
||||
std::time_t currentTime = std::chrono::system_clock::to_time_t(currentTimePoint);
|
||||
// Convert to tm to get structure holding a calendar date and time broken down into its components.
|
||||
std::tm brokenTime = *std::localtime(¤tTime);
|
||||
std::ostringstream calendarTime;
|
||||
|
||||
// std::put_time has not been implemented under GCC5. In order to support centOS7(GCC4.8), we use strftime.
|
||||
// (YYYY-MM-DD-HH-mm-ss)<Year>-<Month>-<Date>-<Hour>-<Mins>-<Seconds>
|
||||
// Get the time since epoch 0(Thu Jan 1 00:00:00 1970) and the remainder after division is our milliseconds
|
||||
char foo[24];
|
||||
if(0 < strftime(foo, sizeof(foo), "%Y-%m-%d-%H-%M-%S", &brokenTime)) {
|
||||
//cout << foo << endl;
|
||||
std::string fooStr(foo);
|
||||
calendarTime << fooStr;
|
||||
}
|
||||
|
||||
std::chrono::milliseconds currentMilliseconds =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(currentTimePoint.time_since_epoch()) % 1000;
|
||||
// Append the milliseconds to the stream
|
||||
calendarTime << "-" << std::setfill('0') << std::setw(3) << currentMilliseconds.count(); // milliseconds
|
||||
return calendarTime.str();
|
||||
}
|
||||
|
||||
class DoApp {
|
||||
public:
|
||||
enum Err {
|
||||
errNone = GazeEngine::Err::errNone,
|
||||
errGeneral = GazeEngine::Err::errGeneral,
|
||||
errRun = GazeEngine::Err::errRun,
|
||||
errInitialization = GazeEngine::Err::errInitialization,
|
||||
errRead = GazeEngine::Err::errRead,
|
||||
errEffect = GazeEngine::Err::errEffect,
|
||||
errParameter = GazeEngine::Err::errParameter,
|
||||
errUnimplemented,
|
||||
errMissing,
|
||||
errVideo,
|
||||
errImageSize,
|
||||
errNotFound,
|
||||
errGLFWInit,
|
||||
errGLInit,
|
||||
errRendererInit,
|
||||
errGLResource,
|
||||
errGLGeneric,
|
||||
errSDK,
|
||||
errCuda,
|
||||
errCancel,
|
||||
errCamera
|
||||
};
|
||||
Err doAppErr(GazeEngine::Err status) { return (Err)status; }
|
||||
GazeEngine gaze_ar_engine;
|
||||
DoApp();
|
||||
~DoApp();
|
||||
|
||||
void stop();
|
||||
Err initGazeEngine(const char *modelPath = nullptr, bool isLandmarks126 = false, bool gazeRedirect=true, unsigned eyeSizeSensitivity=3);
|
||||
Err initCamera(const char *camRes = nullptr, unsigned int camID = 0);
|
||||
Err initOfflineMode(const char *inputFilename = nullptr, const char *outputFilename = nullptr);
|
||||
Err acquireFrame();
|
||||
Err acquireFaceBox();
|
||||
Err acquireFaceBoxAndLandmarks();
|
||||
Err acquireGazeRedirection();
|
||||
Err run();
|
||||
|
||||
void drawFPS(cv::Mat &img);
|
||||
void drawBBoxes(const cv::Mat &src, NvAR_Rect *output_bbox);
|
||||
void DrawLandmarkPoints(const cv::Mat &src, NvAR_Point2f *facial_landmarks, int numLandmarks, cv::Scalar *color);
|
||||
void drawKalmanStatus(cv::Mat &img);
|
||||
void drawVideoCaptureStatus(cv::Mat &img);
|
||||
void processKey(int key);
|
||||
Err writeVideo(const cv::Mat &frm);
|
||||
void getFPS();
|
||||
static const char *errorStringFromCode(Err code);
|
||||
|
||||
cv::VideoCapture cap{};
|
||||
cv::Mat frame, outputFrame;
|
||||
|
||||
int inputWidth, inputHeight;
|
||||
cv::VideoWriter gazeRedirectOutputVideo{};
|
||||
int frameIndex;
|
||||
static const char windowTitle[];
|
||||
double frameTime;
|
||||
// std::chrono::high_resolution_clock::time_point frameTimer;
|
||||
MyTimer frameTimer;
|
||||
cv::VideoWriter capturedVideo;
|
||||
std::ofstream gazeEngineVideoOutputFile;
|
||||
|
||||
GazeEngine::Err nvErr;
|
||||
bool drawVisualization, showFPS, captureVideo, splitScreenView, displayLandmarks;
|
||||
};
|
||||
|
||||
DoApp *gApp = nullptr;
|
||||
const char DoApp::windowTitle[] = "GazeRedirect App";
|
||||
|
||||
void DoApp::processKey(int key) {
|
||||
switch (key) {
|
||||
case '3':
|
||||
gaze_ar_engine.destroyGazeRedirectionFeature();
|
||||
gaze_ar_engine.createGazeRedirectionFeature(FLAG_modelPath.c_str());
|
||||
gaze_ar_engine.initGazeRedirectionIOParams();
|
||||
break;
|
||||
case 'C':
|
||||
case 'c':
|
||||
captureVideo = !captureVideo;
|
||||
break;
|
||||
case 'W':
|
||||
case 'w':
|
||||
drawVisualization = !drawVisualization;
|
||||
break;
|
||||
case 'F':
|
||||
case 'f':
|
||||
showFPS = !showFPS;
|
||||
break;
|
||||
case 'O':
|
||||
case 'o':
|
||||
splitScreenView = !splitScreenView;
|
||||
break;
|
||||
case 'L':
|
||||
case 'l':
|
||||
displayLandmarks = !displayLandmarks;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoApp::Err DoApp::initGazeEngine(const char *modelPath, bool isNumLandmarks126, bool gazeRedirect, unsigned eyeSizeSensitivity) {
|
||||
if (!cap.isOpened()) return errVideo;
|
||||
|
||||
int numLandmarkPoints = isNumLandmarks126 ? 126 : 68;
|
||||
gaze_ar_engine.setNumLandmarks(numLandmarkPoints);
|
||||
gaze_ar_engine.setGazeRedirect(gazeRedirect);
|
||||
gaze_ar_engine.setEyeSizeSensitivity(eyeSizeSensitivity);
|
||||
nvErr = gaze_ar_engine.createGazeRedirectionFeature(modelPath);
|
||||
|
||||
#ifdef DEBUG
|
||||
detector->setOutputLocation(outputDir);
|
||||
#endif // DEBUG
|
||||
|
||||
#define VISUALIZE
|
||||
#ifdef VISUALIZE
|
||||
if (!FLAG_offlineMode) cv::namedWindow(windowTitle, 1);
|
||||
#endif // VISUALIZE
|
||||
|
||||
frameIndex = 0;
|
||||
|
||||
return doAppErr(nvErr);
|
||||
}
|
||||
|
||||
void DoApp::stop() {
|
||||
gaze_ar_engine.destroyGazeRedirectionFeature();
|
||||
|
||||
if (FLAG_offlineMode) {
|
||||
gazeRedirectOutputVideo.release();
|
||||
}
|
||||
cap.release();
|
||||
#ifdef VISUALIZE
|
||||
cv::destroyAllWindows();
|
||||
#endif // VISUALIZE
|
||||
}
|
||||
|
||||
void DoApp::drawBBoxes(const cv::Mat &src, NvAR_Rect *output_bbox) {
|
||||
cv::Mat frm;
|
||||
if (FLAG_offlineMode)
|
||||
frm = src.clone();
|
||||
else
|
||||
frm = src;
|
||||
|
||||
if (output_bbox)
|
||||
cv::rectangle(frm, cv::Point(lround(output_bbox->x), lround(output_bbox->y)),
|
||||
cv::Point(lround(output_bbox->x + output_bbox->width), lround(output_bbox->y + output_bbox->height)),
|
||||
cv::Scalar(255, 0, 0), 2);
|
||||
}
|
||||
|
||||
DoApp::Err DoApp::writeVideo(const cv::Mat &frm) {
|
||||
if (captureVideo) {
|
||||
if (!capturedVideo.isOpened()) {
|
||||
//Assign the filename for capturing video
|
||||
const std::string currentCalendarTime = getCalendarTime();
|
||||
const std::string capturedOutputFileName = currentCalendarTime + ".mp4";
|
||||
getFPS();
|
||||
if (frameTime) {
|
||||
float fps = (float)(1.0 / frameTime);
|
||||
// Open the video for writing.
|
||||
capturedVideo.open(capturedOutputFileName, StringToFourcc(FLAG_captureCodec), fps,
|
||||
cv::Size(frm.cols, frm.rows));
|
||||
if (!capturedVideo.isOpened()) {
|
||||
|
||||
std::cout << "Error: Could not open video for writing: \"" << capturedOutputFileName << "\"\n";
|
||||
return errVideo;
|
||||
}
|
||||
if (FLAG_verbose) {
|
||||
std::cout << "Capturing video started" << std::endl;
|
||||
}
|
||||
capturedVideo << frm;
|
||||
} else { // If frameTime is 0.f, returns without writing the frame to the Video
|
||||
return errNone;
|
||||
}
|
||||
} else {
|
||||
// Write each frame to the Video
|
||||
capturedVideo << frm;
|
||||
}
|
||||
} else {
|
||||
if (capturedVideo.isOpened()) {
|
||||
if (FLAG_verbose) {
|
||||
std::cout << "Capturing video ended" << std::endl;
|
||||
}
|
||||
capturedVideo.release();
|
||||
}
|
||||
}
|
||||
return errNone;
|
||||
}
|
||||
|
||||
void DoApp::DrawLandmarkPoints(const cv::Mat &src, NvAR_Point2f *facial_landmarks, int numLandmarks , cv::Scalar* color) {
|
||||
if (!facial_landmarks)
|
||||
return;
|
||||
cv::Mat frm;
|
||||
if (FLAG_offlineMode)
|
||||
frm = src;
|
||||
else
|
||||
frm = src;
|
||||
NvAR_Point2f *pt, *endPt;
|
||||
for (endPt = (pt = (NvAR_Point2f *)facial_landmarks) + numLandmarks; pt < endPt; ++pt)
|
||||
cv::circle(frm, cv::Point(lround(pt->x), lround(pt->y)), 1.5, *color, -1);
|
||||
}
|
||||
|
||||
DoApp::Err DoApp::acquireFrame() {
|
||||
Err err = errNone;
|
||||
|
||||
// If the machine goes to sleep with the app running and then wakes up, the camera object is not destroyed but the
|
||||
// frames we try to read are empty. So we try to re-initialize the camera with the same resolution settings. If the
|
||||
// resolution has changed, you will need to destroy and create the features again with the new camera resolution (not
|
||||
// done here) as well as reallocate memory accordingly with GazeEngine::initGazeRedirectionIOParams()
|
||||
cap >> frame; // get a new frame from camera into the class variable frame.
|
||||
if (frame.empty()) {
|
||||
// if in Offline mode, this means end of video,so we return
|
||||
if (FLAG_offlineMode) return errVideo;
|
||||
// try Init one more time if reading frames from camera
|
||||
err = initCamera(FLAG_camRes.c_str(), FLAG_camID);
|
||||
if (err != errNone) return err;
|
||||
cap >> frame;
|
||||
if (frame.empty()) return errVideo;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
DoApp::Err DoApp::acquireGazeRedirection() {
|
||||
DoApp::Err doErr = errNone;
|
||||
|
||||
nvErr = gaze_ar_engine.acquireGazeRedirection(frame, outputFrame);
|
||||
|
||||
if (GazeEngine::Err::errNone == nvErr) {
|
||||
#ifdef VISUALIZE
|
||||
frameTimer.pause();
|
||||
NvAR_Rect *bbox = gaze_ar_engine.getLargestBox();
|
||||
// Check for valid bounding box in case confidence check fails
|
||||
if (drawVisualization && bbox) {
|
||||
// Display gaze direction and head rotation
|
||||
NvAR_Quaternion *pose = gaze_ar_engine.getPose();
|
||||
NvAR_Point3f *gaze_direction = gaze_ar_engine.getGazeDirectionPoints();
|
||||
if (pose) {
|
||||
gaze_ar_engine.DrawPose(frame, pose);
|
||||
gaze_ar_engine.DrawEstimatedGaze(frame);
|
||||
}
|
||||
// Print head pose
|
||||
char buf[64];
|
||||
float fontsize;
|
||||
if (inputHeight <= 720) {
|
||||
fontsize = 0.5;
|
||||
} else {
|
||||
fontsize = .5;
|
||||
}
|
||||
snprintf(buf, sizeof(buf), " Original image");
|
||||
cv::putText(frame, buf, cv::Point(120, 40), cv::FONT_HERSHEY_SIMPLEX, fontsize, cv::Scalar(0, 255, 0), 1);
|
||||
snprintf(buf, sizeof(buf), "gaze angles: %.1f %.1f", gaze_ar_engine.gaze_angles_vector[0] * DEGREES_PER_RADIAN,
|
||||
gaze_ar_engine.gaze_angles_vector[1] * DEGREES_PER_RADIAN);
|
||||
cv::putText(frame, buf, cv::Point(120, 110), cv::FONT_HERSHEY_SIMPLEX, fontsize, cv::Scalar(0, 255, 0), 1);
|
||||
// display head translationss
|
||||
snprintf(buf, sizeof(buf), "head translation: %.1f %.1f %.1f", gaze_ar_engine.head_translation[0],
|
||||
gaze_ar_engine.head_translation[1], gaze_ar_engine.head_translation[2]);
|
||||
cv::putText(frame, buf, cv::Point(80, 80), cv::FONT_HERSHEY_SIMPLEX, fontsize, cv::Scalar(0, 255, 0), 1);
|
||||
// Display landmarks if flag is set.
|
||||
if (displayLandmarks) {
|
||||
cv::Scalar landmarks_color(0, 0, 255);
|
||||
DrawLandmarkPoints(frame, gaze_ar_engine.getLandmarks(), gaze_ar_engine.getNumLandmarks(), &landmarks_color);
|
||||
drawBBoxes(frame, gaze_ar_engine.getLargestBox());
|
||||
}
|
||||
snprintf(buf, sizeof(buf), "Redirected Output");
|
||||
cv::putText(outputFrame, buf, cv::Point(80, 40), cv::FONT_HERSHEY_SIMPLEX, fontsize, cv::Scalar(0, 255, 0), 1);
|
||||
}
|
||||
}
|
||||
if (FLAG_offlineMode) {
|
||||
if (splitScreenView && FLAG_gazeRedirect) {
|
||||
// Store the original and redirected image side-by-side
|
||||
cv::Mat matDst(cv::Size(outputFrame.cols * 2, outputFrame.rows), outputFrame.type(), cv::Scalar::all(0));
|
||||
cv::Mat matRoi = matDst(cv::Rect(0, 0, outputFrame.cols, outputFrame.rows));
|
||||
frame.copyTo(matRoi);
|
||||
matRoi = matDst(cv::Rect(outputFrame.cols, 0, outputFrame.cols, outputFrame.rows));
|
||||
outputFrame.copyTo(matRoi);
|
||||
gazeRedirectOutputVideo.write(matDst);
|
||||
} else {
|
||||
if (!FLAG_gazeRedirect) {
|
||||
gazeRedirectOutputVideo.write(frame);
|
||||
} else {
|
||||
gazeRedirectOutputVideo.write(outputFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
frameTimer.resume();
|
||||
#endif //VISUALIZE
|
||||
// If captureOutputs has been set to true, save the output frames.
|
||||
if (FLAG_captureOutputs) {
|
||||
// Display original gives the option to display the original frame in addition to the redirected image
|
||||
// side-by-side.
|
||||
if (splitScreenView && FLAG_gazeRedirect) {
|
||||
// Store the original and redirected image side-by-side
|
||||
cv::Mat matDst(cv::Size(outputFrame.cols * 2, outputFrame.rows), outputFrame.type(), cv::Scalar::all(0));
|
||||
cv::Mat matRoi = matDst(cv::Rect(0, 0, outputFrame.cols, outputFrame.rows));
|
||||
frame.copyTo(matRoi);
|
||||
matRoi = matDst(cv::Rect(outputFrame.cols, 0, outputFrame.cols, outputFrame.rows));
|
||||
outputFrame.copyTo(matRoi);
|
||||
writeVideo(matDst);
|
||||
} else {
|
||||
if (!FLAG_gazeRedirect) {
|
||||
writeVideo(frame);
|
||||
} else {
|
||||
writeVideo(outputFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
return doErr;
|
||||
}
|
||||
|
||||
DoApp::Err DoApp::initCamera(const char *camRes, unsigned int camID) {
|
||||
if (cap.open(camID)) {
|
||||
if (camRes) {
|
||||
int n;
|
||||
n = sscanf(camRes, "%d%*[xX]%d", &inputWidth, &inputHeight);
|
||||
switch (n) {
|
||||
case 2:
|
||||
break; // We have read both width and height
|
||||
case 1:
|
||||
inputHeight = inputWidth;
|
||||
inputWidth = (int)(inputHeight * (4. / 3.) + .5);
|
||||
break;
|
||||
default:
|
||||
inputHeight = 0;
|
||||
inputWidth = 0;
|
||||
break;
|
||||
}
|
||||
if (inputWidth) cap.set(CV_CAP_PROP_FRAME_WIDTH, inputWidth);
|
||||
if (inputHeight) cap.set(CV_CAP_PROP_FRAME_HEIGHT, inputHeight);
|
||||
inputWidth = (int)cap.get(CV_CAP_PROP_FRAME_WIDTH);
|
||||
inputHeight = (int)cap.get(CV_CAP_PROP_FRAME_HEIGHT);
|
||||
|
||||
gaze_ar_engine.setInputImageWidth(inputWidth);
|
||||
gaze_ar_engine.setInputImageHeight(inputHeight);
|
||||
}
|
||||
} else
|
||||
return errCamera;
|
||||
return errNone;
|
||||
}
|
||||
|
||||
DoApp::Err DoApp::initOfflineMode(const char *inputFilename, const char *outputFilename) {
|
||||
if (cap.open(inputFilename)) {
|
||||
inputWidth = (int)cap.get(CV_CAP_PROP_FRAME_WIDTH);
|
||||
inputHeight = (int)cap.get(CV_CAP_PROP_FRAME_HEIGHT);
|
||||
gaze_ar_engine.setInputImageWidth(inputWidth);
|
||||
gaze_ar_engine.setInputImageHeight(inputHeight);
|
||||
} else {
|
||||
printf("ERROR: Unable to open the input video file \"%s\" \n", inputFilename);
|
||||
return Err::errVideo;
|
||||
}
|
||||
std::string fdOutputVideoName, fldOutputVideoName, ffOutputVideoName, fgzOutputVideoName;
|
||||
std::string outputFilePrefix;
|
||||
if (outputFilename && strlen(outputFilename) != 0) {
|
||||
outputFilePrefix = outputFilename;
|
||||
} else {
|
||||
size_t lastindex = std::string(inputFilename).find_last_of(".");
|
||||
outputFilePrefix = std::string(inputFilename).substr(0, lastindex);
|
||||
outputFilePrefix = outputFilePrefix + "_gaze.mp4";
|
||||
}
|
||||
fgzOutputVideoName = outputFilePrefix;
|
||||
if (splitScreenView && FLAG_gazeRedirect) {
|
||||
if (!gazeRedirectOutputVideo.open(fgzOutputVideoName, StringToFourcc(FLAG_captureCodec), cap.get(CV_CAP_PROP_FPS),
|
||||
cv::Size(inputWidth * 2, inputHeight))) {
|
||||
printf("ERROR: Unable to open the output video file \"%s\" \n", fgzOutputVideoName.c_str());
|
||||
return Err::errGeneral;
|
||||
}
|
||||
} else {
|
||||
if (!gazeRedirectOutputVideo.open(fgzOutputVideoName, StringToFourcc(FLAG_captureCodec), cap.get(CV_CAP_PROP_FPS),
|
||||
cv::Size(inputWidth, inputHeight))) {
|
||||
printf("ERROR: Unable to open the output video file \"%s\" \n", fgzOutputVideoName.c_str());
|
||||
return Err::errGeneral;
|
||||
}
|
||||
}
|
||||
captureVideo = true;
|
||||
return Err::errNone;
|
||||
}
|
||||
|
||||
DoApp::DoApp() {
|
||||
// Make sure things are initialized properly
|
||||
gApp = this;
|
||||
drawVisualization = FLAG_drawVisualization;
|
||||
showFPS = false;
|
||||
splitScreenView = FLAG_splitScreenView;
|
||||
displayLandmarks = true;
|
||||
captureVideo = false;
|
||||
frameTime = 0;
|
||||
frameIndex = 0;
|
||||
nvErr = GazeEngine::errNone;
|
||||
}
|
||||
|
||||
DoApp::~DoApp() {}
|
||||
|
||||
char *g_nvARSDKPath = NULL;
|
||||
|
||||
int chooseGPU() {
|
||||
// If the system has multiple supported GPUs then the application
|
||||
// should use CUDA driver APIs or CUDA runtime APIs to enumerate
|
||||
// the GPUs and select one based on the application's requirements
|
||||
|
||||
// Cuda device 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DoApp::getFPS() {
|
||||
const float timeConstant = 16.f;
|
||||
frameTimer.stop();
|
||||
float t = (float)frameTimer.elapsedTimeFloat();
|
||||
if (t < 100.f) {
|
||||
if (frameTime)
|
||||
frameTime += (t - frameTime) * (1.f / timeConstant); // 1 pole IIR filter
|
||||
else
|
||||
frameTime = t;
|
||||
} else { // Ludicrous time interval; reset
|
||||
frameTime = 0.f; // WAKE UP
|
||||
}
|
||||
frameTimer.start();
|
||||
}
|
||||
|
||||
void DoApp::drawFPS(cv::Mat &img) {
|
||||
getFPS();
|
||||
if (frameTime && showFPS) {
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof(buf), "%.1f", 1. / frameTime);
|
||||
cv::putText(img, buf, cv::Point(img.cols - 80, img.rows - 10), cv::FONT_HERSHEY_SIMPLEX, 1,
|
||||
cv::Scalar(255, 255, 255), 1);
|
||||
}
|
||||
}
|
||||
|
||||
void DoApp::drawKalmanStatus(cv::Mat &img) {
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof(buf), "Kalman %s", (gaze_ar_engine.bStabilizeFace ? "on" : "off"));
|
||||
cv::putText(img, buf, cv::Point(10, img.rows - 40), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255, 255, 255), 1);
|
||||
}
|
||||
|
||||
void DoApp::drawVideoCaptureStatus(cv::Mat &img) {
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof(buf), "Video Capturing %s", (captureVideo ? "on" : "off"));
|
||||
cv::putText(img, buf, cv::Point(10, img.rows - 70), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255, 255, 255), 1);
|
||||
}
|
||||
|
||||
DoApp::Err DoApp::run() {
|
||||
DoApp::Err doErr = errNone;
|
||||
|
||||
GazeEngine::Err err = gaze_ar_engine.initGazeRedirectionIOParams();
|
||||
if (err != GazeEngine::Err::errNone) {
|
||||
return doAppErr(err);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
doErr = acquireFrame();
|
||||
if (frame.empty() && FLAG_offlineMode) {
|
||||
// We have reached the end of the video
|
||||
// so return without any error.
|
||||
return DoApp::errNone;
|
||||
} else if (doErr != DoApp::errNone) {
|
||||
return doErr;
|
||||
}
|
||||
outputFrame.create(inputHeight, inputWidth, frame.type());
|
||||
doErr = acquireGazeRedirection();
|
||||
if (DoApp::errCancel == doErr || DoApp::errVideo == doErr) return doErr;
|
||||
#ifdef VISUALIZE
|
||||
if (!frame.empty() && !FLAG_offlineMode) {
|
||||
if (drawVisualization) {
|
||||
drawFPS(frame);
|
||||
drawKalmanStatus(frame);
|
||||
if (FLAG_captureOutputs && captureVideo) {
|
||||
if (!FLAG_gazeRedirect) {
|
||||
drawVideoCaptureStatus(frame);
|
||||
} else {
|
||||
drawVideoCaptureStatus(outputFrame);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (splitScreenView && FLAG_gazeRedirect) {
|
||||
// Store the original and redirected image side-by-side
|
||||
cv::Mat matDst(cv::Size(outputFrame.cols * 2, outputFrame.rows), outputFrame.type(), cv::Scalar::all(0));
|
||||
cv::Mat matRoi = matDst(cv::Rect(0, 0, outputFrame.cols, outputFrame.rows));
|
||||
frame.copyTo(matRoi);
|
||||
matRoi = matDst(cv::Rect(outputFrame.cols, 0, outputFrame.cols, outputFrame.rows));
|
||||
outputFrame.copyTo(matRoi);
|
||||
cv::imshow(windowTitle, matDst);
|
||||
} else {
|
||||
if (!FLAG_gazeRedirect) {
|
||||
cv::imshow(windowTitle, frame);
|
||||
} else {
|
||||
cv::imshow(windowTitle, outputFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif //VISUALIZE
|
||||
if (!FLAG_offlineMode) {
|
||||
int n = cv::waitKey(1);
|
||||
if (n >= 0) {
|
||||
static const int ESC_KEY = 27;
|
||||
if (n == ESC_KEY) break;
|
||||
processKey(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
return doErr;
|
||||
}
|
||||
|
||||
const char *DoApp::errorStringFromCode(DoApp::Err code) {
|
||||
struct LUTEntry {
|
||||
Err code;
|
||||
const char *str;
|
||||
};
|
||||
static const LUTEntry lut[] = {
|
||||
{errNone, "no error"},
|
||||
{errGeneral, "an error has occured"},
|
||||
{errRun, "an error has occured while the feature is running"},
|
||||
{errInitialization, "Initializing Gaze Engine failed"},
|
||||
{errRead, "an error has occured while reading a file"},
|
||||
{errEffect, "an error has occured while creating a feature"},
|
||||
{errParameter, "an error has occured while setting a parameter for a feature"},
|
||||
{errUnimplemented, "the feature is unimplemented"},
|
||||
{errMissing, "missing input parameter"},
|
||||
{errVideo, "no video source has been found"},
|
||||
{errImageSize, "the image size cannot be accommodated"},
|
||||
{errNotFound, "the item cannot be found"},
|
||||
{errGLFWInit, "GLFW initialization failed"},
|
||||
{errGLInit, "OpenGL initialization failed"},
|
||||
{errRendererInit, "renderer initialization failed"},
|
||||
{errGLResource, "an OpenGL resource could not be found"},
|
||||
{errGLGeneric, "an otherwise unspecified OpenGL error has occurred"},
|
||||
{errSDK, "an SDK error has occurred"},
|
||||
{errCuda, "a CUDA error has occurred"},
|
||||
{errCancel, "the user cancelled"},
|
||||
{errCamera, "unable to connect to the camera"},
|
||||
};
|
||||
for (const LUTEntry *p = lut; p < &lut[sizeof(lut) / sizeof(lut[0])]; ++p)
|
||||
if (p->code == code) return p->str;
|
||||
static char msg[18];
|
||||
snprintf(msg, sizeof(msg), "error #%d", code);
|
||||
return msg;
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
* main
|
||||
********************************************************************************/
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Parse the arguments
|
||||
if (0 != ParseMyArgs(argc, argv)) return -100;
|
||||
|
||||
DoApp app;
|
||||
DoApp::Err doErr = DoApp::Err::errNone;
|
||||
if (FLAG_verbose) printf("Enable temporal optimizations in detecting face and landmarks = %d\n", FLAG_temporal);
|
||||
app.gaze_ar_engine.setFaceStabilization(FLAG_temporal);
|
||||
|
||||
if (FLAG_offlineMode) {
|
||||
if (FLAG_inFile.empty()) {
|
||||
doErr = DoApp::errMissing;
|
||||
printf("ERROR: %s, please specify input file using --in \n", app.errorStringFromCode(doErr));
|
||||
goto bail;
|
||||
}
|
||||
doErr = app.initOfflineMode(FLAG_inFile.c_str(), FLAG_outFile.c_str());
|
||||
} else {
|
||||
doErr = app.initCamera(FLAG_camRes.c_str(), FLAG_camID);
|
||||
}
|
||||
BAIL_IF_ERR(doErr);
|
||||
|
||||
doErr = app.initGazeEngine(FLAG_modelPath.c_str(), FLAG_isNumLandmarks126, FLAG_gazeRedirect, FLAG_eyeSizeSensitivity);
|
||||
BAIL_IF_ERR(doErr);
|
||||
|
||||
doErr = app.run();
|
||||
BAIL_IF_ERR(doErr);
|
||||
|
||||
bail:
|
||||
if (doErr) printf("ERROR: %s\n", app.errorStringFromCode(doErr));
|
||||
app.stop();
|
||||
return (int)doErr;
|
||||
}
|
||||
|
||||
BIN
samples/GazeRedirect/GazeRedirect.exe
Normal file
BIN
samples/GazeRedirect/GazeRedirect.exe
Normal file
Binary file not shown.
10
samples/GazeRedirect/Readme.txt
Normal file
10
samples/GazeRedirect/Readme.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
GazeRedirect is a sample Windows application that demonstrates the gaze redirection feature of the NVIDIA AR SDK. The application requires a video feed
|
||||
from a camera connected to the computer running the application, or from a video file, as specified
|
||||
with command-line arguments (enumerated by executing: GazeRedirect.exe --help).
|
||||
|
||||
Here are a few controls for the gaze feature:
|
||||
'o'/'O' - Display original image and the redirected image side-by-side
|
||||
'w'/'W' - Display visualization of landmarks and head translation values.
|
||||
't'/'T' - Display head translation values when visualization is on.
|
||||
|
||||
For more controls and configurations of the sample app, please read the SDK programming guide.
|
||||
3
samples/GazeRedirect/run.bat
Normal file
3
samples/GazeRedirect/run.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
SETLOCAL
|
||||
SET PATH=%PATH%;..\..\samples\external\opencv\bin;..\..\bin;
|
||||
GazeRedirect.exe
|
||||
282
samples/external/GLAD/include/KHR/khrplatform.h
vendored
Normal file
282
samples/external/GLAD/include/KHR/khrplatform.h
vendored
Normal file
@@ -0,0 +1,282 @@
|
||||
#ifndef __khrplatform_h_
|
||||
#define __khrplatform_h_
|
||||
|
||||
/*
|
||||
** Copyright (c) 2008-2018 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||
** copy of this software and/or associated documentation files (the
|
||||
** "Materials"), to deal in the Materials without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
** permit persons to whom the Materials are furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included
|
||||
** in all copies or substantial portions of the Materials.
|
||||
**
|
||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
*/
|
||||
|
||||
/* Khronos platform-specific types and definitions.
|
||||
*
|
||||
* The master copy of khrplatform.h is maintained in the Khronos EGL
|
||||
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
|
||||
* The last semantic modification to khrplatform.h was at commit ID:
|
||||
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
|
||||
*
|
||||
* Adopters may modify this file to suit their platform. Adopters are
|
||||
* encouraged to submit platform specific modifications to the Khronos
|
||||
* group so that they can be included in future versions of this file.
|
||||
* Please submit changes by filing pull requests or issues on
|
||||
* the EGL Registry repository linked above.
|
||||
*
|
||||
*
|
||||
* See the Implementer's Guidelines for information about where this file
|
||||
* should be located on your system and for more details of its use:
|
||||
* http://www.khronos.org/registry/implementers_guide.pdf
|
||||
*
|
||||
* This file should be included as
|
||||
* #include <KHR/khrplatform.h>
|
||||
* by Khronos client API header files that use its types and defines.
|
||||
*
|
||||
* The types in khrplatform.h should only be used to define API-specific types.
|
||||
*
|
||||
* Types defined in khrplatform.h:
|
||||
* khronos_int8_t signed 8 bit
|
||||
* khronos_uint8_t unsigned 8 bit
|
||||
* khronos_int16_t signed 16 bit
|
||||
* khronos_uint16_t unsigned 16 bit
|
||||
* khronos_int32_t signed 32 bit
|
||||
* khronos_uint32_t unsigned 32 bit
|
||||
* khronos_int64_t signed 64 bit
|
||||
* khronos_uint64_t unsigned 64 bit
|
||||
* khronos_intptr_t signed same number of bits as a pointer
|
||||
* khronos_uintptr_t unsigned same number of bits as a pointer
|
||||
* khronos_ssize_t signed size
|
||||
* khronos_usize_t unsigned size
|
||||
* khronos_float_t signed 32 bit floating point
|
||||
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
|
||||
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
|
||||
* nanoseconds
|
||||
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
|
||||
* khronos_boolean_enum_t enumerated boolean type. This should
|
||||
* only be used as a base type when a client API's boolean type is
|
||||
* an enum. Client APIs which use an integer or other type for
|
||||
* booleans cannot use this as the base type for their boolean.
|
||||
*
|
||||
* Tokens defined in khrplatform.h:
|
||||
*
|
||||
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
|
||||
*
|
||||
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
|
||||
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
|
||||
*
|
||||
* Calling convention macros defined in this file:
|
||||
* KHRONOS_APICALL
|
||||
* KHRONOS_APIENTRY
|
||||
* KHRONOS_APIATTRIBUTES
|
||||
*
|
||||
* These may be used in function prototypes as:
|
||||
*
|
||||
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
|
||||
* int arg1,
|
||||
* int arg2) KHRONOS_APIATTRIBUTES;
|
||||
*/
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APICALL
|
||||
*-------------------------------------------------------------------------
|
||||
* This precedes the return type of the function in the function prototype.
|
||||
*/
|
||||
#if defined(_WIN32) && !defined(__SCITECH_SNAP__)
|
||||
# define KHRONOS_APICALL __declspec(dllimport)
|
||||
#elif defined (__SYMBIAN32__)
|
||||
# define KHRONOS_APICALL IMPORT_C
|
||||
#elif defined(__ANDROID__)
|
||||
# define KHRONOS_APICALL __attribute__((visibility("default")))
|
||||
#else
|
||||
# define KHRONOS_APICALL
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APIENTRY
|
||||
*-------------------------------------------------------------------------
|
||||
* This follows the return type of the function and precedes the function
|
||||
* name in the function prototype.
|
||||
*/
|
||||
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
|
||||
/* Win32 but not WinCE */
|
||||
# define KHRONOS_APIENTRY __stdcall
|
||||
#else
|
||||
# define KHRONOS_APIENTRY
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APIATTRIBUTES
|
||||
*-------------------------------------------------------------------------
|
||||
* This follows the closing parenthesis of the function prototype arguments.
|
||||
*/
|
||||
#if defined (__ARMCC_2__)
|
||||
#define KHRONOS_APIATTRIBUTES __softfp
|
||||
#else
|
||||
#define KHRONOS_APIATTRIBUTES
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* basic type definitions
|
||||
*-----------------------------------------------------------------------*/
|
||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
|
||||
|
||||
|
||||
/*
|
||||
* Using <stdint.h>
|
||||
*/
|
||||
#include <stdint.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(__VMS ) || defined(__sgi)
|
||||
|
||||
/*
|
||||
* Using <inttypes.h>
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
|
||||
|
||||
/*
|
||||
* Win32
|
||||
*/
|
||||
typedef __int32 khronos_int32_t;
|
||||
typedef unsigned __int32 khronos_uint32_t;
|
||||
typedef __int64 khronos_int64_t;
|
||||
typedef unsigned __int64 khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(__sun__) || defined(__digital__)
|
||||
|
||||
/*
|
||||
* Sun or Digital
|
||||
*/
|
||||
typedef int khronos_int32_t;
|
||||
typedef unsigned int khronos_uint32_t;
|
||||
#if defined(__arch64__) || defined(_LP64)
|
||||
typedef long int khronos_int64_t;
|
||||
typedef unsigned long int khronos_uint64_t;
|
||||
#else
|
||||
typedef long long int khronos_int64_t;
|
||||
typedef unsigned long long int khronos_uint64_t;
|
||||
#endif /* __arch64__ */
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif 0
|
||||
|
||||
/*
|
||||
* Hypothetical platform with no float or int64 support
|
||||
*/
|
||||
typedef int khronos_int32_t;
|
||||
typedef unsigned int khronos_uint32_t;
|
||||
#define KHRONOS_SUPPORT_INT64 0
|
||||
#define KHRONOS_SUPPORT_FLOAT 0
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* Generic fallback
|
||||
*/
|
||||
#include <stdint.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Types that are (so far) the same on all platforms
|
||||
*/
|
||||
typedef signed char khronos_int8_t;
|
||||
typedef unsigned char khronos_uint8_t;
|
||||
typedef signed short int khronos_int16_t;
|
||||
typedef unsigned short int khronos_uint16_t;
|
||||
|
||||
/*
|
||||
* Types that differ between LLP64 and LP64 architectures - in LLP64,
|
||||
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
|
||||
* to be the only LLP64 architecture in current use.
|
||||
*/
|
||||
#ifdef _WIN64
|
||||
typedef signed long long int khronos_intptr_t;
|
||||
typedef unsigned long long int khronos_uintptr_t;
|
||||
typedef signed long long int khronos_ssize_t;
|
||||
typedef unsigned long long int khronos_usize_t;
|
||||
#else
|
||||
typedef signed long int khronos_intptr_t;
|
||||
typedef unsigned long int khronos_uintptr_t;
|
||||
typedef signed long int khronos_ssize_t;
|
||||
typedef unsigned long int khronos_usize_t;
|
||||
#endif
|
||||
|
||||
#if KHRONOS_SUPPORT_FLOAT
|
||||
/*
|
||||
* Float type
|
||||
*/
|
||||
typedef float khronos_float_t;
|
||||
#endif
|
||||
|
||||
#if KHRONOS_SUPPORT_INT64
|
||||
/* Time types
|
||||
*
|
||||
* These types can be used to represent a time interval in nanoseconds or
|
||||
* an absolute Unadjusted System Time. Unadjusted System Time is the number
|
||||
* of nanoseconds since some arbitrary system event (e.g. since the last
|
||||
* time the system booted). The Unadjusted System Time is an unsigned
|
||||
* 64 bit value that wraps back to 0 every 584 years. Time intervals
|
||||
* may be either signed or unsigned.
|
||||
*/
|
||||
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
|
||||
typedef khronos_int64_t khronos_stime_nanoseconds_t;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Dummy value used to pad enum types to 32 bits.
|
||||
*/
|
||||
#ifndef KHRONOS_MAX_ENUM
|
||||
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enumerated boolean type
|
||||
*
|
||||
* Values other than zero should be considered to be true. Therefore
|
||||
* comparisons should not be made against KHRONOS_TRUE.
|
||||
*/
|
||||
typedef enum {
|
||||
KHRONOS_FALSE = 0,
|
||||
KHRONOS_TRUE = 1,
|
||||
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
|
||||
} khronos_boolean_enum_t;
|
||||
|
||||
#endif /* __khrplatform_h_ */
|
||||
5163
samples/external/GLAD/include/glad/glad.h
vendored
Normal file
5163
samples/external/GLAD/include/glad/glad.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
28
samples/external/GLAD/lib/cmake/glad/gladConfig.cmake
vendored
Normal file
28
samples/external/GLAD/lib/cmake/glad/gladConfig.cmake
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() #######
|
||||
####### Any changes to this file will be overwritten by the next CMake run ####
|
||||
####### The input file was Config.cmake.in ########
|
||||
|
||||
get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE)
|
||||
|
||||
macro(set_and_check _var _file)
|
||||
set(${_var} "${_file}")
|
||||
if(NOT EXISTS "${_file}")
|
||||
message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(check_required_components _NAME)
|
||||
foreach(comp ${${_NAME}_FIND_COMPONENTS})
|
||||
if(NOT ${_NAME}_${comp}_FOUND)
|
||||
if(${_NAME}_FIND_REQUIRED_${comp})
|
||||
set(${_NAME}_FOUND FALSE)
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
####################################################################################
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/gladTargets.cmake")
|
||||
check_required_components(glad)
|
||||
46
samples/external/GLAD/lib/cmake/glad/gladConfigVersion.cmake
vendored
Normal file
46
samples/external/GLAD/lib/cmake/glad/gladConfigVersion.cmake
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
# This is a basic version file for the Config-mode of find_package().
|
||||
# It is used by write_basic_package_version_file() as input file for configure_file()
|
||||
# to create a version-file which can be installed along a config.cmake file.
|
||||
#
|
||||
# The created file sets PACKAGE_VERSION_EXACT if the current version string and
|
||||
# the requested version string are exactly the same and it sets
|
||||
# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version,
|
||||
# but only if the requested major version is the same as the current one.
|
||||
# The variable CVF_VERSION must be set before calling configure_file().
|
||||
|
||||
|
||||
set(PACKAGE_VERSION "0.1.29")
|
||||
|
||||
if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
|
||||
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||
else()
|
||||
|
||||
if("0.1.29" MATCHES "^([0-9]+)\\.")
|
||||
set(CVF_VERSION_MAJOR "${CMAKE_MATCH_1}")
|
||||
else()
|
||||
set(CVF_VERSION_MAJOR "0.1.29")
|
||||
endif()
|
||||
|
||||
if(PACKAGE_FIND_VERSION_MAJOR STREQUAL CVF_VERSION_MAJOR)
|
||||
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||
else()
|
||||
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||
endif()
|
||||
|
||||
if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
|
||||
set(PACKAGE_VERSION_EXACT TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
|
||||
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
|
||||
if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "8")
|
||||
math(EXPR installedBits "8 * 8")
|
||||
set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
|
||||
set(PACKAGE_VERSION_UNSUITABLE TRUE)
|
||||
endif()
|
||||
19
samples/external/GLAD/lib/cmake/glad/gladTargets-debug.cmake
vendored
Normal file
19
samples/external/GLAD/lib/cmake/glad/gladTargets-debug.cmake
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
#----------------------------------------------------------------
|
||||
# Generated CMake target import file for configuration "Debug".
|
||||
#----------------------------------------------------------------
|
||||
|
||||
# Commands may need to know the format version.
|
||||
set(CMAKE_IMPORT_FILE_VERSION 1)
|
||||
|
||||
# Import target "glad::glad" for configuration "Debug"
|
||||
set_property(TARGET glad::glad APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
|
||||
set_target_properties(glad::glad PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
|
||||
IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/glad.lib"
|
||||
)
|
||||
|
||||
list(APPEND _IMPORT_CHECK_TARGETS glad::glad )
|
||||
list(APPEND _IMPORT_CHECK_FILES_FOR_glad::glad "${_IMPORT_PREFIX}/lib/glad.lib" )
|
||||
|
||||
# Commands beyond this point should not need to know the version.
|
||||
set(CMAKE_IMPORT_FILE_VERSION)
|
||||
19
samples/external/GLAD/lib/cmake/glad/gladTargets-release.cmake
vendored
Normal file
19
samples/external/GLAD/lib/cmake/glad/gladTargets-release.cmake
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
#----------------------------------------------------------------
|
||||
# Generated CMake target import file for configuration "Release".
|
||||
#----------------------------------------------------------------
|
||||
|
||||
# Commands may need to know the format version.
|
||||
set(CMAKE_IMPORT_FILE_VERSION 1)
|
||||
|
||||
# Import target "glad::glad" for configuration "Release"
|
||||
set_property(TARGET glad::glad APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
|
||||
set_target_properties(glad::glad PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
|
||||
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/glad.lib"
|
||||
)
|
||||
|
||||
list(APPEND _IMPORT_CHECK_TARGETS glad::glad )
|
||||
list(APPEND _IMPORT_CHECK_FILES_FOR_glad::glad "${_IMPORT_PREFIX}/lib/glad.lib" )
|
||||
|
||||
# Commands beyond this point should not need to know the version.
|
||||
set(CMAKE_IMPORT_FILE_VERSION)
|
||||
94
samples/external/GLAD/lib/cmake/glad/gladTargets.cmake
vendored
Normal file
94
samples/external/GLAD/lib/cmake/glad/gladTargets.cmake
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
# Generated by CMake
|
||||
|
||||
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.5)
|
||||
message(FATAL_ERROR "CMake >= 2.6.0 required")
|
||||
endif()
|
||||
cmake_policy(PUSH)
|
||||
cmake_policy(VERSION 2.6)
|
||||
#----------------------------------------------------------------
|
||||
# Generated CMake target import file.
|
||||
#----------------------------------------------------------------
|
||||
|
||||
# Commands may need to know the format version.
|
||||
set(CMAKE_IMPORT_FILE_VERSION 1)
|
||||
|
||||
# Protect against multiple inclusion, which would fail when already imported targets are added once more.
|
||||
set(_targetsDefined)
|
||||
set(_targetsNotDefined)
|
||||
set(_expectedTargets)
|
||||
foreach(_expectedTarget glad::glad)
|
||||
list(APPEND _expectedTargets ${_expectedTarget})
|
||||
if(NOT TARGET ${_expectedTarget})
|
||||
list(APPEND _targetsNotDefined ${_expectedTarget})
|
||||
endif()
|
||||
if(TARGET ${_expectedTarget})
|
||||
list(APPEND _targetsDefined ${_expectedTarget})
|
||||
endif()
|
||||
endforeach()
|
||||
if("${_targetsDefined}" STREQUAL "${_expectedTargets}")
|
||||
unset(_targetsDefined)
|
||||
unset(_targetsNotDefined)
|
||||
unset(_expectedTargets)
|
||||
set(CMAKE_IMPORT_FILE_VERSION)
|
||||
cmake_policy(POP)
|
||||
return()
|
||||
endif()
|
||||
if(NOT "${_targetsDefined}" STREQUAL "")
|
||||
message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n")
|
||||
endif()
|
||||
unset(_targetsDefined)
|
||||
unset(_targetsNotDefined)
|
||||
unset(_expectedTargets)
|
||||
|
||||
|
||||
# Compute the installation prefix relative to this file.
|
||||
get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
|
||||
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
|
||||
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
|
||||
if(_IMPORT_PREFIX STREQUAL "/")
|
||||
set(_IMPORT_PREFIX "")
|
||||
endif()
|
||||
|
||||
# Create imported target glad::glad
|
||||
add_library(glad::glad STATIC IMPORTED)
|
||||
|
||||
set_target_properties(glad::glad PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include/glad;${_IMPORT_PREFIX}/include"
|
||||
)
|
||||
|
||||
# Load information for each installed configuration.
|
||||
get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||
file(GLOB CONFIG_FILES "${_DIR}/gladTargets-*.cmake")
|
||||
foreach(f ${CONFIG_FILES})
|
||||
include(${f})
|
||||
endforeach()
|
||||
|
||||
# Cleanup temporary variables.
|
||||
set(_IMPORT_PREFIX)
|
||||
|
||||
# Loop over all imported files and verify that they actually exist
|
||||
foreach(target ${_IMPORT_CHECK_TARGETS} )
|
||||
foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} )
|
||||
if(NOT EXISTS "${file}" )
|
||||
message(FATAL_ERROR "The imported target \"${target}\" references the file
|
||||
\"${file}\"
|
||||
but this file does not exist. Possible reasons include:
|
||||
* The file was deleted, renamed, or moved to another location.
|
||||
* An install or uninstall procedure did not complete successfully.
|
||||
* The installation package was faulty and contained
|
||||
\"${CMAKE_CURRENT_LIST_FILE}\"
|
||||
but not all the files it references.
|
||||
")
|
||||
endif()
|
||||
endforeach()
|
||||
unset(_IMPORT_CHECK_FILES_FOR_${target})
|
||||
endforeach()
|
||||
unset(_IMPORT_CHECK_TARGETS)
|
||||
|
||||
# This file does not depend on other imported targets which have
|
||||
# been exported from the same project but in a separate export set.
|
||||
|
||||
# Commands beyond this point should not need to know the version.
|
||||
set(CMAKE_IMPORT_FILE_VERSION)
|
||||
cmake_policy(POP)
|
||||
BIN
samples/external/GLAD/lib/glad.lib
vendored
Normal file
BIN
samples/external/GLAD/lib/glad.lib
vendored
Normal file
Binary file not shown.
4248
samples/external/GLFW/include/GLFW/glfw3.h
vendored
Normal file
4248
samples/external/GLFW/include/GLFW/glfw3.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
456
samples/external/GLFW/include/GLFW/glfw3native.h
vendored
Normal file
456
samples/external/GLFW/include/GLFW/glfw3native.h
vendored
Normal file
@@ -0,0 +1,456 @@
|
||||
/*************************************************************************
|
||||
* GLFW 3.2 - www.glfw.org
|
||||
* A library for OpenGL, window and input
|
||||
*------------------------------------------------------------------------
|
||||
* Copyright (c) 2002-2006 Marcus Geelnard
|
||||
* Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would
|
||||
* be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef _glfw3_native_h_
|
||||
#define _glfw3_native_h_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* Doxygen documentation
|
||||
*************************************************************************/
|
||||
|
||||
/*! @file glfw3native.h
|
||||
* @brief The header of the native access functions.
|
||||
*
|
||||
* This is the header file of the native access functions. See @ref native for
|
||||
* more information.
|
||||
*/
|
||||
/*! @defgroup native Native access
|
||||
*
|
||||
* **By using the native access functions you assert that you know what you're
|
||||
* doing and how to fix problems caused by using them. If you don't, you
|
||||
* shouldn't be using them.**
|
||||
*
|
||||
* Before the inclusion of @ref glfw3native.h, you may define exactly one
|
||||
* window system API macro and zero or more context creation API macros.
|
||||
*
|
||||
* The chosen backends must match those the library was compiled for. Failure
|
||||
* to do this will cause a link-time error.
|
||||
*
|
||||
* The available window API macros are:
|
||||
* * `GLFW_EXPOSE_NATIVE_WIN32`
|
||||
* * `GLFW_EXPOSE_NATIVE_COCOA`
|
||||
* * `GLFW_EXPOSE_NATIVE_X11`
|
||||
* * `GLFW_EXPOSE_NATIVE_WAYLAND`
|
||||
* * `GLFW_EXPOSE_NATIVE_MIR`
|
||||
*
|
||||
* The available context API macros are:
|
||||
* * `GLFW_EXPOSE_NATIVE_WGL`
|
||||
* * `GLFW_EXPOSE_NATIVE_NSGL`
|
||||
* * `GLFW_EXPOSE_NATIVE_GLX`
|
||||
* * `GLFW_EXPOSE_NATIVE_EGL`
|
||||
*
|
||||
* These macros select which of the native access functions that are declared
|
||||
* and which platform-specific headers to include. It is then up your (by
|
||||
* definition platform-specific) code to handle which of these should be
|
||||
* defined.
|
||||
*/
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* System headers and types
|
||||
*************************************************************************/
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_WIN32)
|
||||
// This is a workaround for the fact that glfw3.h needs to export APIENTRY (for
|
||||
// example to allow applications to correctly declare a GL_ARB_debug_output
|
||||
// callback) but windows.h assumes no one will define APIENTRY before it does
|
||||
#undef APIENTRY
|
||||
#include <windows.h>
|
||||
#elif defined(GLFW_EXPOSE_NATIVE_COCOA)
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#if defined(__OBJC__)
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#else
|
||||
typedef void* id;
|
||||
#endif
|
||||
#elif defined(GLFW_EXPOSE_NATIVE_X11)
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#elif defined(GLFW_EXPOSE_NATIVE_WAYLAND)
|
||||
#include <wayland-client.h>
|
||||
#elif defined(GLFW_EXPOSE_NATIVE_MIR)
|
||||
#include <mir_toolkit/mir_client_library.h>
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_WGL)
|
||||
/* WGL is declared by windows.h */
|
||||
#endif
|
||||
#if defined(GLFW_EXPOSE_NATIVE_NSGL)
|
||||
/* NSGL is declared by Cocoa.h */
|
||||
#endif
|
||||
#if defined(GLFW_EXPOSE_NATIVE_GLX)
|
||||
#include <GL/glx.h>
|
||||
#endif
|
||||
#if defined(GLFW_EXPOSE_NATIVE_EGL)
|
||||
#include <EGL/egl.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* Functions
|
||||
*************************************************************************/
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_WIN32)
|
||||
/*! @brief Returns the adapter device name of the specified monitor.
|
||||
*
|
||||
* @return The UTF-8 encoded adapter device name (for example `\\.\DISPLAY1`)
|
||||
* of the specified monitor, or `NULL` if an [error](@ref error_handling)
|
||||
* occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.1.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Returns the display device name of the specified monitor.
|
||||
*
|
||||
* @return The UTF-8 encoded display device name (for example
|
||||
* `\\.\DISPLAY1\Monitor0`) of the specified monitor, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.1.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Returns the `HWND` of the specified window.
|
||||
*
|
||||
* @return The `HWND` of the specified window, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI HWND glfwGetWin32Window(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_WGL)
|
||||
/*! @brief Returns the `HGLRC` of the specified window.
|
||||
*
|
||||
* @return The `HGLRC` of the specified window, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_COCOA)
|
||||
/*! @brief Returns the `CGDirectDisplayID` of the specified monitor.
|
||||
*
|
||||
* @return The `CGDirectDisplayID` of the specified monitor, or
|
||||
* `kCGNullDirectDisplay` if an [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.1.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Returns the `NSWindow` of the specified window.
|
||||
*
|
||||
* @return The `NSWindow` of the specified window, or `nil` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI id glfwGetCocoaWindow(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_NSGL)
|
||||
/*! @brief Returns the `NSOpenGLContext` of the specified window.
|
||||
*
|
||||
* @return The `NSOpenGLContext` of the specified window, or `nil` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI id glfwGetNSGLContext(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_X11)
|
||||
/*! @brief Returns the `Display` used by GLFW.
|
||||
*
|
||||
* @return The `Display` used by GLFW, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI Display* glfwGetX11Display(void);
|
||||
|
||||
/*! @brief Returns the `RRCrtc` of the specified monitor.
|
||||
*
|
||||
* @return The `RRCrtc` of the specified monitor, or `None` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.1.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Returns the `RROutput` of the specified monitor.
|
||||
*
|
||||
* @return The `RROutput` of the specified monitor, or `None` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.1.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Returns the `Window` of the specified window.
|
||||
*
|
||||
* @return The `Window` of the specified window, or `None` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI Window glfwGetX11Window(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_GLX)
|
||||
/*! @brief Returns the `GLXContext` of the specified window.
|
||||
*
|
||||
* @return The `GLXContext` of the specified window, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* window);
|
||||
|
||||
/*! @brief Returns the `GLXWindow` of the specified window.
|
||||
*
|
||||
* @return The `GLXWindow` of the specified window, or `None` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.2.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_WAYLAND)
|
||||
/*! @brief Returns the `struct wl_display*` used by GLFW.
|
||||
*
|
||||
* @return The `struct wl_display*` used by GLFW, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.2.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI struct wl_display* glfwGetWaylandDisplay(void);
|
||||
|
||||
/*! @brief Returns the `struct wl_output*` of the specified monitor.
|
||||
*
|
||||
* @return The `struct wl_output*` of the specified monitor, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.2.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Returns the main `struct wl_surface*` of the specified window.
|
||||
*
|
||||
* @return The main `struct wl_surface*` of the specified window, or `NULL` if
|
||||
* an [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.2.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_MIR)
|
||||
/*! @brief Returns the `MirConnection*` used by GLFW.
|
||||
*
|
||||
* @return The `MirConnection*` used by GLFW, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.2.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI MirConnection* glfwGetMirDisplay(void);
|
||||
|
||||
/*! @brief Returns the Mir output ID of the specified monitor.
|
||||
*
|
||||
* @return The Mir output ID of the specified monitor, or zero if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.2.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI int glfwGetMirMonitor(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Returns the `MirSurface*` of the specified window.
|
||||
*
|
||||
* @return The `MirSurface*` of the specified window, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.2.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI MirSurface* glfwGetMirWindow(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_EGL)
|
||||
/*! @brief Returns the `EGLDisplay` used by GLFW.
|
||||
*
|
||||
* @return The `EGLDisplay` used by GLFW, or `EGL_NO_DISPLAY` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI EGLDisplay glfwGetEGLDisplay(void);
|
||||
|
||||
/*! @brief Returns the `EGLContext` of the specified window.
|
||||
*
|
||||
* @return The `EGLContext` of the specified window, or `EGL_NO_CONTEXT` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* window);
|
||||
|
||||
/*! @brief Returns the `EGLSurface` of the specified window.
|
||||
*
|
||||
* @return The `EGLSurface` of the specified window, or `EGL_NO_SURFACE` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _glfw3_native_h_ */
|
||||
|
||||
1
samples/external/GLFW/lib/cmake/glfw3/glfw3Config.cmake
vendored
Normal file
1
samples/external/GLFW/lib/cmake/glfw3/glfw3Config.cmake
vendored
Normal file
@@ -0,0 +1 @@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/glfw3Targets.cmake")
|
||||
46
samples/external/GLFW/lib/cmake/glfw3/glfw3ConfigVersion.cmake
vendored
Normal file
46
samples/external/GLFW/lib/cmake/glfw3/glfw3ConfigVersion.cmake
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
# This is a basic version file for the Config-mode of find_package().
|
||||
# It is used by write_basic_package_version_file() as input file for configure_file()
|
||||
# to create a version-file which can be installed along a config.cmake file.
|
||||
#
|
||||
# The created file sets PACKAGE_VERSION_EXACT if the current version string and
|
||||
# the requested version string are exactly the same and it sets
|
||||
# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version,
|
||||
# but only if the requested major version is the same as the current one.
|
||||
# The variable CVF_VERSION must be set before calling configure_file().
|
||||
|
||||
|
||||
set(PACKAGE_VERSION "3.2.1")
|
||||
|
||||
if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
|
||||
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||
else()
|
||||
|
||||
if("3.2.1" MATCHES "^([0-9]+)\\.")
|
||||
set(CVF_VERSION_MAJOR "${CMAKE_MATCH_1}")
|
||||
else()
|
||||
set(CVF_VERSION_MAJOR "3.2.1")
|
||||
endif()
|
||||
|
||||
if(PACKAGE_FIND_VERSION_MAJOR STREQUAL CVF_VERSION_MAJOR)
|
||||
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||
else()
|
||||
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||
endif()
|
||||
|
||||
if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
|
||||
set(PACKAGE_VERSION_EXACT TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
|
||||
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
|
||||
if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "8")
|
||||
math(EXPR installedBits "8 * 8")
|
||||
set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
|
||||
set(PACKAGE_VERSION_UNSUITABLE TRUE)
|
||||
endif()
|
||||
19
samples/external/GLFW/lib/cmake/glfw3/glfw3Targets-debug.cmake
vendored
Normal file
19
samples/external/GLFW/lib/cmake/glfw3/glfw3Targets-debug.cmake
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
#----------------------------------------------------------------
|
||||
# Generated CMake target import file for configuration "Debug".
|
||||
#----------------------------------------------------------------
|
||||
|
||||
# Commands may need to know the format version.
|
||||
set(CMAKE_IMPORT_FILE_VERSION 1)
|
||||
|
||||
# Import target "glfw" for configuration "Debug"
|
||||
set_property(TARGET glfw APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
|
||||
set_target_properties(glfw PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
|
||||
IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/glfw3.lib"
|
||||
)
|
||||
|
||||
list(APPEND _IMPORT_CHECK_TARGETS glfw )
|
||||
list(APPEND _IMPORT_CHECK_FILES_FOR_glfw "${_IMPORT_PREFIX}/lib/glfw3.lib" )
|
||||
|
||||
# Commands beyond this point should not need to know the version.
|
||||
set(CMAKE_IMPORT_FILE_VERSION)
|
||||
19
samples/external/GLFW/lib/cmake/glfw3/glfw3Targets-release.cmake
vendored
Normal file
19
samples/external/GLFW/lib/cmake/glfw3/glfw3Targets-release.cmake
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
#----------------------------------------------------------------
|
||||
# Generated CMake target import file for configuration "Release".
|
||||
#----------------------------------------------------------------
|
||||
|
||||
# Commands may need to know the format version.
|
||||
set(CMAKE_IMPORT_FILE_VERSION 1)
|
||||
|
||||
# Import target "glfw" for configuration "Release"
|
||||
set_property(TARGET glfw APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
|
||||
set_target_properties(glfw PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
|
||||
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/glfw3.lib"
|
||||
)
|
||||
|
||||
list(APPEND _IMPORT_CHECK_TARGETS glfw )
|
||||
list(APPEND _IMPORT_CHECK_FILES_FOR_glfw "${_IMPORT_PREFIX}/lib/glfw3.lib" )
|
||||
|
||||
# Commands beyond this point should not need to know the version.
|
||||
set(CMAKE_IMPORT_FILE_VERSION)
|
||||
94
samples/external/GLFW/lib/cmake/glfw3/glfw3Targets.cmake
vendored
Normal file
94
samples/external/GLFW/lib/cmake/glfw3/glfw3Targets.cmake
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
# Generated by CMake
|
||||
|
||||
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.5)
|
||||
message(FATAL_ERROR "CMake >= 2.6.0 required")
|
||||
endif()
|
||||
cmake_policy(PUSH)
|
||||
cmake_policy(VERSION 2.6)
|
||||
#----------------------------------------------------------------
|
||||
# Generated CMake target import file.
|
||||
#----------------------------------------------------------------
|
||||
|
||||
# Commands may need to know the format version.
|
||||
set(CMAKE_IMPORT_FILE_VERSION 1)
|
||||
|
||||
# Protect against multiple inclusion, which would fail when already imported targets are added once more.
|
||||
set(_targetsDefined)
|
||||
set(_targetsNotDefined)
|
||||
set(_expectedTargets)
|
||||
foreach(_expectedTarget glfw)
|
||||
list(APPEND _expectedTargets ${_expectedTarget})
|
||||
if(NOT TARGET ${_expectedTarget})
|
||||
list(APPEND _targetsNotDefined ${_expectedTarget})
|
||||
endif()
|
||||
if(TARGET ${_expectedTarget})
|
||||
list(APPEND _targetsDefined ${_expectedTarget})
|
||||
endif()
|
||||
endforeach()
|
||||
if("${_targetsDefined}" STREQUAL "${_expectedTargets}")
|
||||
unset(_targetsDefined)
|
||||
unset(_targetsNotDefined)
|
||||
unset(_expectedTargets)
|
||||
set(CMAKE_IMPORT_FILE_VERSION)
|
||||
cmake_policy(POP)
|
||||
return()
|
||||
endif()
|
||||
if(NOT "${_targetsDefined}" STREQUAL "")
|
||||
message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n")
|
||||
endif()
|
||||
unset(_targetsDefined)
|
||||
unset(_targetsNotDefined)
|
||||
unset(_expectedTargets)
|
||||
|
||||
|
||||
# Compute the installation prefix relative to this file.
|
||||
get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
|
||||
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
|
||||
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
|
||||
if(_IMPORT_PREFIX STREQUAL "/")
|
||||
set(_IMPORT_PREFIX "")
|
||||
endif()
|
||||
|
||||
# Create imported target glfw
|
||||
add_library(glfw STATIC IMPORTED)
|
||||
|
||||
set_target_properties(glfw PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include"
|
||||
)
|
||||
|
||||
# Load information for each installed configuration.
|
||||
get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||
file(GLOB CONFIG_FILES "${_DIR}/glfw3Targets-*.cmake")
|
||||
foreach(f ${CONFIG_FILES})
|
||||
include(${f})
|
||||
endforeach()
|
||||
|
||||
# Cleanup temporary variables.
|
||||
set(_IMPORT_PREFIX)
|
||||
|
||||
# Loop over all imported files and verify that they actually exist
|
||||
foreach(target ${_IMPORT_CHECK_TARGETS} )
|
||||
foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} )
|
||||
if(NOT EXISTS "${file}" )
|
||||
message(FATAL_ERROR "The imported target \"${target}\" references the file
|
||||
\"${file}\"
|
||||
but this file does not exist. Possible reasons include:
|
||||
* The file was deleted, renamed, or moved to another location.
|
||||
* An install or uninstall procedure did not complete successfully.
|
||||
* The installation package was faulty and contained
|
||||
\"${CMAKE_CURRENT_LIST_FILE}\"
|
||||
but not all the files it references.
|
||||
")
|
||||
endif()
|
||||
endforeach()
|
||||
unset(_IMPORT_CHECK_FILES_FOR_${target})
|
||||
endforeach()
|
||||
unset(_IMPORT_CHECK_TARGETS)
|
||||
|
||||
# This file does not depend on other imported targets which have
|
||||
# been exported from the same project but in a separate export set.
|
||||
|
||||
# Commands beyond this point should not need to know the version.
|
||||
set(CMAKE_IMPORT_FILE_VERSION)
|
||||
cmake_policy(POP)
|
||||
BIN
samples/external/GLFW/lib/glfw3.lib
vendored
Normal file
BIN
samples/external/GLFW/lib/glfw3.lib
vendored
Normal file
Binary file not shown.
13
samples/external/GLFW/lib/pkgconfig/glfw3.pc
vendored
Normal file
13
samples/external/GLFW/lib/pkgconfig/glfw3.pc
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
prefix=C:/Users/kturkowski/ext/GLFW
|
||||
exec_prefix=${prefix}
|
||||
includedir=${prefix}/include
|
||||
libdir=${exec_prefix}/lib
|
||||
|
||||
Name: GLFW
|
||||
Description: A multi-platform library for OpenGL, window and input
|
||||
Version: 3.2.1
|
||||
URL: http://www.glfw.org/
|
||||
Requires.private:
|
||||
Libs: -L${libdir} -lglfw3
|
||||
Libs.private: -lgdi32
|
||||
Cflags: -I${includedir}
|
||||
21
samples/external/Imgui/imgui-docking/LICENSE.txt
vendored
Normal file
21
samples/external/Imgui/imgui-docking/LICENSE.txt
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2021 Omar Cornut
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
478
samples/external/Imgui/imgui-docking/backends/imgui_impl_allegro5.cpp
vendored
Normal file
478
samples/external/Imgui/imgui-docking/backends/imgui_impl_allegro5.cpp
vendored
Normal file
@@ -0,0 +1,478 @@
|
||||
// dear imgui: Renderer + Platform Backend for Allegro 5
|
||||
// (Info: Allegro 5 is a cross-platform general purpose library for handling windows, inputs, graphics, etc.)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Platform: Clipboard support (from Allegro 5.1.12)
|
||||
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// Issues:
|
||||
// [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually.
|
||||
// [ ] Platform: Missing gamepad support.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2021-08-17: Calling io.AddFocusEvent() on ALLEGRO_EVENT_DISPLAY_SWITCH_OUT/ALLEGRO_EVENT_DISPLAY_SWITCH_IN events.
|
||||
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||
// 2021-05-19: Renderer: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||
// 2021-02-18: Change blending equation to preserve alpha in output buffer.
|
||||
// 2020-08-10: Inputs: Fixed horizontal mouse wheel direction.
|
||||
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
|
||||
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
|
||||
// 2019-05-11: Inputs: Don't filter character value from ALLEGRO_EVENT_KEY_CHAR before calling AddInputCharacter().
|
||||
// 2019-04-30: Renderer: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||
// 2018-11-30: Platform: Added touchscreen support.
|
||||
// 2018-11-30: Misc: Setting up io.BackendPlatformName/io.BackendRendererName so they can be displayed in the About Window.
|
||||
// 2018-06-13: Platform: Added clipboard support (from Allegro 5.1.12).
|
||||
// 2018-06-13: Renderer: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
||||
// 2018-06-13: Renderer: Backup/restore transform and clipping rectangle.
|
||||
// 2018-06-11: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
|
||||
// 2018-04-18: Misc: Renamed file from imgui_impl_a5.cpp to imgui_impl_allegro5.cpp.
|
||||
// 2018-04-18: Misc: Added support for 32-bit vertex indices to avoid conversion at runtime. Added imconfig_allegro5.h to enforce 32-bit indices when included from imgui.h.
|
||||
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplAllegro5_RenderDrawData() in the .h file so you can call it yourself.
|
||||
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
|
||||
|
||||
#include <stdint.h> // uint64_t
|
||||
#include <cstring> // memcpy
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_allegro5.h"
|
||||
|
||||
// Allegro
|
||||
#include <allegro5/allegro.h>
|
||||
#include <allegro5/allegro_primitives.h>
|
||||
#ifdef _WIN32
|
||||
#include <allegro5/allegro_windows.h>
|
||||
#endif
|
||||
#define ALLEGRO_HAS_CLIPBOARD (ALLEGRO_VERSION_INT >= ((5 << 24) | (1 << 16) | (12 << 8))) // Clipboard only supported from Allegro 5.1.12
|
||||
|
||||
// Visual Studio warnings
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (disable: 4127) // condition expression is constant
|
||||
#endif
|
||||
|
||||
// Allegro Data
|
||||
struct ImGui_ImplAllegro5_Data
|
||||
{
|
||||
ALLEGRO_DISPLAY* Display;
|
||||
ALLEGRO_BITMAP* Texture;
|
||||
double Time;
|
||||
ALLEGRO_MOUSE_CURSOR* MouseCursorInvisible;
|
||||
ALLEGRO_VERTEX_DECL* VertexDecl;
|
||||
char* ClipboardTextData;
|
||||
|
||||
ImGui_ImplAllegro5_Data() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
|
||||
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||
// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
|
||||
static ImGui_ImplAllegro5_Data* ImGui_ImplAllegro5_GetBackendData() { return ImGui::GetCurrentContext() ? (ImGui_ImplAllegro5_Data*)ImGui::GetIO().BackendPlatformUserData : NULL; }
|
||||
|
||||
struct ImDrawVertAllegro
|
||||
{
|
||||
ImVec2 pos;
|
||||
ImVec2 uv;
|
||||
ALLEGRO_COLOR col;
|
||||
};
|
||||
|
||||
static void ImGui_ImplAllegro5_SetupRenderState(ImDrawData* draw_data)
|
||||
{
|
||||
// Setup blending
|
||||
al_set_separate_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);
|
||||
|
||||
// Setup orthographic projection matrix
|
||||
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right).
|
||||
{
|
||||
float L = draw_data->DisplayPos.x;
|
||||
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||
float T = draw_data->DisplayPos.y;
|
||||
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
|
||||
ALLEGRO_TRANSFORM transform;
|
||||
al_identity_transform(&transform);
|
||||
al_use_transform(&transform);
|
||||
al_orthographic_transform(&transform, L, T, 1.0f, R, B, -1.0f);
|
||||
al_use_projection_transform(&transform);
|
||||
}
|
||||
}
|
||||
|
||||
// Render function.
|
||||
void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data)
|
||||
{
|
||||
// Avoid rendering when minimized
|
||||
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
||||
return;
|
||||
|
||||
// Backup Allegro state that will be modified
|
||||
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||
ALLEGRO_TRANSFORM last_transform = *al_get_current_transform();
|
||||
ALLEGRO_TRANSFORM last_projection_transform = *al_get_current_projection_transform();
|
||||
int last_clip_x, last_clip_y, last_clip_w, last_clip_h;
|
||||
al_get_clipping_rectangle(&last_clip_x, &last_clip_y, &last_clip_w, &last_clip_h);
|
||||
int last_blender_op, last_blender_src, last_blender_dst;
|
||||
al_get_blender(&last_blender_op, &last_blender_src, &last_blender_dst);
|
||||
|
||||
// Setup desired render state
|
||||
ImGui_ImplAllegro5_SetupRenderState(draw_data);
|
||||
|
||||
// Render command lists
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
|
||||
// Allegro's implementation of al_draw_indexed_prim() for DX9 is completely broken. Unindex our buffers ourselves.
|
||||
// FIXME-OPT: Unfortunately Allegro doesn't support 32-bit packed colors so we have to convert them to 4 float as well..
|
||||
static ImVector<ImDrawVertAllegro> vertices;
|
||||
vertices.resize(cmd_list->IdxBuffer.Size);
|
||||
for (int i = 0; i < cmd_list->IdxBuffer.Size; i++)
|
||||
{
|
||||
const ImDrawVert* src_v = &cmd_list->VtxBuffer[cmd_list->IdxBuffer[i]];
|
||||
ImDrawVertAllegro* dst_v = &vertices[i];
|
||||
dst_v->pos = src_v->pos;
|
||||
dst_v->uv = src_v->uv;
|
||||
unsigned char* c = (unsigned char*)&src_v->col;
|
||||
dst_v->col = al_map_rgba(c[0], c[1], c[2], c[3]);
|
||||
}
|
||||
|
||||
const int* indices = NULL;
|
||||
if (sizeof(ImDrawIdx) == 2)
|
||||
{
|
||||
// FIXME-OPT: Unfortunately Allegro doesn't support 16-bit indices.. You can '#define ImDrawIdx int' in imconfig.h to request Dear ImGui to output 32-bit indices.
|
||||
// Otherwise, we convert them from 16-bit to 32-bit at runtime here, which works perfectly but is a little wasteful.
|
||||
static ImVector<int> indices_converted;
|
||||
indices_converted.resize(cmd_list->IdxBuffer.Size);
|
||||
for (int i = 0; i < cmd_list->IdxBuffer.Size; ++i)
|
||||
indices_converted[i] = (int)cmd_list->IdxBuffer.Data[i];
|
||||
indices = indices_converted.Data;
|
||||
}
|
||||
else if (sizeof(ImDrawIdx) == 4)
|
||||
{
|
||||
indices = (const int*)cmd_list->IdxBuffer.Data;
|
||||
}
|
||||
|
||||
// Render command lists
|
||||
int idx_offset = 0;
|
||||
ImVec2 clip_off = draw_data->DisplayPos;
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||
if (pcmd->UserCallback)
|
||||
{
|
||||
// User callback, registered via ImDrawList::AddCallback()
|
||||
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||
ImGui_ImplAllegro5_SetupRenderState(draw_data);
|
||||
else
|
||||
pcmd->UserCallback(cmd_list, pcmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
|
||||
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
|
||||
if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
|
||||
continue;
|
||||
|
||||
// Apply scissor/clipping rectangle, Draw
|
||||
ALLEGRO_BITMAP* texture = (ALLEGRO_BITMAP*)pcmd->GetTexID();
|
||||
al_set_clipping_rectangle(clip_min.x, clip_min.y, clip_max.x - clip_min.x, clip_max.y - clip_min.y);
|
||||
al_draw_prim(&vertices[0], bd->VertexDecl, texture, idx_offset, idx_offset + pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST);
|
||||
}
|
||||
idx_offset += pcmd->ElemCount;
|
||||
}
|
||||
}
|
||||
|
||||
// Restore modified Allegro state
|
||||
al_set_blender(last_blender_op, last_blender_src, last_blender_dst);
|
||||
al_set_clipping_rectangle(last_clip_x, last_clip_y, last_clip_w, last_clip_h);
|
||||
al_use_transform(&last_transform);
|
||||
al_use_projection_transform(&last_projection_transform);
|
||||
}
|
||||
|
||||
bool ImGui_ImplAllegro5_CreateDeviceObjects()
|
||||
{
|
||||
// Build texture atlas
|
||||
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
unsigned char* pixels;
|
||||
int width, height;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||
|
||||
// Create texture
|
||||
int flags = al_get_new_bitmap_flags();
|
||||
int fmt = al_get_new_bitmap_format();
|
||||
al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP | ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR);
|
||||
al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE);
|
||||
ALLEGRO_BITMAP* img = al_create_bitmap(width, height);
|
||||
al_set_new_bitmap_flags(flags);
|
||||
al_set_new_bitmap_format(fmt);
|
||||
if (!img)
|
||||
return false;
|
||||
|
||||
ALLEGRO_LOCKED_REGION* locked_img = al_lock_bitmap(img, al_get_bitmap_format(img), ALLEGRO_LOCK_WRITEONLY);
|
||||
if (!locked_img)
|
||||
{
|
||||
al_destroy_bitmap(img);
|
||||
return false;
|
||||
}
|
||||
memcpy(locked_img->data, pixels, sizeof(int) * width * height);
|
||||
al_unlock_bitmap(img);
|
||||
|
||||
// Convert software texture to hardware texture.
|
||||
ALLEGRO_BITMAP* cloned_img = al_clone_bitmap(img);
|
||||
al_destroy_bitmap(img);
|
||||
if (!cloned_img)
|
||||
return false;
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->SetTexID((void*)cloned_img);
|
||||
bd->Texture = cloned_img;
|
||||
|
||||
// Create an invisible mouse cursor
|
||||
// Because al_hide_mouse_cursor() seems to mess up with the actual inputs..
|
||||
ALLEGRO_BITMAP* mouse_cursor = al_create_bitmap(8, 8);
|
||||
bd->MouseCursorInvisible = al_create_mouse_cursor(mouse_cursor, 0, 0);
|
||||
al_destroy_bitmap(mouse_cursor);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplAllegro5_InvalidateDeviceObjects()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||
if (bd->Texture)
|
||||
{
|
||||
io.Fonts->SetTexID(NULL);
|
||||
al_destroy_bitmap(bd->Texture);
|
||||
bd->Texture = NULL;
|
||||
}
|
||||
if (bd->MouseCursorInvisible)
|
||||
{
|
||||
al_destroy_mouse_cursor(bd->MouseCursorInvisible);
|
||||
bd->MouseCursorInvisible = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#if ALLEGRO_HAS_CLIPBOARD
|
||||
static const char* ImGui_ImplAllegro5_GetClipboardText(void*)
|
||||
{
|
||||
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||
if (bd->ClipboardTextData)
|
||||
al_free(bd->ClipboardTextData);
|
||||
bd->ClipboardTextData = al_get_clipboard_text(bd->Display);
|
||||
return bd->ClipboardTextData;
|
||||
}
|
||||
|
||||
static void ImGui_ImplAllegro5_SetClipboardText(void*, const char* text)
|
||||
{
|
||||
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||
al_set_clipboard_text(bd->Display, text);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IM_ASSERT(io.BackendPlatformUserData == NULL && "Already initialized a platform backend!");
|
||||
|
||||
// Setup backend capabilities flags
|
||||
ImGui_ImplAllegro5_Data* bd = IM_NEW(ImGui_ImplAllegro5_Data)();
|
||||
io.BackendPlatformUserData = (void*)bd;
|
||||
io.BackendPlatformName = io.BackendRendererName = "imgui_impl_allegro5";
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||
|
||||
bd->Display = display;
|
||||
|
||||
// Create custom vertex declaration.
|
||||
// Unfortunately Allegro doesn't support 32-bit packed colors so we have to convert them to 4 floats.
|
||||
// We still use a custom declaration to use 'ALLEGRO_PRIM_TEX_COORD' instead of 'ALLEGRO_PRIM_TEX_COORD_PIXEL' else we can't do a reliable conversion.
|
||||
ALLEGRO_VERTEX_ELEMENT elems[] =
|
||||
{
|
||||
{ ALLEGRO_PRIM_POSITION, ALLEGRO_PRIM_FLOAT_2, IM_OFFSETOF(ImDrawVertAllegro, pos) },
|
||||
{ ALLEGRO_PRIM_TEX_COORD, ALLEGRO_PRIM_FLOAT_2, IM_OFFSETOF(ImDrawVertAllegro, uv) },
|
||||
{ ALLEGRO_PRIM_COLOR_ATTR, 0, IM_OFFSETOF(ImDrawVertAllegro, col) },
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
bd->VertexDecl = al_create_vertex_decl(elems, sizeof(ImDrawVertAllegro));
|
||||
|
||||
io.KeyMap[ImGuiKey_Tab] = ALLEGRO_KEY_TAB;
|
||||
io.KeyMap[ImGuiKey_LeftArrow] = ALLEGRO_KEY_LEFT;
|
||||
io.KeyMap[ImGuiKey_RightArrow] = ALLEGRO_KEY_RIGHT;
|
||||
io.KeyMap[ImGuiKey_UpArrow] = ALLEGRO_KEY_UP;
|
||||
io.KeyMap[ImGuiKey_DownArrow] = ALLEGRO_KEY_DOWN;
|
||||
io.KeyMap[ImGuiKey_PageUp] = ALLEGRO_KEY_PGUP;
|
||||
io.KeyMap[ImGuiKey_PageDown] = ALLEGRO_KEY_PGDN;
|
||||
io.KeyMap[ImGuiKey_Home] = ALLEGRO_KEY_HOME;
|
||||
io.KeyMap[ImGuiKey_End] = ALLEGRO_KEY_END;
|
||||
io.KeyMap[ImGuiKey_Insert] = ALLEGRO_KEY_INSERT;
|
||||
io.KeyMap[ImGuiKey_Delete] = ALLEGRO_KEY_DELETE;
|
||||
io.KeyMap[ImGuiKey_Backspace] = ALLEGRO_KEY_BACKSPACE;
|
||||
io.KeyMap[ImGuiKey_Space] = ALLEGRO_KEY_SPACE;
|
||||
io.KeyMap[ImGuiKey_Enter] = ALLEGRO_KEY_ENTER;
|
||||
io.KeyMap[ImGuiKey_Escape] = ALLEGRO_KEY_ESCAPE;
|
||||
io.KeyMap[ImGuiKey_KeyPadEnter] = ALLEGRO_KEY_PAD_ENTER;
|
||||
io.KeyMap[ImGuiKey_A] = ALLEGRO_KEY_A;
|
||||
io.KeyMap[ImGuiKey_C] = ALLEGRO_KEY_C;
|
||||
io.KeyMap[ImGuiKey_V] = ALLEGRO_KEY_V;
|
||||
io.KeyMap[ImGuiKey_X] = ALLEGRO_KEY_X;
|
||||
io.KeyMap[ImGuiKey_Y] = ALLEGRO_KEY_Y;
|
||||
io.KeyMap[ImGuiKey_Z] = ALLEGRO_KEY_Z;
|
||||
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
||||
|
||||
#if ALLEGRO_HAS_CLIPBOARD
|
||||
io.SetClipboardTextFn = ImGui_ImplAllegro5_SetClipboardText;
|
||||
io.GetClipboardTextFn = ImGui_ImplAllegro5_GetClipboardText;
|
||||
io.ClipboardUserData = NULL;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplAllegro5_Shutdown()
|
||||
{
|
||||
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||
IM_ASSERT(bd != NULL && "No platform backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui_ImplAllegro5_InvalidateDeviceObjects();
|
||||
if (bd->VertexDecl)
|
||||
al_destroy_vertex_decl(bd->VertexDecl);
|
||||
if (bd->ClipboardTextData)
|
||||
al_free(bd->ClipboardTextData);
|
||||
|
||||
io.BackendPlatformUserData = NULL;
|
||||
io.BackendPlatformName = io.BackendRendererName = NULL;
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
|
||||
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
|
||||
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
|
||||
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
|
||||
bool ImGui_ImplAllegro5_ProcessEvent(ALLEGRO_EVENT* ev)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||
|
||||
switch (ev->type)
|
||||
{
|
||||
case ALLEGRO_EVENT_MOUSE_AXES:
|
||||
if (ev->mouse.display == bd->Display)
|
||||
{
|
||||
io.MouseWheel += ev->mouse.dz;
|
||||
io.MouseWheelH -= ev->mouse.dw;
|
||||
io.MousePos = ImVec2(ev->mouse.x, ev->mouse.y);
|
||||
}
|
||||
return true;
|
||||
case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
|
||||
case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
|
||||
if (ev->mouse.display == bd->Display && ev->mouse.button <= 5)
|
||||
io.MouseDown[ev->mouse.button - 1] = (ev->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN);
|
||||
return true;
|
||||
case ALLEGRO_EVENT_TOUCH_MOVE:
|
||||
if (ev->touch.display == bd->Display)
|
||||
io.MousePos = ImVec2(ev->touch.x, ev->touch.y);
|
||||
return true;
|
||||
case ALLEGRO_EVENT_TOUCH_BEGIN:
|
||||
case ALLEGRO_EVENT_TOUCH_END:
|
||||
case ALLEGRO_EVENT_TOUCH_CANCEL:
|
||||
if (ev->touch.display == bd->Display && ev->touch.primary)
|
||||
io.MouseDown[0] = (ev->type == ALLEGRO_EVENT_TOUCH_BEGIN);
|
||||
return true;
|
||||
case ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY:
|
||||
if (ev->mouse.display == bd->Display)
|
||||
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
||||
return true;
|
||||
case ALLEGRO_EVENT_KEY_CHAR:
|
||||
if (ev->keyboard.display == bd->Display)
|
||||
if (ev->keyboard.unichar != 0)
|
||||
io.AddInputCharacter((unsigned int)ev->keyboard.unichar);
|
||||
return true;
|
||||
case ALLEGRO_EVENT_KEY_DOWN:
|
||||
case ALLEGRO_EVENT_KEY_UP:
|
||||
if (ev->keyboard.display == bd->Display)
|
||||
io.KeysDown[ev->keyboard.keycode] = (ev->type == ALLEGRO_EVENT_KEY_DOWN);
|
||||
return true;
|
||||
case ALLEGRO_EVENT_DISPLAY_SWITCH_OUT:
|
||||
if (ev->display.source == bd->Display)
|
||||
io.AddFocusEvent(false);
|
||||
return true;
|
||||
case ALLEGRO_EVENT_DISPLAY_SWITCH_IN:
|
||||
if (ev->display.source == bd->Display)
|
||||
{
|
||||
io.AddFocusEvent(true);
|
||||
#if defined(ALLEGRO_UNSTABLE)
|
||||
al_clear_keyboard_state(bd->Display);
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ImGui_ImplAllegro5_UpdateMouseCursor()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
|
||||
return;
|
||||
|
||||
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
||||
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None)
|
||||
{
|
||||
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
||||
al_set_mouse_cursor(bd->Display, bd->MouseCursorInvisible);
|
||||
}
|
||||
else
|
||||
{
|
||||
ALLEGRO_SYSTEM_MOUSE_CURSOR cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_DEFAULT;
|
||||
switch (imgui_cursor)
|
||||
{
|
||||
case ImGuiMouseCursor_TextInput: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_EDIT; break;
|
||||
case ImGuiMouseCursor_ResizeAll: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_MOVE; break;
|
||||
case ImGuiMouseCursor_ResizeNS: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_N; break;
|
||||
case ImGuiMouseCursor_ResizeEW: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_E; break;
|
||||
case ImGuiMouseCursor_ResizeNESW: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NE; break;
|
||||
case ImGuiMouseCursor_ResizeNWSE: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NW; break;
|
||||
case ImGuiMouseCursor_NotAllowed: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_UNAVAILABLE; break;
|
||||
}
|
||||
al_set_system_mouse_cursor(bd->Display, cursor_id);
|
||||
}
|
||||
}
|
||||
|
||||
void ImGui_ImplAllegro5_NewFrame()
|
||||
{
|
||||
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
|
||||
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplAllegro5_Init()?");
|
||||
|
||||
if (!bd->Texture)
|
||||
ImGui_ImplAllegro5_CreateDeviceObjects();
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
// Setup display size (every frame to accommodate for window resizing)
|
||||
int w, h;
|
||||
w = al_get_display_width(bd->Display);
|
||||
h = al_get_display_height(bd->Display);
|
||||
io.DisplaySize = ImVec2((float)w, (float)h);
|
||||
|
||||
// Setup time step
|
||||
double current_time = al_get_time();
|
||||
io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f);
|
||||
bd->Time = current_time;
|
||||
|
||||
// Setup inputs
|
||||
ALLEGRO_KEYBOARD_STATE keys;
|
||||
al_get_keyboard_state(&keys);
|
||||
io.KeyCtrl = al_key_down(&keys, ALLEGRO_KEY_LCTRL) || al_key_down(&keys, ALLEGRO_KEY_RCTRL);
|
||||
io.KeyShift = al_key_down(&keys, ALLEGRO_KEY_LSHIFT) || al_key_down(&keys, ALLEGRO_KEY_RSHIFT);
|
||||
io.KeyAlt = al_key_down(&keys, ALLEGRO_KEY_ALT) || al_key_down(&keys, ALLEGRO_KEY_ALTGR);
|
||||
io.KeySuper = al_key_down(&keys, ALLEGRO_KEY_LWIN) || al_key_down(&keys, ALLEGRO_KEY_RWIN);
|
||||
|
||||
ImGui_ImplAllegro5_UpdateMouseCursor();
|
||||
}
|
||||
31
samples/external/Imgui/imgui-docking/backends/imgui_impl_allegro5.h
vendored
Normal file
31
samples/external/Imgui/imgui-docking/backends/imgui_impl_allegro5.h
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
// dear imgui: Renderer + Platform Backend for Allegro 5
|
||||
// (Info: Allegro 5 is a cross-platform general purpose library for handling windows, inputs, graphics, etc.)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Platform: Clipboard support (from Allegro 5.1.12)
|
||||
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// Issues:
|
||||
// [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually.
|
||||
// [ ] Platform: Missing gamepad support.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
struct ALLEGRO_DISPLAY;
|
||||
union ALLEGRO_EVENT;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display);
|
||||
IMGUI_IMPL_API void ImGui_ImplAllegro5_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplAllegro5_NewFrame();
|
||||
IMGUI_IMPL_API void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data);
|
||||
IMGUI_IMPL_API bool ImGui_ImplAllegro5_ProcessEvent(ALLEGRO_EVENT* event);
|
||||
|
||||
// Use if you want to reset your rendering device without losing Dear ImGui state.
|
||||
IMGUI_IMPL_API bool ImGui_ImplAllegro5_CreateDeviceObjects();
|
||||
IMGUI_IMPL_API void ImGui_ImplAllegro5_InvalidateDeviceObjects();
|
||||
187
samples/external/Imgui/imgui-docking/backends/imgui_impl_android.cpp
vendored
Normal file
187
samples/external/Imgui/imgui-docking/backends/imgui_impl_android.cpp
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
// dear imgui: Platform Binding for Android native app
|
||||
// This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Keyboard arrays indexed using AKEYCODE_* codes, e.g. ImGui::IsKeyPressed(AKEYCODE_SPACE).
|
||||
// Missing features:
|
||||
// [ ] Platform: Clipboard support.
|
||||
// [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android.
|
||||
// Important:
|
||||
// - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446)
|
||||
// - FIXME: Unicode character inputs needs to be passed by Dear ImGui by the application (see examples/ and issue #3446)
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2021-03-04: Initial version.
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_android.h"
|
||||
#include <time.h>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <android/native_window.h>
|
||||
#include <android/input.h>
|
||||
#include <android/keycodes.h>
|
||||
#include <android/log.h>
|
||||
|
||||
// Android data
|
||||
static double g_Time = 0.0;
|
||||
static ANativeWindow* g_Window;
|
||||
static char g_LogTag[] = "ImGuiExample";
|
||||
static std::map<int32_t, std::queue<int32_t>> g_KeyEventQueues; // FIXME: Remove dependency on map and queue once we use upcoming input queue.
|
||||
|
||||
int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
int32_t event_type = AInputEvent_getType(input_event);
|
||||
switch (event_type)
|
||||
{
|
||||
case AINPUT_EVENT_TYPE_KEY:
|
||||
{
|
||||
int32_t event_key_code = AKeyEvent_getKeyCode(input_event);
|
||||
int32_t event_action = AKeyEvent_getAction(input_event);
|
||||
int32_t event_meta_state = AKeyEvent_getMetaState(input_event);
|
||||
|
||||
io.KeyCtrl = ((event_meta_state & AMETA_CTRL_ON) != 0);
|
||||
io.KeyShift = ((event_meta_state & AMETA_SHIFT_ON) != 0);
|
||||
io.KeyAlt = ((event_meta_state & AMETA_ALT_ON) != 0);
|
||||
|
||||
switch (event_action)
|
||||
{
|
||||
// FIXME: AKEY_EVENT_ACTION_DOWN and AKEY_EVENT_ACTION_UP occur at once as soon as a touch pointer
|
||||
// goes up from a key. We use a simple key event queue/ and process one event per key per frame in
|
||||
// ImGui_ImplAndroid_NewFrame()...or consider using IO queue, if suitable: https://github.com/ocornut/imgui/issues/2787
|
||||
case AKEY_EVENT_ACTION_DOWN:
|
||||
case AKEY_EVENT_ACTION_UP:
|
||||
g_KeyEventQueues[event_key_code].push(event_action);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AINPUT_EVENT_TYPE_MOTION:
|
||||
{
|
||||
int32_t event_action = AMotionEvent_getAction(input_event);
|
||||
int32_t event_pointer_index = (event_action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
|
||||
event_action &= AMOTION_EVENT_ACTION_MASK;
|
||||
switch (event_action)
|
||||
{
|
||||
case AMOTION_EVENT_ACTION_DOWN:
|
||||
case AMOTION_EVENT_ACTION_UP:
|
||||
// Physical mouse buttons (and probably other physical devices) also invoke the actions AMOTION_EVENT_ACTION_DOWN/_UP,
|
||||
// but we have to process them separately to identify the actual button pressed. This is done below via
|
||||
// AMOTION_EVENT_ACTION_BUTTON_PRESS/_RELEASE. Here, we only process "FINGER" input (and "UNKNOWN", as a fallback).
|
||||
if((AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_FINGER)
|
||||
|| (AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_UNKNOWN))
|
||||
{
|
||||
io.MouseDown[0] = (event_action == AMOTION_EVENT_ACTION_DOWN);
|
||||
io.MousePos = ImVec2(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index));
|
||||
}
|
||||
break;
|
||||
case AMOTION_EVENT_ACTION_BUTTON_PRESS:
|
||||
case AMOTION_EVENT_ACTION_BUTTON_RELEASE:
|
||||
{
|
||||
int32_t button_state = AMotionEvent_getButtonState(input_event);
|
||||
io.MouseDown[0] = ((button_state & AMOTION_EVENT_BUTTON_PRIMARY) != 0);
|
||||
io.MouseDown[1] = ((button_state & AMOTION_EVENT_BUTTON_SECONDARY) != 0);
|
||||
io.MouseDown[2] = ((button_state & AMOTION_EVENT_BUTTON_TERTIARY) != 0);
|
||||
}
|
||||
break;
|
||||
case AMOTION_EVENT_ACTION_HOVER_MOVE: // Hovering: Tool moves while NOT pressed (such as a physical mouse)
|
||||
case AMOTION_EVENT_ACTION_MOVE: // Touch pointer moves while DOWN
|
||||
io.MousePos = ImVec2(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index));
|
||||
break;
|
||||
case AMOTION_EVENT_ACTION_SCROLL:
|
||||
io.MouseWheel = AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_VSCROLL, event_pointer_index);
|
||||
io.MouseWheelH = AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_HSCROLL, event_pointer_index);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ImGui_ImplAndroid_Init(ANativeWindow* window)
|
||||
{
|
||||
g_Window = window;
|
||||
g_Time = 0.0;
|
||||
|
||||
// Setup backend capabilities flags
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.BackendPlatformName = "imgui_impl_android";
|
||||
|
||||
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
|
||||
io.KeyMap[ImGuiKey_Tab] = AKEYCODE_TAB;
|
||||
io.KeyMap[ImGuiKey_LeftArrow] = AKEYCODE_DPAD_LEFT; // also covers physical keyboard arrow key
|
||||
io.KeyMap[ImGuiKey_RightArrow] = AKEYCODE_DPAD_RIGHT; // also covers physical keyboard arrow key
|
||||
io.KeyMap[ImGuiKey_UpArrow] = AKEYCODE_DPAD_UP; // also covers physical keyboard arrow key
|
||||
io.KeyMap[ImGuiKey_DownArrow] = AKEYCODE_DPAD_DOWN; // also covers physical keyboard arrow key
|
||||
io.KeyMap[ImGuiKey_PageUp] = AKEYCODE_PAGE_UP;
|
||||
io.KeyMap[ImGuiKey_PageDown] = AKEYCODE_PAGE_DOWN;
|
||||
io.KeyMap[ImGuiKey_Home] = AKEYCODE_MOVE_HOME;
|
||||
io.KeyMap[ImGuiKey_End] = AKEYCODE_MOVE_END;
|
||||
io.KeyMap[ImGuiKey_Insert] = AKEYCODE_INSERT;
|
||||
io.KeyMap[ImGuiKey_Delete] = AKEYCODE_FORWARD_DEL;
|
||||
io.KeyMap[ImGuiKey_Backspace] = AKEYCODE_DEL;
|
||||
io.KeyMap[ImGuiKey_Space] = AKEYCODE_SPACE;
|
||||
io.KeyMap[ImGuiKey_Enter] = AKEYCODE_ENTER;
|
||||
io.KeyMap[ImGuiKey_Escape] = AKEYCODE_ESCAPE;
|
||||
io.KeyMap[ImGuiKey_KeyPadEnter] = AKEYCODE_NUMPAD_ENTER;
|
||||
io.KeyMap[ImGuiKey_A] = AKEYCODE_A;
|
||||
io.KeyMap[ImGuiKey_C] = AKEYCODE_C;
|
||||
io.KeyMap[ImGuiKey_V] = AKEYCODE_V;
|
||||
io.KeyMap[ImGuiKey_X] = AKEYCODE_X;
|
||||
io.KeyMap[ImGuiKey_Y] = AKEYCODE_Y;
|
||||
io.KeyMap[ImGuiKey_Z] = AKEYCODE_Z;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplAndroid_Shutdown()
|
||||
{
|
||||
}
|
||||
|
||||
void ImGui_ImplAndroid_NewFrame()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
// Process queued key events
|
||||
// FIXME: This is a workaround for multiple key event actions occurring at once (see above) and can be removed once we use upcoming input queue.
|
||||
for (auto& key_queue : g_KeyEventQueues)
|
||||
{
|
||||
if (key_queue.second.empty())
|
||||
continue;
|
||||
io.KeysDown[key_queue.first] = (key_queue.second.front() == AKEY_EVENT_ACTION_DOWN);
|
||||
key_queue.second.pop();
|
||||
}
|
||||
|
||||
// Setup display size (every frame to accommodate for window resizing)
|
||||
int32_t window_width = ANativeWindow_getWidth(g_Window);
|
||||
int32_t window_height = ANativeWindow_getHeight(g_Window);
|
||||
int display_width = window_width;
|
||||
int display_height = window_height;
|
||||
|
||||
io.DisplaySize = ImVec2((float)window_width, (float)window_height);
|
||||
if (window_width > 0 && window_height > 0)
|
||||
io.DisplayFramebufferScale = ImVec2((float)display_width / window_width, (float)display_height / window_height);
|
||||
|
||||
// Setup time step
|
||||
struct timespec current_timespec;
|
||||
clock_gettime(CLOCK_MONOTONIC, ¤t_timespec);
|
||||
double current_time = (double)(current_timespec.tv_sec) + (current_timespec.tv_nsec / 1000000000.0);
|
||||
io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f);
|
||||
g_Time = current_time;
|
||||
}
|
||||
27
samples/external/Imgui/imgui-docking/backends/imgui_impl_android.h
vendored
Normal file
27
samples/external/Imgui/imgui-docking/backends/imgui_impl_android.h
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
// dear imgui: Platform Binding for Android native app
|
||||
// This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Keyboard arrays indexed using AKEYCODE_* codes, e.g. ImGui::IsKeyPressed(AKEYCODE_SPACE).
|
||||
// Missing features:
|
||||
// [ ] Platform: Clipboard support.
|
||||
// [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android.
|
||||
// Important:
|
||||
// - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446)
|
||||
// - FIXME: Unicode character inputs needs to be passed by Dear ImGui by the application (see examples/ and issue #3446)
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
#pragma once
|
||||
|
||||
struct ANativeWindow;
|
||||
struct AInputEvent;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplAndroid_Init(ANativeWindow* window);
|
||||
IMGUI_IMPL_API int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event);
|
||||
IMGUI_IMPL_API void ImGui_ImplAndroid_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplAndroid_NewFrame();
|
||||
712
samples/external/Imgui/imgui-docking/backends/imgui_impl_dx10.cpp
vendored
Normal file
712
samples/external/Imgui/imgui-docking/backends/imgui_impl_dx10.cpp
vendored
Normal file
@@ -0,0 +1,712 @@
|
||||
// dear imgui: Renderer Backend for DirectX10
|
||||
// This needs to be used along with a Platform Backend (e.g. Win32)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Multi-viewport support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
|
||||
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||
// 2021-05-19: DirectX10: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||
// 2021-02-18: DirectX10: Change blending equation to preserve alpha in output buffer.
|
||||
// 2019-07-21: DirectX10: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData().
|
||||
// 2019-05-29: DirectX10: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||
// 2019-04-30: DirectX10: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||
// 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile().
|
||||
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||
// 2018-07-13: DirectX10: Fixed unreleased resources in Init and Shutdown functions.
|
||||
// 2018-06-08: Misc: Extracted imgui_impl_dx10.cpp/.h away from the old combined DX10+Win32 example.
|
||||
// 2018-06-08: DirectX10: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
||||
// 2018-04-09: Misc: Fixed erroneous call to io.Fonts->ClearInputData() + ClearTexData() that was left in DX10 example but removed in 1.47 (Nov 2015) on other backends.
|
||||
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX10_RenderDrawData() in the .h file so you can call it yourself.
|
||||
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||
// 2016-05-07: DirectX10: Disabling depth-write.
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_dx10.h"
|
||||
|
||||
// DirectX
|
||||
#include <stdio.h>
|
||||
#include <d3d10_1.h>
|
||||
#include <d3d10.h>
|
||||
#include <d3dcompiler.h>
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
|
||||
#endif
|
||||
|
||||
// DirectX data
|
||||
struct ImGui_ImplDX10_Data
|
||||
{
|
||||
ID3D10Device* pd3dDevice;
|
||||
IDXGIFactory* pFactory;
|
||||
ID3D10Buffer* pVB;
|
||||
ID3D10Buffer* pIB;
|
||||
ID3D10VertexShader* pVertexShader;
|
||||
ID3D10InputLayout* pInputLayout;
|
||||
ID3D10Buffer* pVertexConstantBuffer;
|
||||
ID3D10PixelShader* pPixelShader;
|
||||
ID3D10SamplerState* pFontSampler;
|
||||
ID3D10ShaderResourceView* pFontTextureView;
|
||||
ID3D10RasterizerState* pRasterizerState;
|
||||
ID3D10BlendState* pBlendState;
|
||||
ID3D10DepthStencilState* pDepthStencilState;
|
||||
int VertexBufferSize;
|
||||
int IndexBufferSize;
|
||||
|
||||
ImGui_ImplDX10_Data() { memset(this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }
|
||||
};
|
||||
|
||||
struct VERTEX_CONSTANT_BUFFER
|
||||
{
|
||||
float mvp[4][4];
|
||||
};
|
||||
|
||||
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||
static ImGui_ImplDX10_Data* ImGui_ImplDX10_GetBackendData()
|
||||
{
|
||||
return ImGui::GetCurrentContext() ? (ImGui_ImplDX10_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
|
||||
}
|
||||
|
||||
// Forward Declarations
|
||||
static void ImGui_ImplDX10_InitPlatformInterface();
|
||||
static void ImGui_ImplDX10_ShutdownPlatformInterface();
|
||||
|
||||
// Functions
|
||||
static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* ctx)
|
||||
{
|
||||
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||
|
||||
// Setup viewport
|
||||
D3D10_VIEWPORT vp;
|
||||
memset(&vp, 0, sizeof(D3D10_VIEWPORT));
|
||||
vp.Width = (UINT)draw_data->DisplaySize.x;
|
||||
vp.Height = (UINT)draw_data->DisplaySize.y;
|
||||
vp.MinDepth = 0.0f;
|
||||
vp.MaxDepth = 1.0f;
|
||||
vp.TopLeftX = vp.TopLeftY = 0;
|
||||
ctx->RSSetViewports(1, &vp);
|
||||
|
||||
// Bind shader and vertex buffers
|
||||
unsigned int stride = sizeof(ImDrawVert);
|
||||
unsigned int offset = 0;
|
||||
ctx->IASetInputLayout(bd->pInputLayout);
|
||||
ctx->IASetVertexBuffers(0, 1, &bd->pVB, &stride, &offset);
|
||||
ctx->IASetIndexBuffer(bd->pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
|
||||
ctx->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
ctx->VSSetShader(bd->pVertexShader);
|
||||
ctx->VSSetConstantBuffers(0, 1, &bd->pVertexConstantBuffer);
|
||||
ctx->PSSetShader(bd->pPixelShader);
|
||||
ctx->PSSetSamplers(0, 1, &bd->pFontSampler);
|
||||
ctx->GSSetShader(NULL);
|
||||
|
||||
// Setup render state
|
||||
const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
|
||||
ctx->OMSetBlendState(bd->pBlendState, blend_factor, 0xffffffff);
|
||||
ctx->OMSetDepthStencilState(bd->pDepthStencilState, 0);
|
||||
ctx->RSSetState(bd->pRasterizerState);
|
||||
}
|
||||
|
||||
// Render function
|
||||
void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
|
||||
{
|
||||
// Avoid rendering when minimized
|
||||
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
||||
return;
|
||||
|
||||
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||
ID3D10Device* ctx = bd->pd3dDevice;
|
||||
|
||||
// Create and grow vertex/index buffers if needed
|
||||
if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount)
|
||||
{
|
||||
if (bd->pVB) { bd->pVB->Release(); bd->pVB = NULL; }
|
||||
bd->VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
||||
D3D10_BUFFER_DESC desc;
|
||||
memset(&desc, 0, sizeof(D3D10_BUFFER_DESC));
|
||||
desc.Usage = D3D10_USAGE_DYNAMIC;
|
||||
desc.ByteWidth = bd->VertexBufferSize * sizeof(ImDrawVert);
|
||||
desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
|
||||
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
||||
desc.MiscFlags = 0;
|
||||
if (ctx->CreateBuffer(&desc, NULL, &bd->pVB) < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount)
|
||||
{
|
||||
if (bd->pIB) { bd->pIB->Release(); bd->pIB = NULL; }
|
||||
bd->IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
||||
D3D10_BUFFER_DESC desc;
|
||||
memset(&desc, 0, sizeof(D3D10_BUFFER_DESC));
|
||||
desc.Usage = D3D10_USAGE_DYNAMIC;
|
||||
desc.ByteWidth = bd->IndexBufferSize * sizeof(ImDrawIdx);
|
||||
desc.BindFlags = D3D10_BIND_INDEX_BUFFER;
|
||||
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
||||
if (ctx->CreateBuffer(&desc, NULL, &bd->pIB) < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy and convert all vertices into a single contiguous buffer
|
||||
ImDrawVert* vtx_dst = NULL;
|
||||
ImDrawIdx* idx_dst = NULL;
|
||||
bd->pVB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&vtx_dst);
|
||||
bd->pIB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&idx_dst);
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
|
||||
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
|
||||
vtx_dst += cmd_list->VtxBuffer.Size;
|
||||
idx_dst += cmd_list->IdxBuffer.Size;
|
||||
}
|
||||
bd->pVB->Unmap();
|
||||
bd->pIB->Unmap();
|
||||
|
||||
// Setup orthographic projection matrix into our constant buffer
|
||||
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||
{
|
||||
void* mapped_resource;
|
||||
if (bd->pVertexConstantBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
|
||||
return;
|
||||
VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource;
|
||||
float L = draw_data->DisplayPos.x;
|
||||
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||
float T = draw_data->DisplayPos.y;
|
||||
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
|
||||
float mvp[4][4] =
|
||||
{
|
||||
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
|
||||
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
|
||||
{ 0.0f, 0.0f, 0.5f, 0.0f },
|
||||
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
|
||||
};
|
||||
memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
|
||||
bd->pVertexConstantBuffer->Unmap();
|
||||
}
|
||||
|
||||
// Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
|
||||
struct BACKUP_DX10_STATE
|
||||
{
|
||||
UINT ScissorRectsCount, ViewportsCount;
|
||||
D3D10_RECT ScissorRects[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
|
||||
D3D10_VIEWPORT Viewports[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
|
||||
ID3D10RasterizerState* RS;
|
||||
ID3D10BlendState* BlendState;
|
||||
FLOAT BlendFactor[4];
|
||||
UINT SampleMask;
|
||||
UINT StencilRef;
|
||||
ID3D10DepthStencilState* DepthStencilState;
|
||||
ID3D10ShaderResourceView* PSShaderResource;
|
||||
ID3D10SamplerState* PSSampler;
|
||||
ID3D10PixelShader* PS;
|
||||
ID3D10VertexShader* VS;
|
||||
ID3D10GeometryShader* GS;
|
||||
D3D10_PRIMITIVE_TOPOLOGY PrimitiveTopology;
|
||||
ID3D10Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer;
|
||||
UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset;
|
||||
DXGI_FORMAT IndexBufferFormat;
|
||||
ID3D10InputLayout* InputLayout;
|
||||
};
|
||||
BACKUP_DX10_STATE old = {};
|
||||
old.ScissorRectsCount = old.ViewportsCount = D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
|
||||
ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects);
|
||||
ctx->RSGetViewports(&old.ViewportsCount, old.Viewports);
|
||||
ctx->RSGetState(&old.RS);
|
||||
ctx->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask);
|
||||
ctx->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef);
|
||||
ctx->PSGetShaderResources(0, 1, &old.PSShaderResource);
|
||||
ctx->PSGetSamplers(0, 1, &old.PSSampler);
|
||||
ctx->PSGetShader(&old.PS);
|
||||
ctx->VSGetShader(&old.VS);
|
||||
ctx->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer);
|
||||
ctx->GSGetShader(&old.GS);
|
||||
ctx->IAGetPrimitiveTopology(&old.PrimitiveTopology);
|
||||
ctx->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset);
|
||||
ctx->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset);
|
||||
ctx->IAGetInputLayout(&old.InputLayout);
|
||||
|
||||
// Setup desired DX state
|
||||
ImGui_ImplDX10_SetupRenderState(draw_data, ctx);
|
||||
|
||||
// Render command lists
|
||||
// (Because we merged all buffers into a single one, we maintain our own offset into them)
|
||||
int global_vtx_offset = 0;
|
||||
int global_idx_offset = 0;
|
||||
ImVec2 clip_off = draw_data->DisplayPos;
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||
if (pcmd->UserCallback)
|
||||
{
|
||||
// User callback, registered via ImDrawList::AddCallback()
|
||||
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||
ImGui_ImplDX10_SetupRenderState(draw_data, ctx);
|
||||
else
|
||||
pcmd->UserCallback(cmd_list, pcmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
|
||||
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
|
||||
if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
|
||||
continue;
|
||||
|
||||
// Apply scissor/clipping rectangle
|
||||
const D3D10_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
|
||||
ctx->RSSetScissorRects(1, &r);
|
||||
|
||||
// Bind texture, Draw
|
||||
ID3D10ShaderResourceView* texture_srv = (ID3D10ShaderResourceView*)pcmd->GetTexID();
|
||||
ctx->PSSetShaderResources(0, 1, &texture_srv);
|
||||
ctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset);
|
||||
}
|
||||
}
|
||||
global_idx_offset += cmd_list->IdxBuffer.Size;
|
||||
global_vtx_offset += cmd_list->VtxBuffer.Size;
|
||||
}
|
||||
|
||||
// Restore modified DX state
|
||||
ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects);
|
||||
ctx->RSSetViewports(old.ViewportsCount, old.Viewports);
|
||||
ctx->RSSetState(old.RS); if (old.RS) old.RS->Release();
|
||||
ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release();
|
||||
ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release();
|
||||
ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release();
|
||||
ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release();
|
||||
ctx->PSSetShader(old.PS); if (old.PS) old.PS->Release();
|
||||
ctx->VSSetShader(old.VS); if (old.VS) old.VS->Release();
|
||||
ctx->GSSetShader(old.GS); if (old.GS) old.GS->Release();
|
||||
ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release();
|
||||
ctx->IASetPrimitiveTopology(old.PrimitiveTopology);
|
||||
ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release();
|
||||
ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release();
|
||||
ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release();
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX10_CreateFontsTexture()
|
||||
{
|
||||
// Build texture atlas
|
||||
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
unsigned char* pixels;
|
||||
int width, height;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||
|
||||
// Upload texture to graphics system
|
||||
{
|
||||
D3D10_TEXTURE2D_DESC desc;
|
||||
ZeroMemory(&desc, sizeof(desc));
|
||||
desc.Width = width;
|
||||
desc.Height = height;
|
||||
desc.MipLevels = 1;
|
||||
desc.ArraySize = 1;
|
||||
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.Usage = D3D10_USAGE_DEFAULT;
|
||||
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
|
||||
desc.CPUAccessFlags = 0;
|
||||
|
||||
ID3D10Texture2D* pTexture = NULL;
|
||||
D3D10_SUBRESOURCE_DATA subResource;
|
||||
subResource.pSysMem = pixels;
|
||||
subResource.SysMemPitch = desc.Width * 4;
|
||||
subResource.SysMemSlicePitch = 0;
|
||||
bd->pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
|
||||
IM_ASSERT(pTexture != NULL);
|
||||
|
||||
// Create texture view
|
||||
D3D10_SHADER_RESOURCE_VIEW_DESC srv_desc;
|
||||
ZeroMemory(&srv_desc, sizeof(srv_desc));
|
||||
srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
srv_desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
|
||||
srv_desc.Texture2D.MipLevels = desc.MipLevels;
|
||||
srv_desc.Texture2D.MostDetailedMip = 0;
|
||||
bd->pd3dDevice->CreateShaderResourceView(pTexture, &srv_desc, &bd->pFontTextureView);
|
||||
pTexture->Release();
|
||||
}
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->SetTexID((ImTextureID)bd->pFontTextureView);
|
||||
|
||||
// Create texture sampler
|
||||
{
|
||||
D3D10_SAMPLER_DESC desc;
|
||||
ZeroMemory(&desc, sizeof(desc));
|
||||
desc.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR;
|
||||
desc.AddressU = D3D10_TEXTURE_ADDRESS_WRAP;
|
||||
desc.AddressV = D3D10_TEXTURE_ADDRESS_WRAP;
|
||||
desc.AddressW = D3D10_TEXTURE_ADDRESS_WRAP;
|
||||
desc.MipLODBias = 0.f;
|
||||
desc.ComparisonFunc = D3D10_COMPARISON_ALWAYS;
|
||||
desc.MinLOD = 0.f;
|
||||
desc.MaxLOD = 0.f;
|
||||
bd->pd3dDevice->CreateSamplerState(&desc, &bd->pFontSampler);
|
||||
}
|
||||
}
|
||||
|
||||
bool ImGui_ImplDX10_CreateDeviceObjects()
|
||||
{
|
||||
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||
if (!bd->pd3dDevice)
|
||||
return false;
|
||||
if (bd->pFontSampler)
|
||||
ImGui_ImplDX10_InvalidateDeviceObjects();
|
||||
|
||||
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
|
||||
// If you would like to use this DX10 sample code but remove this dependency you can:
|
||||
// 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
|
||||
// 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
|
||||
// See https://github.com/ocornut/imgui/pull/638 for sources and details.
|
||||
|
||||
// Create the vertex shader
|
||||
{
|
||||
static const char* vertexShader =
|
||||
"cbuffer vertexBuffer : register(b0) \
|
||||
{\
|
||||
float4x4 ProjectionMatrix; \
|
||||
};\
|
||||
struct VS_INPUT\
|
||||
{\
|
||||
float2 pos : POSITION;\
|
||||
float4 col : COLOR0;\
|
||||
float2 uv : TEXCOORD0;\
|
||||
};\
|
||||
\
|
||||
struct PS_INPUT\
|
||||
{\
|
||||
float4 pos : SV_POSITION;\
|
||||
float4 col : COLOR0;\
|
||||
float2 uv : TEXCOORD0;\
|
||||
};\
|
||||
\
|
||||
PS_INPUT main(VS_INPUT input)\
|
||||
{\
|
||||
PS_INPUT output;\
|
||||
output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\
|
||||
output.col = input.col;\
|
||||
output.uv = input.uv;\
|
||||
return output;\
|
||||
}";
|
||||
|
||||
ID3DBlob* vertexShaderBlob;
|
||||
if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &vertexShaderBlob, NULL)))
|
||||
return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||
if (bd->pd3dDevice->CreateVertexShader(vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &bd->pVertexShader) != S_OK)
|
||||
{
|
||||
vertexShaderBlob->Release();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create the input layout
|
||||
D3D10_INPUT_ELEMENT_DESC local_layout[] =
|
||||
{
|
||||
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, pos), D3D10_INPUT_PER_VERTEX_DATA, 0 },
|
||||
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, uv), D3D10_INPUT_PER_VERTEX_DATA, 0 },
|
||||
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)IM_OFFSETOF(ImDrawVert, col), D3D10_INPUT_PER_VERTEX_DATA, 0 },
|
||||
};
|
||||
if (bd->pd3dDevice->CreateInputLayout(local_layout, 3, vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &bd->pInputLayout) != S_OK)
|
||||
{
|
||||
vertexShaderBlob->Release();
|
||||
return false;
|
||||
}
|
||||
vertexShaderBlob->Release();
|
||||
|
||||
// Create the constant buffer
|
||||
{
|
||||
D3D10_BUFFER_DESC desc;
|
||||
desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
|
||||
desc.Usage = D3D10_USAGE_DYNAMIC;
|
||||
desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
|
||||
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
||||
desc.MiscFlags = 0;
|
||||
bd->pd3dDevice->CreateBuffer(&desc, NULL, &bd->pVertexConstantBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
// Create the pixel shader
|
||||
{
|
||||
static const char* pixelShader =
|
||||
"struct PS_INPUT\
|
||||
{\
|
||||
float4 pos : SV_POSITION;\
|
||||
float4 col : COLOR0;\
|
||||
float2 uv : TEXCOORD0;\
|
||||
};\
|
||||
sampler sampler0;\
|
||||
Texture2D texture0;\
|
||||
\
|
||||
float4 main(PS_INPUT input) : SV_Target\
|
||||
{\
|
||||
float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
|
||||
return out_col; \
|
||||
}";
|
||||
|
||||
ID3DBlob* pixelShaderBlob;
|
||||
if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &pixelShaderBlob, NULL)))
|
||||
return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||
if (bd->pd3dDevice->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), &bd->pPixelShader) != S_OK)
|
||||
{
|
||||
pixelShaderBlob->Release();
|
||||
return false;
|
||||
}
|
||||
pixelShaderBlob->Release();
|
||||
}
|
||||
|
||||
// Create the blending setup
|
||||
{
|
||||
D3D10_BLEND_DESC desc;
|
||||
ZeroMemory(&desc, sizeof(desc));
|
||||
desc.AlphaToCoverageEnable = false;
|
||||
desc.BlendEnable[0] = true;
|
||||
desc.SrcBlend = D3D10_BLEND_SRC_ALPHA;
|
||||
desc.DestBlend = D3D10_BLEND_INV_SRC_ALPHA;
|
||||
desc.BlendOp = D3D10_BLEND_OP_ADD;
|
||||
desc.SrcBlendAlpha = D3D10_BLEND_ONE;
|
||||
desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
|
||||
desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
|
||||
desc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
|
||||
bd->pd3dDevice->CreateBlendState(&desc, &bd->pBlendState);
|
||||
}
|
||||
|
||||
// Create the rasterizer state
|
||||
{
|
||||
D3D10_RASTERIZER_DESC desc;
|
||||
ZeroMemory(&desc, sizeof(desc));
|
||||
desc.FillMode = D3D10_FILL_SOLID;
|
||||
desc.CullMode = D3D10_CULL_NONE;
|
||||
desc.ScissorEnable = true;
|
||||
desc.DepthClipEnable = true;
|
||||
bd->pd3dDevice->CreateRasterizerState(&desc, &bd->pRasterizerState);
|
||||
}
|
||||
|
||||
// Create depth-stencil State
|
||||
{
|
||||
D3D10_DEPTH_STENCIL_DESC desc;
|
||||
ZeroMemory(&desc, sizeof(desc));
|
||||
desc.DepthEnable = false;
|
||||
desc.DepthWriteMask = D3D10_DEPTH_WRITE_MASK_ALL;
|
||||
desc.DepthFunc = D3D10_COMPARISON_ALWAYS;
|
||||
desc.StencilEnable = false;
|
||||
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D10_STENCIL_OP_KEEP;
|
||||
desc.FrontFace.StencilFunc = D3D10_COMPARISON_ALWAYS;
|
||||
desc.BackFace = desc.FrontFace;
|
||||
bd->pd3dDevice->CreateDepthStencilState(&desc, &bd->pDepthStencilState);
|
||||
}
|
||||
|
||||
ImGui_ImplDX10_CreateFontsTexture();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplDX10_InvalidateDeviceObjects()
|
||||
{
|
||||
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||
if (!bd->pd3dDevice)
|
||||
return;
|
||||
|
||||
if (bd->pFontSampler) { bd->pFontSampler->Release(); bd->pFontSampler = NULL; }
|
||||
if (bd->pFontTextureView) { bd->pFontTextureView->Release(); bd->pFontTextureView = NULL; ImGui::GetIO().Fonts->SetTexID(NULL); } // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
||||
if (bd->pIB) { bd->pIB->Release(); bd->pIB = NULL; }
|
||||
if (bd->pVB) { bd->pVB->Release(); bd->pVB = NULL; }
|
||||
if (bd->pBlendState) { bd->pBlendState->Release(); bd->pBlendState = NULL; }
|
||||
if (bd->pDepthStencilState) { bd->pDepthStencilState->Release(); bd->pDepthStencilState = NULL; }
|
||||
if (bd->pRasterizerState) { bd->pRasterizerState->Release(); bd->pRasterizerState = NULL; }
|
||||
if (bd->pPixelShader) { bd->pPixelShader->Release(); bd->pPixelShader = NULL; }
|
||||
if (bd->pVertexConstantBuffer) { bd->pVertexConstantBuffer->Release(); bd->pVertexConstantBuffer = NULL; }
|
||||
if (bd->pInputLayout) { bd->pInputLayout->Release(); bd->pInputLayout = NULL; }
|
||||
if (bd->pVertexShader) { bd->pVertexShader->Release(); bd->pVertexShader = NULL; }
|
||||
}
|
||||
|
||||
bool ImGui_ImplDX10_Init(ID3D10Device* device)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
|
||||
|
||||
// Setup backend capabilities flags
|
||||
ImGui_ImplDX10_Data* bd = IM_NEW(ImGui_ImplDX10_Data)();
|
||||
io.BackendRendererUserData = (void*)bd;
|
||||
io.BackendRendererName = "imgui_impl_dx10";
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
|
||||
|
||||
// Get factory from device
|
||||
IDXGIDevice* pDXGIDevice = NULL;
|
||||
IDXGIAdapter* pDXGIAdapter = NULL;
|
||||
IDXGIFactory* pFactory = NULL;
|
||||
if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
|
||||
if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
|
||||
if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
|
||||
{
|
||||
bd->pd3dDevice = device;
|
||||
bd->pFactory = pFactory;
|
||||
}
|
||||
if (pDXGIDevice) pDXGIDevice->Release();
|
||||
if (pDXGIAdapter) pDXGIAdapter->Release();
|
||||
bd->pd3dDevice->AddRef();
|
||||
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
ImGui_ImplDX10_InitPlatformInterface();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplDX10_Shutdown()
|
||||
{
|
||||
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||
IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui_ImplDX10_ShutdownPlatformInterface();
|
||||
ImGui_ImplDX10_InvalidateDeviceObjects();
|
||||
if (bd->pFactory) { bd->pFactory->Release(); }
|
||||
if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
|
||||
io.BackendRendererName = NULL;
|
||||
io.BackendRendererUserData = NULL;
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
void ImGui_ImplDX10_NewFrame()
|
||||
{
|
||||
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplDX10_Init()?");
|
||||
|
||||
if (!bd->pFontSampler)
|
||||
ImGui_ImplDX10_CreateDeviceObjects();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
|
||||
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
|
||||
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Helper structure we store in the void* RenderUserData field of each ImGuiViewport to easily retrieve our backend data.
|
||||
struct ImGui_ImplDX10_ViewportData
|
||||
{
|
||||
IDXGISwapChain* SwapChain;
|
||||
ID3D10RenderTargetView* RTView;
|
||||
|
||||
ImGui_ImplDX10_ViewportData() { SwapChain = NULL; RTView = NULL; }
|
||||
~ImGui_ImplDX10_ViewportData() { IM_ASSERT(SwapChain == NULL && RTView == NULL); }
|
||||
};
|
||||
|
||||
static void ImGui_ImplDX10_CreateWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||
ImGui_ImplDX10_ViewportData* vd = IM_NEW(ImGui_ImplDX10_ViewportData)();
|
||||
viewport->RendererUserData = vd;
|
||||
|
||||
// PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL_Window*).
|
||||
// Some backends will leave PlatformHandleRaw NULL, in which case we assume PlatformHandle will contain the HWND.
|
||||
HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle;
|
||||
IM_ASSERT(hwnd != 0);
|
||||
|
||||
// Create swap chain
|
||||
DXGI_SWAP_CHAIN_DESC sd;
|
||||
ZeroMemory(&sd, sizeof(sd));
|
||||
sd.BufferDesc.Width = (UINT)viewport->Size.x;
|
||||
sd.BufferDesc.Height = (UINT)viewport->Size.y;
|
||||
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
sd.SampleDesc.Count = 1;
|
||||
sd.SampleDesc.Quality = 0;
|
||||
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
sd.BufferCount = 1;
|
||||
sd.OutputWindow = hwnd;
|
||||
sd.Windowed = TRUE;
|
||||
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
|
||||
sd.Flags = 0;
|
||||
|
||||
IM_ASSERT(vd->SwapChain == NULL && vd->RTView == NULL);
|
||||
bd->pFactory->CreateSwapChain(bd->pd3dDevice, &sd, &vd->SwapChain);
|
||||
|
||||
// Create the render target
|
||||
if (vd->SwapChain)
|
||||
{
|
||||
ID3D10Texture2D* pBackBuffer;
|
||||
vd->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
|
||||
bd->pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &vd->RTView);
|
||||
pBackBuffer->Release();
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX10_DestroyWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
// The main viewport (owned by the application) will always have RendererUserData == NULL here since we didn't create the data for it.
|
||||
if (ImGui_ImplDX10_ViewportData* vd = (ImGui_ImplDX10_ViewportData*)viewport->RendererUserData)
|
||||
{
|
||||
if (vd->SwapChain)
|
||||
vd->SwapChain->Release();
|
||||
vd->SwapChain = NULL;
|
||||
if (vd->RTView)
|
||||
vd->RTView->Release();
|
||||
vd->RTView = NULL;
|
||||
IM_DELETE(vd);
|
||||
}
|
||||
viewport->RendererUserData = NULL;
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX10_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
|
||||
{
|
||||
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||
ImGui_ImplDX10_ViewportData* vd = (ImGui_ImplDX10_ViewportData*)viewport->RendererUserData;
|
||||
if (vd->RTView)
|
||||
{
|
||||
vd->RTView->Release();
|
||||
vd->RTView = NULL;
|
||||
}
|
||||
if (vd->SwapChain)
|
||||
{
|
||||
ID3D10Texture2D* pBackBuffer = NULL;
|
||||
vd->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, DXGI_FORMAT_UNKNOWN, 0);
|
||||
vd->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
|
||||
if (pBackBuffer == NULL) { fprintf(stderr, "ImGui_ImplDX10_SetWindowSize() failed creating buffers.\n"); return; }
|
||||
bd->pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &vd->RTView);
|
||||
pBackBuffer->Release();
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX10_RenderViewport(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||
ImGui_ImplDX10_ViewportData* vd = (ImGui_ImplDX10_ViewportData*)viewport->RendererUserData;
|
||||
ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
bd->pd3dDevice->OMSetRenderTargets(1, &vd->RTView, NULL);
|
||||
if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
|
||||
bd->pd3dDevice->ClearRenderTargetView(vd->RTView, (float*)&clear_color);
|
||||
ImGui_ImplDX10_RenderDrawData(viewport->DrawData);
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX10_SwapBuffers(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplDX10_ViewportData* vd = (ImGui_ImplDX10_ViewportData*)viewport->RendererUserData;
|
||||
vd->SwapChain->Present(0, 0); // Present without vsync
|
||||
}
|
||||
|
||||
void ImGui_ImplDX10_InitPlatformInterface()
|
||||
{
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Renderer_CreateWindow = ImGui_ImplDX10_CreateWindow;
|
||||
platform_io.Renderer_DestroyWindow = ImGui_ImplDX10_DestroyWindow;
|
||||
platform_io.Renderer_SetWindowSize = ImGui_ImplDX10_SetWindowSize;
|
||||
platform_io.Renderer_RenderWindow = ImGui_ImplDX10_RenderViewport;
|
||||
platform_io.Renderer_SwapBuffers = ImGui_ImplDX10_SwapBuffers;
|
||||
}
|
||||
|
||||
void ImGui_ImplDX10_ShutdownPlatformInterface()
|
||||
{
|
||||
ImGui::DestroyPlatformWindows();
|
||||
}
|
||||
|
||||
26
samples/external/Imgui/imgui-docking/backends/imgui_impl_dx10.h
vendored
Normal file
26
samples/external/Imgui/imgui-docking/backends/imgui_impl_dx10.h
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
// dear imgui: Renderer Backend for DirectX10
|
||||
// This needs to be used along with a Platform Backend (e.g. Win32)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Multi-viewport support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
struct ID3D10Device;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplDX10_Init(ID3D10Device* device);
|
||||
IMGUI_IMPL_API void ImGui_ImplDX10_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplDX10_NewFrame();
|
||||
IMGUI_IMPL_API void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data);
|
||||
|
||||
// Use if you want to reset your rendering device without losing Dear ImGui state.
|
||||
IMGUI_IMPL_API void ImGui_ImplDX10_InvalidateDeviceObjects();
|
||||
IMGUI_IMPL_API bool ImGui_ImplDX10_CreateDeviceObjects();
|
||||
728
samples/external/Imgui/imgui-docking/backends/imgui_impl_dx11.cpp
vendored
Normal file
728
samples/external/Imgui/imgui-docking/backends/imgui_impl_dx11.cpp
vendored
Normal file
@@ -0,0 +1,728 @@
|
||||
// dear imgui: Renderer Backend for DirectX11
|
||||
// This needs to be used along with a Platform Backend (e.g. Win32)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Multi-viewport support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
|
||||
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||
// 2021-05-19: DirectX11: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||
// 2021-02-18: DirectX11: Change blending equation to preserve alpha in output buffer.
|
||||
// 2019-08-01: DirectX11: Fixed code querying the Geometry Shader state (would generally error with Debug layer enabled).
|
||||
// 2019-07-21: DirectX11: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData. Clearing Hull/Domain/Compute shaders without backup/restore.
|
||||
// 2019-05-29: DirectX11: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||
// 2019-04-30: DirectX11: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||
// 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile().
|
||||
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||
// 2018-08-01: DirectX11: Querying for IDXGIFactory instead of IDXGIFactory1 to increase compatibility.
|
||||
// 2018-07-13: DirectX11: Fixed unreleased resources in Init and Shutdown functions.
|
||||
// 2018-06-08: Misc: Extracted imgui_impl_dx11.cpp/.h away from the old combined DX11+Win32 example.
|
||||
// 2018-06-08: DirectX11: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
||||
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX11_RenderDrawData() in the .h file so you can call it yourself.
|
||||
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||
// 2016-05-07: DirectX11: Disabling depth-write.
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_dx11.h"
|
||||
|
||||
// DirectX
|
||||
#include <stdio.h>
|
||||
#include <d3d11.h>
|
||||
#include <d3dcompiler.h>
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
|
||||
#endif
|
||||
|
||||
// DirectX11 data
|
||||
struct ImGui_ImplDX11_Data
|
||||
{
|
||||
ID3D11Device* pd3dDevice;
|
||||
ID3D11DeviceContext* pd3dDeviceContext;
|
||||
IDXGIFactory* pFactory;
|
||||
ID3D11Buffer* pVB;
|
||||
ID3D11Buffer* pIB;
|
||||
ID3D11VertexShader* pVertexShader;
|
||||
ID3D11InputLayout* pInputLayout;
|
||||
ID3D11Buffer* pVertexConstantBuffer;
|
||||
ID3D11PixelShader* pPixelShader;
|
||||
ID3D11SamplerState* pFontSampler;
|
||||
ID3D11ShaderResourceView* pFontTextureView;
|
||||
ID3D11RasterizerState* pRasterizerState;
|
||||
ID3D11BlendState* pBlendState;
|
||||
ID3D11DepthStencilState* pDepthStencilState;
|
||||
int VertexBufferSize;
|
||||
int IndexBufferSize;
|
||||
|
||||
ImGui_ImplDX11_Data() { memset(this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }
|
||||
};
|
||||
|
||||
struct VERTEX_CONSTANT_BUFFER
|
||||
{
|
||||
float mvp[4][4];
|
||||
};
|
||||
|
||||
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||
static ImGui_ImplDX11_Data* ImGui_ImplDX11_GetBackendData()
|
||||
{
|
||||
return ImGui::GetCurrentContext() ? (ImGui_ImplDX11_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
|
||||
}
|
||||
|
||||
// Forward Declarations
|
||||
static void ImGui_ImplDX11_InitPlatformInterface();
|
||||
static void ImGui_ImplDX11_ShutdownPlatformInterface();
|
||||
|
||||
// Functions
|
||||
static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceContext* ctx)
|
||||
{
|
||||
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||
|
||||
// Setup viewport
|
||||
D3D11_VIEWPORT vp;
|
||||
memset(&vp, 0, sizeof(D3D11_VIEWPORT));
|
||||
vp.Width = draw_data->DisplaySize.x;
|
||||
vp.Height = draw_data->DisplaySize.y;
|
||||
vp.MinDepth = 0.0f;
|
||||
vp.MaxDepth = 1.0f;
|
||||
vp.TopLeftX = vp.TopLeftY = 0;
|
||||
ctx->RSSetViewports(1, &vp);
|
||||
|
||||
// Setup shader and vertex buffers
|
||||
unsigned int stride = sizeof(ImDrawVert);
|
||||
unsigned int offset = 0;
|
||||
ctx->IASetInputLayout(bd->pInputLayout);
|
||||
ctx->IASetVertexBuffers(0, 1, &bd->pVB, &stride, &offset);
|
||||
ctx->IASetIndexBuffer(bd->pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
|
||||
ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
ctx->VSSetShader(bd->pVertexShader, NULL, 0);
|
||||
ctx->VSSetConstantBuffers(0, 1, &bd->pVertexConstantBuffer);
|
||||
ctx->PSSetShader(bd->pPixelShader, NULL, 0);
|
||||
ctx->PSSetSamplers(0, 1, &bd->pFontSampler);
|
||||
ctx->GSSetShader(NULL, NULL, 0);
|
||||
ctx->HSSetShader(NULL, NULL, 0); // In theory we should backup and restore this as well.. very infrequently used..
|
||||
ctx->DSSetShader(NULL, NULL, 0); // In theory we should backup and restore this as well.. very infrequently used..
|
||||
ctx->CSSetShader(NULL, NULL, 0); // In theory we should backup and restore this as well.. very infrequently used..
|
||||
|
||||
// Setup blend state
|
||||
const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
|
||||
ctx->OMSetBlendState(bd->pBlendState, blend_factor, 0xffffffff);
|
||||
ctx->OMSetDepthStencilState(bd->pDepthStencilState, 0);
|
||||
ctx->RSSetState(bd->pRasterizerState);
|
||||
}
|
||||
|
||||
// Render function
|
||||
void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
|
||||
{
|
||||
// Avoid rendering when minimized
|
||||
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
||||
return;
|
||||
|
||||
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||
ID3D11DeviceContext* ctx = bd->pd3dDeviceContext;
|
||||
|
||||
// Create and grow vertex/index buffers if needed
|
||||
if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount)
|
||||
{
|
||||
if (bd->pVB) { bd->pVB->Release(); bd->pVB = NULL; }
|
||||
bd->VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
||||
D3D11_BUFFER_DESC desc;
|
||||
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
|
||||
desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||
desc.ByteWidth = bd->VertexBufferSize * sizeof(ImDrawVert);
|
||||
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
desc.MiscFlags = 0;
|
||||
if (bd->pd3dDevice->CreateBuffer(&desc, NULL, &bd->pVB) < 0)
|
||||
return;
|
||||
}
|
||||
if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount)
|
||||
{
|
||||
if (bd->pIB) { bd->pIB->Release(); bd->pIB = NULL; }
|
||||
bd->IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
||||
D3D11_BUFFER_DESC desc;
|
||||
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
|
||||
desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||
desc.ByteWidth = bd->IndexBufferSize * sizeof(ImDrawIdx);
|
||||
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
if (bd->pd3dDevice->CreateBuffer(&desc, NULL, &bd->pIB) < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
// Upload vertex/index data into a single contiguous GPU buffer
|
||||
D3D11_MAPPED_SUBRESOURCE vtx_resource, idx_resource;
|
||||
if (ctx->Map(bd->pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK)
|
||||
return;
|
||||
if (ctx->Map(bd->pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK)
|
||||
return;
|
||||
ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData;
|
||||
ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData;
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
|
||||
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
|
||||
vtx_dst += cmd_list->VtxBuffer.Size;
|
||||
idx_dst += cmd_list->IdxBuffer.Size;
|
||||
}
|
||||
ctx->Unmap(bd->pVB, 0);
|
||||
ctx->Unmap(bd->pIB, 0);
|
||||
|
||||
// Setup orthographic projection matrix into our constant buffer
|
||||
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||
{
|
||||
D3D11_MAPPED_SUBRESOURCE mapped_resource;
|
||||
if (ctx->Map(bd->pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
|
||||
return;
|
||||
VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource.pData;
|
||||
float L = draw_data->DisplayPos.x;
|
||||
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||
float T = draw_data->DisplayPos.y;
|
||||
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
|
||||
float mvp[4][4] =
|
||||
{
|
||||
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
|
||||
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
|
||||
{ 0.0f, 0.0f, 0.5f, 0.0f },
|
||||
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
|
||||
};
|
||||
memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
|
||||
ctx->Unmap(bd->pVertexConstantBuffer, 0);
|
||||
}
|
||||
|
||||
// Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
|
||||
struct BACKUP_DX11_STATE
|
||||
{
|
||||
UINT ScissorRectsCount, ViewportsCount;
|
||||
D3D11_RECT ScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
|
||||
D3D11_VIEWPORT Viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
|
||||
ID3D11RasterizerState* RS;
|
||||
ID3D11BlendState* BlendState;
|
||||
FLOAT BlendFactor[4];
|
||||
UINT SampleMask;
|
||||
UINT StencilRef;
|
||||
ID3D11DepthStencilState* DepthStencilState;
|
||||
ID3D11ShaderResourceView* PSShaderResource;
|
||||
ID3D11SamplerState* PSSampler;
|
||||
ID3D11PixelShader* PS;
|
||||
ID3D11VertexShader* VS;
|
||||
ID3D11GeometryShader* GS;
|
||||
UINT PSInstancesCount, VSInstancesCount, GSInstancesCount;
|
||||
ID3D11ClassInstance *PSInstances[256], *VSInstances[256], *GSInstances[256]; // 256 is max according to PSSetShader documentation
|
||||
D3D11_PRIMITIVE_TOPOLOGY PrimitiveTopology;
|
||||
ID3D11Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer;
|
||||
UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset;
|
||||
DXGI_FORMAT IndexBufferFormat;
|
||||
ID3D11InputLayout* InputLayout;
|
||||
};
|
||||
BACKUP_DX11_STATE old = {};
|
||||
old.ScissorRectsCount = old.ViewportsCount = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
|
||||
ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects);
|
||||
ctx->RSGetViewports(&old.ViewportsCount, old.Viewports);
|
||||
ctx->RSGetState(&old.RS);
|
||||
ctx->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask);
|
||||
ctx->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef);
|
||||
ctx->PSGetShaderResources(0, 1, &old.PSShaderResource);
|
||||
ctx->PSGetSamplers(0, 1, &old.PSSampler);
|
||||
old.PSInstancesCount = old.VSInstancesCount = old.GSInstancesCount = 256;
|
||||
ctx->PSGetShader(&old.PS, old.PSInstances, &old.PSInstancesCount);
|
||||
ctx->VSGetShader(&old.VS, old.VSInstances, &old.VSInstancesCount);
|
||||
ctx->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer);
|
||||
ctx->GSGetShader(&old.GS, old.GSInstances, &old.GSInstancesCount);
|
||||
|
||||
ctx->IAGetPrimitiveTopology(&old.PrimitiveTopology);
|
||||
ctx->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset);
|
||||
ctx->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset);
|
||||
ctx->IAGetInputLayout(&old.InputLayout);
|
||||
|
||||
// Setup desired DX state
|
||||
ImGui_ImplDX11_SetupRenderState(draw_data, ctx);
|
||||
|
||||
// Render command lists
|
||||
// (Because we merged all buffers into a single one, we maintain our own offset into them)
|
||||
int global_idx_offset = 0;
|
||||
int global_vtx_offset = 0;
|
||||
ImVec2 clip_off = draw_data->DisplayPos;
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||
if (pcmd->UserCallback != NULL)
|
||||
{
|
||||
// User callback, registered via ImDrawList::AddCallback()
|
||||
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||
ImGui_ImplDX11_SetupRenderState(draw_data, ctx);
|
||||
else
|
||||
pcmd->UserCallback(cmd_list, pcmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
|
||||
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
|
||||
if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
|
||||
continue;
|
||||
|
||||
// Apply scissor/clipping rectangle
|
||||
const D3D11_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
|
||||
ctx->RSSetScissorRects(1, &r);
|
||||
|
||||
// Bind texture, Draw
|
||||
ID3D11ShaderResourceView* texture_srv = (ID3D11ShaderResourceView*)pcmd->GetTexID();
|
||||
ctx->PSSetShaderResources(0, 1, &texture_srv);
|
||||
ctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset);
|
||||
}
|
||||
}
|
||||
global_idx_offset += cmd_list->IdxBuffer.Size;
|
||||
global_vtx_offset += cmd_list->VtxBuffer.Size;
|
||||
}
|
||||
|
||||
// Restore modified DX state
|
||||
ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects);
|
||||
ctx->RSSetViewports(old.ViewportsCount, old.Viewports);
|
||||
ctx->RSSetState(old.RS); if (old.RS) old.RS->Release();
|
||||
ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release();
|
||||
ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release();
|
||||
ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release();
|
||||
ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release();
|
||||
ctx->PSSetShader(old.PS, old.PSInstances, old.PSInstancesCount); if (old.PS) old.PS->Release();
|
||||
for (UINT i = 0; i < old.PSInstancesCount; i++) if (old.PSInstances[i]) old.PSInstances[i]->Release();
|
||||
ctx->VSSetShader(old.VS, old.VSInstances, old.VSInstancesCount); if (old.VS) old.VS->Release();
|
||||
ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release();
|
||||
ctx->GSSetShader(old.GS, old.GSInstances, old.GSInstancesCount); if (old.GS) old.GS->Release();
|
||||
for (UINT i = 0; i < old.VSInstancesCount; i++) if (old.VSInstances[i]) old.VSInstances[i]->Release();
|
||||
ctx->IASetPrimitiveTopology(old.PrimitiveTopology);
|
||||
ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release();
|
||||
ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release();
|
||||
ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release();
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX11_CreateFontsTexture()
|
||||
{
|
||||
// Build texture atlas
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||
unsigned char* pixels;
|
||||
int width, height;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||
|
||||
// Upload texture to graphics system
|
||||
{
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
ZeroMemory(&desc, sizeof(desc));
|
||||
desc.Width = width;
|
||||
desc.Height = height;
|
||||
desc.MipLevels = 1;
|
||||
desc.ArraySize = 1;
|
||||
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.Usage = D3D11_USAGE_DEFAULT;
|
||||
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||
desc.CPUAccessFlags = 0;
|
||||
|
||||
ID3D11Texture2D* pTexture = NULL;
|
||||
D3D11_SUBRESOURCE_DATA subResource;
|
||||
subResource.pSysMem = pixels;
|
||||
subResource.SysMemPitch = desc.Width * 4;
|
||||
subResource.SysMemSlicePitch = 0;
|
||||
bd->pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
|
||||
IM_ASSERT(pTexture != NULL);
|
||||
|
||||
// Create texture view
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
|
||||
ZeroMemory(&srvDesc, sizeof(srvDesc));
|
||||
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
srvDesc.Texture2D.MipLevels = desc.MipLevels;
|
||||
srvDesc.Texture2D.MostDetailedMip = 0;
|
||||
bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &bd->pFontTextureView);
|
||||
pTexture->Release();
|
||||
}
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->SetTexID((ImTextureID)bd->pFontTextureView);
|
||||
|
||||
// Create texture sampler
|
||||
{
|
||||
D3D11_SAMPLER_DESC desc;
|
||||
ZeroMemory(&desc, sizeof(desc));
|
||||
desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
|
||||
desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
desc.MipLODBias = 0.f;
|
||||
desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
|
||||
desc.MinLOD = 0.f;
|
||||
desc.MaxLOD = 0.f;
|
||||
bd->pd3dDevice->CreateSamplerState(&desc, &bd->pFontSampler);
|
||||
}
|
||||
}
|
||||
|
||||
bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||
{
|
||||
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||
if (!bd->pd3dDevice)
|
||||
return false;
|
||||
if (bd->pFontSampler)
|
||||
ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||
|
||||
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
|
||||
// If you would like to use this DX11 sample code but remove this dependency you can:
|
||||
// 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
|
||||
// 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
|
||||
// See https://github.com/ocornut/imgui/pull/638 for sources and details.
|
||||
|
||||
// Create the vertex shader
|
||||
{
|
||||
static const char* vertexShader =
|
||||
"cbuffer vertexBuffer : register(b0) \
|
||||
{\
|
||||
float4x4 ProjectionMatrix; \
|
||||
};\
|
||||
struct VS_INPUT\
|
||||
{\
|
||||
float2 pos : POSITION;\
|
||||
float4 col : COLOR0;\
|
||||
float2 uv : TEXCOORD0;\
|
||||
};\
|
||||
\
|
||||
struct PS_INPUT\
|
||||
{\
|
||||
float4 pos : SV_POSITION;\
|
||||
float4 col : COLOR0;\
|
||||
float2 uv : TEXCOORD0;\
|
||||
};\
|
||||
\
|
||||
PS_INPUT main(VS_INPUT input)\
|
||||
{\
|
||||
PS_INPUT output;\
|
||||
output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\
|
||||
output.col = input.col;\
|
||||
output.uv = input.uv;\
|
||||
return output;\
|
||||
}";
|
||||
|
||||
ID3DBlob* vertexShaderBlob;
|
||||
if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &vertexShaderBlob, NULL)))
|
||||
return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||
if (bd->pd3dDevice->CreateVertexShader(vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), NULL, &bd->pVertexShader) != S_OK)
|
||||
{
|
||||
vertexShaderBlob->Release();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create the input layout
|
||||
D3D11_INPUT_ELEMENT_DESC local_layout[] =
|
||||
{
|
||||
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, pos), D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)IM_OFFSETOF(ImDrawVert, col), D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||
};
|
||||
if (bd->pd3dDevice->CreateInputLayout(local_layout, 3, vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &bd->pInputLayout) != S_OK)
|
||||
{
|
||||
vertexShaderBlob->Release();
|
||||
return false;
|
||||
}
|
||||
vertexShaderBlob->Release();
|
||||
|
||||
// Create the constant buffer
|
||||
{
|
||||
D3D11_BUFFER_DESC desc;
|
||||
desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
|
||||
desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
desc.MiscFlags = 0;
|
||||
bd->pd3dDevice->CreateBuffer(&desc, NULL, &bd->pVertexConstantBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
// Create the pixel shader
|
||||
{
|
||||
static const char* pixelShader =
|
||||
"struct PS_INPUT\
|
||||
{\
|
||||
float4 pos : SV_POSITION;\
|
||||
float4 col : COLOR0;\
|
||||
float2 uv : TEXCOORD0;\
|
||||
};\
|
||||
sampler sampler0;\
|
||||
Texture2D texture0;\
|
||||
\
|
||||
float4 main(PS_INPUT input) : SV_Target\
|
||||
{\
|
||||
float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
|
||||
return out_col; \
|
||||
}";
|
||||
|
||||
ID3DBlob* pixelShaderBlob;
|
||||
if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &pixelShaderBlob, NULL)))
|
||||
return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||
if (bd->pd3dDevice->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), NULL, &bd->pPixelShader) != S_OK)
|
||||
{
|
||||
pixelShaderBlob->Release();
|
||||
return false;
|
||||
}
|
||||
pixelShaderBlob->Release();
|
||||
}
|
||||
|
||||
// Create the blending setup
|
||||
{
|
||||
D3D11_BLEND_DESC desc;
|
||||
ZeroMemory(&desc, sizeof(desc));
|
||||
desc.AlphaToCoverageEnable = false;
|
||||
desc.RenderTarget[0].BlendEnable = true;
|
||||
desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
|
||||
desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
|
||||
desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
|
||||
desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
|
||||
desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
|
||||
desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
||||
desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
||||
bd->pd3dDevice->CreateBlendState(&desc, &bd->pBlendState);
|
||||
}
|
||||
|
||||
// Create the rasterizer state
|
||||
{
|
||||
D3D11_RASTERIZER_DESC desc;
|
||||
ZeroMemory(&desc, sizeof(desc));
|
||||
desc.FillMode = D3D11_FILL_SOLID;
|
||||
desc.CullMode = D3D11_CULL_NONE;
|
||||
desc.ScissorEnable = true;
|
||||
desc.DepthClipEnable = true;
|
||||
bd->pd3dDevice->CreateRasterizerState(&desc, &bd->pRasterizerState);
|
||||
}
|
||||
|
||||
// Create depth-stencil State
|
||||
{
|
||||
D3D11_DEPTH_STENCIL_DESC desc;
|
||||
ZeroMemory(&desc, sizeof(desc));
|
||||
desc.DepthEnable = false;
|
||||
desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
|
||||
desc.DepthFunc = D3D11_COMPARISON_ALWAYS;
|
||||
desc.StencilEnable = false;
|
||||
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
|
||||
desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
|
||||
desc.BackFace = desc.FrontFace;
|
||||
bd->pd3dDevice->CreateDepthStencilState(&desc, &bd->pDepthStencilState);
|
||||
}
|
||||
|
||||
ImGui_ImplDX11_CreateFontsTexture();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplDX11_InvalidateDeviceObjects()
|
||||
{
|
||||
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||
if (!bd->pd3dDevice)
|
||||
return;
|
||||
|
||||
if (bd->pFontSampler) { bd->pFontSampler->Release(); bd->pFontSampler = NULL; }
|
||||
if (bd->pFontTextureView) { bd->pFontTextureView->Release(); bd->pFontTextureView = NULL; ImGui::GetIO().Fonts->SetTexID(NULL); } // We copied data->pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
||||
if (bd->pIB) { bd->pIB->Release(); bd->pIB = NULL; }
|
||||
if (bd->pVB) { bd->pVB->Release(); bd->pVB = NULL; }
|
||||
if (bd->pBlendState) { bd->pBlendState->Release(); bd->pBlendState = NULL; }
|
||||
if (bd->pDepthStencilState) { bd->pDepthStencilState->Release(); bd->pDepthStencilState = NULL; }
|
||||
if (bd->pRasterizerState) { bd->pRasterizerState->Release(); bd->pRasterizerState = NULL; }
|
||||
if (bd->pPixelShader) { bd->pPixelShader->Release(); bd->pPixelShader = NULL; }
|
||||
if (bd->pVertexConstantBuffer) { bd->pVertexConstantBuffer->Release(); bd->pVertexConstantBuffer = NULL; }
|
||||
if (bd->pInputLayout) { bd->pInputLayout->Release(); bd->pInputLayout = NULL; }
|
||||
if (bd->pVertexShader) { bd->pVertexShader->Release(); bd->pVertexShader = NULL; }
|
||||
}
|
||||
|
||||
bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
|
||||
|
||||
// Setup backend capabilities flags
|
||||
ImGui_ImplDX11_Data* bd = IM_NEW(ImGui_ImplDX11_Data)();
|
||||
io.BackendRendererUserData = (void*)bd;
|
||||
io.BackendRendererName = "imgui_impl_dx11";
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
|
||||
|
||||
// Get factory from device
|
||||
IDXGIDevice* pDXGIDevice = NULL;
|
||||
IDXGIAdapter* pDXGIAdapter = NULL;
|
||||
IDXGIFactory* pFactory = NULL;
|
||||
|
||||
if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
|
||||
if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
|
||||
if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
|
||||
{
|
||||
bd->pd3dDevice = device;
|
||||
bd->pd3dDeviceContext = device_context;
|
||||
bd->pFactory = pFactory;
|
||||
}
|
||||
if (pDXGIDevice) pDXGIDevice->Release();
|
||||
if (pDXGIAdapter) pDXGIAdapter->Release();
|
||||
bd->pd3dDevice->AddRef();
|
||||
bd->pd3dDeviceContext->AddRef();
|
||||
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
ImGui_ImplDX11_InitPlatformInterface();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplDX11_Shutdown()
|
||||
{
|
||||
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||
IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui_ImplDX11_ShutdownPlatformInterface();
|
||||
ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||
if (bd->pFactory) { bd->pFactory->Release(); }
|
||||
if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
|
||||
if (bd->pd3dDeviceContext) { bd->pd3dDeviceContext->Release(); }
|
||||
io.BackendRendererName = NULL;
|
||||
io.BackendRendererUserData = NULL;
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
void ImGui_ImplDX11_NewFrame()
|
||||
{
|
||||
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplDX11_Init()?");
|
||||
|
||||
if (!bd->pFontSampler)
|
||||
ImGui_ImplDX11_CreateDeviceObjects();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
|
||||
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
|
||||
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Helper structure we store in the void* RenderUserData field of each ImGuiViewport to easily retrieve our backend data.
|
||||
struct ImGui_ImplDX11_ViewportData
|
||||
{
|
||||
IDXGISwapChain* SwapChain;
|
||||
ID3D11RenderTargetView* RTView;
|
||||
|
||||
ImGui_ImplDX11_ViewportData() { SwapChain = NULL; RTView = NULL; }
|
||||
~ImGui_ImplDX11_ViewportData() { IM_ASSERT(SwapChain == NULL && RTView == NULL); }
|
||||
};
|
||||
|
||||
static void ImGui_ImplDX11_CreateWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||
ImGui_ImplDX11_ViewportData* vd = IM_NEW(ImGui_ImplDX11_ViewportData)();
|
||||
viewport->RendererUserData = vd;
|
||||
|
||||
// PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL_Window*).
|
||||
// Some backend will leave PlatformHandleRaw NULL, in which case we assume PlatformHandle will contain the HWND.
|
||||
HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle;
|
||||
IM_ASSERT(hwnd != 0);
|
||||
|
||||
// Create swap chain
|
||||
DXGI_SWAP_CHAIN_DESC sd;
|
||||
ZeroMemory(&sd, sizeof(sd));
|
||||
sd.BufferDesc.Width = (UINT)viewport->Size.x;
|
||||
sd.BufferDesc.Height = (UINT)viewport->Size.y;
|
||||
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
sd.SampleDesc.Count = 1;
|
||||
sd.SampleDesc.Quality = 0;
|
||||
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
sd.BufferCount = 1;
|
||||
sd.OutputWindow = hwnd;
|
||||
sd.Windowed = TRUE;
|
||||
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
|
||||
sd.Flags = 0;
|
||||
|
||||
IM_ASSERT(vd->SwapChain == NULL && vd->RTView == NULL);
|
||||
bd->pFactory->CreateSwapChain(bd->pd3dDevice, &sd, &vd->SwapChain);
|
||||
|
||||
// Create the render target
|
||||
if (vd->SwapChain)
|
||||
{
|
||||
ID3D11Texture2D* pBackBuffer;
|
||||
vd->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
|
||||
bd->pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &vd->RTView);
|
||||
pBackBuffer->Release();
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX11_DestroyWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
// The main viewport (owned by the application) will always have RendererUserData == NULL since we didn't create the data for it.
|
||||
if (ImGui_ImplDX11_ViewportData* vd = (ImGui_ImplDX11_ViewportData*)viewport->RendererUserData)
|
||||
{
|
||||
if (vd->SwapChain)
|
||||
vd->SwapChain->Release();
|
||||
vd->SwapChain = NULL;
|
||||
if (vd->RTView)
|
||||
vd->RTView->Release();
|
||||
vd->RTView = NULL;
|
||||
IM_DELETE(vd);
|
||||
}
|
||||
viewport->RendererUserData = NULL;
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX11_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
|
||||
{
|
||||
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||
ImGui_ImplDX11_ViewportData* vd = (ImGui_ImplDX11_ViewportData*)viewport->RendererUserData;
|
||||
if (vd->RTView)
|
||||
{
|
||||
vd->RTView->Release();
|
||||
vd->RTView = NULL;
|
||||
}
|
||||
if (vd->SwapChain)
|
||||
{
|
||||
ID3D11Texture2D* pBackBuffer = NULL;
|
||||
vd->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, DXGI_FORMAT_UNKNOWN, 0);
|
||||
vd->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
|
||||
if (pBackBuffer == NULL) { fprintf(stderr, "ImGui_ImplDX11_SetWindowSize() failed creating buffers.\n"); return; }
|
||||
bd->pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &vd->RTView);
|
||||
pBackBuffer->Release();
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX11_RenderWindow(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||
ImGui_ImplDX11_ViewportData* vd = (ImGui_ImplDX11_ViewportData*)viewport->RendererUserData;
|
||||
ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
bd->pd3dDeviceContext->OMSetRenderTargets(1, &vd->RTView, NULL);
|
||||
if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
|
||||
bd->pd3dDeviceContext->ClearRenderTargetView(vd->RTView, (float*)&clear_color);
|
||||
ImGui_ImplDX11_RenderDrawData(viewport->DrawData);
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX11_SwapBuffers(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplDX11_ViewportData* vd = (ImGui_ImplDX11_ViewportData*)viewport->RendererUserData;
|
||||
vd->SwapChain->Present(0, 0); // Present without vsync
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX11_InitPlatformInterface()
|
||||
{
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Renderer_CreateWindow = ImGui_ImplDX11_CreateWindow;
|
||||
platform_io.Renderer_DestroyWindow = ImGui_ImplDX11_DestroyWindow;
|
||||
platform_io.Renderer_SetWindowSize = ImGui_ImplDX11_SetWindowSize;
|
||||
platform_io.Renderer_RenderWindow = ImGui_ImplDX11_RenderWindow;
|
||||
platform_io.Renderer_SwapBuffers = ImGui_ImplDX11_SwapBuffers;
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX11_ShutdownPlatformInterface()
|
||||
{
|
||||
ImGui::DestroyPlatformWindows();
|
||||
}
|
||||
27
samples/external/Imgui/imgui-docking/backends/imgui_impl_dx11.h
vendored
Normal file
27
samples/external/Imgui/imgui-docking/backends/imgui_impl_dx11.h
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
// dear imgui: Renderer Backend for DirectX11
|
||||
// This needs to be used along with a Platform Backend (e.g. Win32)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Multi-viewport support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
struct ID3D11Device;
|
||||
struct ID3D11DeviceContext;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context);
|
||||
IMGUI_IMPL_API void ImGui_ImplDX11_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplDX11_NewFrame();
|
||||
IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data);
|
||||
|
||||
// Use if you want to reset your rendering device without losing Dear ImGui state.
|
||||
IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||
IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects();
|
||||
1073
samples/external/Imgui/imgui-docking/backends/imgui_impl_dx12.cpp
vendored
Normal file
1073
samples/external/Imgui/imgui-docking/backends/imgui_impl_dx12.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
40
samples/external/Imgui/imgui-docking/backends/imgui_impl_dx12.h
vendored
Normal file
40
samples/external/Imgui/imgui-docking/backends/imgui_impl_dx12.h
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// dear imgui: Renderer Backend for DirectX12
|
||||
// This needs to be used along with a Platform Backend (e.g. Win32)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Multi-viewport support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
|
||||
// Important: to compile on 32-bit systems, this backend requires code to be compiled with '#define ImTextureID ImU64'.
|
||||
// This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*.
|
||||
// This define is set in the example .vcxproj file and need to be replicated in your app or by adding it to your imconfig.h file.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
#include <dxgiformat.h> // DXGI_FORMAT
|
||||
|
||||
struct ID3D12Device;
|
||||
struct ID3D12DescriptorHeap;
|
||||
struct ID3D12GraphicsCommandList;
|
||||
struct D3D12_CPU_DESCRIPTOR_HANDLE;
|
||||
struct D3D12_GPU_DESCRIPTOR_HANDLE;
|
||||
|
||||
// cmd_list is the command list that the implementation will use to render imgui draw lists.
|
||||
// Before calling the render function, caller must prepare cmd_list by resetting it and setting the appropriate
|
||||
// render target and descriptor heap that contains font_srv_cpu_desc_handle/font_srv_gpu_desc_handle.
|
||||
// font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture.
|
||||
IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* cbv_srv_heap,
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle);
|
||||
IMGUI_IMPL_API void ImGui_ImplDX12_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplDX12_NewFrame();
|
||||
IMGUI_IMPL_API void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* graphics_command_list);
|
||||
|
||||
// Use if you want to reset your rendering device without losing Dear ImGui state.
|
||||
IMGUI_IMPL_API void ImGui_ImplDX12_InvalidateDeviceObjects();
|
||||
IMGUI_IMPL_API bool ImGui_ImplDX12_CreateDeviceObjects();
|
||||
540
samples/external/Imgui/imgui-docking/backends/imgui_impl_dx9.cpp
vendored
Normal file
540
samples/external/Imgui/imgui-docking/backends/imgui_impl_dx9.cpp
vendored
Normal file
@@ -0,0 +1,540 @@
|
||||
// dear imgui: Renderer Backend for DirectX9
|
||||
// This needs to be used along with a Platform Backend (e.g. Win32)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Multi-viewport support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
|
||||
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||
// 2021-06-25: DirectX9: Explicitly disable texture state stages after >= 1.
|
||||
// 2021-05-19: DirectX9: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||
// 2021-04-23: DirectX9: Explicitly setting up more graphics states to increase compatibility with unusual non-default states.
|
||||
// 2021-03-18: DirectX9: Calling IDirect3DStateBlock9::Capture() after CreateStateBlock() as a workaround for state restoring issues (see #3857).
|
||||
// 2021-03-03: DirectX9: Added support for IMGUI_USE_BGRA_PACKED_COLOR in user's imconfig file.
|
||||
// 2021-02-18: DirectX9: Change blending equation to preserve alpha in output buffer.
|
||||
// 2019-05-29: DirectX9: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||
// 2019-04-30: DirectX9: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||
// 2019-03-29: Misc: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects().
|
||||
// 2019-01-16: Misc: Disabled fog before drawing UI's. Fixes issue #2288.
|
||||
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||
// 2018-06-08: Misc: Extracted imgui_impl_dx9.cpp/.h away from the old combined DX9+Win32 example.
|
||||
// 2018-06-08: DirectX9: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
||||
// 2018-05-07: Render: Saving/restoring Transform because they don't seem to be included in the StateBlock. Setting shading mode to Gouraud.
|
||||
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX9_RenderDrawData() in the .h file so you can call it yourself.
|
||||
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_dx9.h"
|
||||
|
||||
// DirectX
|
||||
#include <d3d9.h>
|
||||
|
||||
// DirectX data
|
||||
struct ImGui_ImplDX9_Data
|
||||
{
|
||||
LPDIRECT3DDEVICE9 pd3dDevice;
|
||||
LPDIRECT3DVERTEXBUFFER9 pVB;
|
||||
LPDIRECT3DINDEXBUFFER9 pIB;
|
||||
LPDIRECT3DTEXTURE9 FontTexture;
|
||||
int VertexBufferSize;
|
||||
int IndexBufferSize;
|
||||
|
||||
ImGui_ImplDX9_Data() { memset(this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }
|
||||
};
|
||||
|
||||
struct CUSTOMVERTEX
|
||||
{
|
||||
float pos[3];
|
||||
D3DCOLOR col;
|
||||
float uv[2];
|
||||
};
|
||||
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
|
||||
|
||||
#ifdef IMGUI_USE_BGRA_PACKED_COLOR
|
||||
#define IMGUI_COL_TO_DX9_ARGB(_COL) (_COL)
|
||||
#else
|
||||
#define IMGUI_COL_TO_DX9_ARGB(_COL) (((_COL) & 0xFF00FF00) | (((_COL) & 0xFF0000) >> 16) | (((_COL) & 0xFF) << 16))
|
||||
#endif
|
||||
|
||||
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||
static ImGui_ImplDX9_Data* ImGui_ImplDX9_GetBackendData()
|
||||
{
|
||||
return ImGui::GetCurrentContext() ? (ImGui_ImplDX9_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
|
||||
}
|
||||
|
||||
// Forward Declarations
|
||||
static void ImGui_ImplDX9_InitPlatformInterface();
|
||||
static void ImGui_ImplDX9_ShutdownPlatformInterface();
|
||||
static void ImGui_ImplDX9_CreateDeviceObjectsForPlatformWindows();
|
||||
static void ImGui_ImplDX9_InvalidateDeviceObjectsForPlatformWindows();
|
||||
|
||||
// Functions
|
||||
static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data)
|
||||
{
|
||||
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||
|
||||
// Setup viewport
|
||||
D3DVIEWPORT9 vp;
|
||||
vp.X = vp.Y = 0;
|
||||
vp.Width = (DWORD)draw_data->DisplaySize.x;
|
||||
vp.Height = (DWORD)draw_data->DisplaySize.y;
|
||||
vp.MinZ = 0.0f;
|
||||
vp.MaxZ = 1.0f;
|
||||
bd->pd3dDevice->SetViewport(&vp);
|
||||
|
||||
// Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient)
|
||||
bd->pd3dDevice->SetPixelShader(NULL);
|
||||
bd->pd3dDevice->SetVertexShader(NULL);
|
||||
bd->pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
|
||||
bd->pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
|
||||
bd->pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
|
||||
bd->pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
|
||||
bd->pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
||||
bd->pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
|
||||
bd->pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
|
||||
bd->pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
|
||||
bd->pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
|
||||
bd->pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
|
||||
bd->pd3dDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
|
||||
bd->pd3dDevice->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE);
|
||||
bd->pd3dDevice->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_INVSRCALPHA);
|
||||
bd->pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
|
||||
bd->pd3dDevice->SetRenderState(D3DRS_FOGENABLE, FALSE);
|
||||
bd->pd3dDevice->SetRenderState(D3DRS_RANGEFOGENABLE, FALSE);
|
||||
bd->pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, FALSE);
|
||||
bd->pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
|
||||
bd->pd3dDevice->SetRenderState(D3DRS_CLIPPING, TRUE);
|
||||
bd->pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
|
||||
bd->pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
|
||||
bd->pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||
bd->pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
|
||||
bd->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
|
||||
bd->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
||||
bd->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
|
||||
bd->pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
|
||||
bd->pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
|
||||
bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
||||
bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
||||
|
||||
// Setup orthographic projection matrix
|
||||
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||
// Being agnostic of whether <d3dx9.h> or <DirectXMath.h> can be used, we aren't relying on D3DXMatrixIdentity()/D3DXMatrixOrthoOffCenterLH() or DirectX::XMMatrixIdentity()/DirectX::XMMatrixOrthographicOffCenterLH()
|
||||
{
|
||||
float L = draw_data->DisplayPos.x + 0.5f;
|
||||
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x + 0.5f;
|
||||
float T = draw_data->DisplayPos.y + 0.5f;
|
||||
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y + 0.5f;
|
||||
D3DMATRIX mat_identity = { { { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } } };
|
||||
D3DMATRIX mat_projection =
|
||||
{ { {
|
||||
2.0f/(R-L), 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 2.0f/(T-B), 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.5f, 0.0f,
|
||||
(L+R)/(L-R), (T+B)/(B-T), 0.5f, 1.0f
|
||||
} } };
|
||||
bd->pd3dDevice->SetTransform(D3DTS_WORLD, &mat_identity);
|
||||
bd->pd3dDevice->SetTransform(D3DTS_VIEW, &mat_identity);
|
||||
bd->pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_projection);
|
||||
}
|
||||
}
|
||||
|
||||
// Render function.
|
||||
void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
|
||||
{
|
||||
// Avoid rendering when minimized
|
||||
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
||||
return;
|
||||
|
||||
// Create and grow buffers if needed
|
||||
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||
if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount)
|
||||
{
|
||||
if (bd->pVB) { bd->pVB->Release(); bd->pVB = NULL; }
|
||||
bd->VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
||||
if (bd->pd3dDevice->CreateVertexBuffer(bd->VertexBufferSize * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &bd->pVB, NULL) < 0)
|
||||
return;
|
||||
}
|
||||
if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount)
|
||||
{
|
||||
if (bd->pIB) { bd->pIB->Release(); bd->pIB = NULL; }
|
||||
bd->IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
||||
if (bd->pd3dDevice->CreateIndexBuffer(bd->IndexBufferSize * sizeof(ImDrawIdx), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &bd->pIB, NULL) < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
// Backup the DX9 state
|
||||
IDirect3DStateBlock9* d3d9_state_block = NULL;
|
||||
if (bd->pd3dDevice->CreateStateBlock(D3DSBT_ALL, &d3d9_state_block) < 0)
|
||||
return;
|
||||
if (d3d9_state_block->Capture() < 0)
|
||||
{
|
||||
d3d9_state_block->Release();
|
||||
return;
|
||||
}
|
||||
|
||||
// Backup the DX9 transform (DX9 documentation suggests that it is included in the StateBlock but it doesn't appear to)
|
||||
D3DMATRIX last_world, last_view, last_projection;
|
||||
bd->pd3dDevice->GetTransform(D3DTS_WORLD, &last_world);
|
||||
bd->pd3dDevice->GetTransform(D3DTS_VIEW, &last_view);
|
||||
bd->pd3dDevice->GetTransform(D3DTS_PROJECTION, &last_projection);
|
||||
|
||||
// Allocate buffers
|
||||
CUSTOMVERTEX* vtx_dst;
|
||||
ImDrawIdx* idx_dst;
|
||||
if (bd->pVB->Lock(0, (UINT)(draw_data->TotalVtxCount * sizeof(CUSTOMVERTEX)), (void**)&vtx_dst, D3DLOCK_DISCARD) < 0)
|
||||
{
|
||||
d3d9_state_block->Release();
|
||||
return;
|
||||
}
|
||||
if (bd->pIB->Lock(0, (UINT)(draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (void**)&idx_dst, D3DLOCK_DISCARD) < 0)
|
||||
{
|
||||
bd->pVB->Unlock();
|
||||
d3d9_state_block->Release();
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy and convert all vertices into a single contiguous buffer, convert colors to DX9 default format.
|
||||
// FIXME-OPT: This is a minor waste of resource, the ideal is to use imconfig.h and
|
||||
// 1) to avoid repacking colors: #define IMGUI_USE_BGRA_PACKED_COLOR
|
||||
// 2) to avoid repacking vertices: #define IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert { ImVec2 pos; float z; ImU32 col; ImVec2 uv; }
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
const ImDrawVert* vtx_src = cmd_list->VtxBuffer.Data;
|
||||
for (int i = 0; i < cmd_list->VtxBuffer.Size; i++)
|
||||
{
|
||||
vtx_dst->pos[0] = vtx_src->pos.x;
|
||||
vtx_dst->pos[1] = vtx_src->pos.y;
|
||||
vtx_dst->pos[2] = 0.0f;
|
||||
vtx_dst->col = IMGUI_COL_TO_DX9_ARGB(vtx_src->col);
|
||||
vtx_dst->uv[0] = vtx_src->uv.x;
|
||||
vtx_dst->uv[1] = vtx_src->uv.y;
|
||||
vtx_dst++;
|
||||
vtx_src++;
|
||||
}
|
||||
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
|
||||
idx_dst += cmd_list->IdxBuffer.Size;
|
||||
}
|
||||
bd->pVB->Unlock();
|
||||
bd->pIB->Unlock();
|
||||
bd->pd3dDevice->SetStreamSource(0, bd->pVB, 0, sizeof(CUSTOMVERTEX));
|
||||
bd->pd3dDevice->SetIndices(bd->pIB);
|
||||
bd->pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
|
||||
|
||||
// Setup desired DX state
|
||||
ImGui_ImplDX9_SetupRenderState(draw_data);
|
||||
|
||||
// Render command lists
|
||||
// (Because we merged all buffers into a single one, we maintain our own offset into them)
|
||||
int global_vtx_offset = 0;
|
||||
int global_idx_offset = 0;
|
||||
ImVec2 clip_off = draw_data->DisplayPos;
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||
if (pcmd->UserCallback != NULL)
|
||||
{
|
||||
// User callback, registered via ImDrawList::AddCallback()
|
||||
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||
ImGui_ImplDX9_SetupRenderState(draw_data);
|
||||
else
|
||||
pcmd->UserCallback(cmd_list, pcmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
|
||||
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
|
||||
if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
|
||||
continue;
|
||||
|
||||
// Apply Scissor/clipping rectangle, Bind texture, Draw
|
||||
const RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
|
||||
const LPDIRECT3DTEXTURE9 texture = (LPDIRECT3DTEXTURE9)pcmd->GetTexID();
|
||||
bd->pd3dDevice->SetTexture(0, texture);
|
||||
bd->pd3dDevice->SetScissorRect(&r);
|
||||
bd->pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, pcmd->VtxOffset + global_vtx_offset, 0, (UINT)cmd_list->VtxBuffer.Size, pcmd->IdxOffset + global_idx_offset, pcmd->ElemCount / 3);
|
||||
}
|
||||
}
|
||||
global_idx_offset += cmd_list->IdxBuffer.Size;
|
||||
global_vtx_offset += cmd_list->VtxBuffer.Size;
|
||||
}
|
||||
|
||||
// When using multi-viewports, it appears that there's an odd logic in DirectX9 which prevent subsequent windows
|
||||
// from rendering until the first window submits at least one draw call, even once. That's our workaround. (see #2560)
|
||||
if (global_vtx_offset == 0)
|
||||
bd->pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 0, 0, 0);
|
||||
|
||||
// Restore the DX9 transform
|
||||
bd->pd3dDevice->SetTransform(D3DTS_WORLD, &last_world);
|
||||
bd->pd3dDevice->SetTransform(D3DTS_VIEW, &last_view);
|
||||
bd->pd3dDevice->SetTransform(D3DTS_PROJECTION, &last_projection);
|
||||
|
||||
// Restore the DX9 state
|
||||
d3d9_state_block->Apply();
|
||||
d3d9_state_block->Release();
|
||||
}
|
||||
|
||||
bool ImGui_ImplDX9_Init(IDirect3DDevice9* device)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
|
||||
|
||||
// Setup backend capabilities flags
|
||||
ImGui_ImplDX9_Data* bd = IM_NEW(ImGui_ImplDX9_Data)();
|
||||
io.BackendRendererUserData = (void*)bd;
|
||||
io.BackendRendererName = "imgui_impl_dx9";
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
|
||||
|
||||
bd->pd3dDevice = device;
|
||||
bd->pd3dDevice->AddRef();
|
||||
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
ImGui_ImplDX9_InitPlatformInterface();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplDX9_Shutdown()
|
||||
{
|
||||
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||
IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui_ImplDX9_ShutdownPlatformInterface();
|
||||
ImGui_ImplDX9_InvalidateDeviceObjects();
|
||||
if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
|
||||
io.BackendRendererName = NULL;
|
||||
io.BackendRendererUserData = NULL;
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
static bool ImGui_ImplDX9_CreateFontsTexture()
|
||||
{
|
||||
// Build texture atlas
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||
unsigned char* pixels;
|
||||
int width, height, bytes_per_pixel;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_per_pixel);
|
||||
|
||||
// Convert RGBA32 to BGRA32 (because RGBA32 is not well supported by DX9 devices)
|
||||
#ifndef IMGUI_USE_BGRA_PACKED_COLOR
|
||||
if (io.Fonts->TexPixelsUseColors)
|
||||
{
|
||||
ImU32* dst_start = (ImU32*)ImGui::MemAlloc((size_t)width * height * bytes_per_pixel);
|
||||
for (ImU32* src = (ImU32*)pixels, *dst = dst_start, *dst_end = dst_start + (size_t)width * height; dst < dst_end; src++, dst++)
|
||||
*dst = IMGUI_COL_TO_DX9_ARGB(*src);
|
||||
pixels = (unsigned char*)dst_start;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Upload texture to graphics system
|
||||
bd->FontTexture = NULL;
|
||||
if (bd->pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bd->FontTexture, NULL) < 0)
|
||||
return false;
|
||||
D3DLOCKED_RECT tex_locked_rect;
|
||||
if (bd->FontTexture->LockRect(0, &tex_locked_rect, NULL, 0) != D3D_OK)
|
||||
return false;
|
||||
for (int y = 0; y < height; y++)
|
||||
memcpy((unsigned char*)tex_locked_rect.pBits + (size_t)tex_locked_rect.Pitch * y, pixels + (size_t)width * bytes_per_pixel * y, (size_t)width * bytes_per_pixel);
|
||||
bd->FontTexture->UnlockRect(0);
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->SetTexID((ImTextureID)bd->FontTexture);
|
||||
|
||||
#ifndef IMGUI_USE_BGRA_PACKED_COLOR
|
||||
if (io.Fonts->TexPixelsUseColors)
|
||||
ImGui::MemFree(pixels);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImGui_ImplDX9_CreateDeviceObjects()
|
||||
{
|
||||
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||
if (!bd || !bd->pd3dDevice)
|
||||
return false;
|
||||
if (!ImGui_ImplDX9_CreateFontsTexture())
|
||||
return false;
|
||||
ImGui_ImplDX9_CreateDeviceObjectsForPlatformWindows();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplDX9_InvalidateDeviceObjects()
|
||||
{
|
||||
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||
if (!bd || !bd->pd3dDevice)
|
||||
return;
|
||||
if (bd->pVB) { bd->pVB->Release(); bd->pVB = NULL; }
|
||||
if (bd->pIB) { bd->pIB->Release(); bd->pIB = NULL; }
|
||||
if (bd->FontTexture) { bd->FontTexture->Release(); bd->FontTexture = NULL; ImGui::GetIO().Fonts->SetTexID(NULL); } // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
||||
ImGui_ImplDX9_InvalidateDeviceObjectsForPlatformWindows();
|
||||
}
|
||||
|
||||
void ImGui_ImplDX9_NewFrame()
|
||||
{
|
||||
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplDX9_Init()?");
|
||||
|
||||
if (!bd->FontTexture)
|
||||
ImGui_ImplDX9_CreateDeviceObjects();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
|
||||
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
|
||||
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Helper structure we store in the void* RenderUserData field of each ImGuiViewport to easily retrieve our backend data.
|
||||
struct ImGui_ImplDX9_ViewportData
|
||||
{
|
||||
IDirect3DSwapChain9* SwapChain;
|
||||
D3DPRESENT_PARAMETERS d3dpp;
|
||||
|
||||
ImGui_ImplDX9_ViewportData() { SwapChain = NULL; ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS)); }
|
||||
~ImGui_ImplDX9_ViewportData() { IM_ASSERT(SwapChain == NULL); }
|
||||
};
|
||||
|
||||
static void ImGui_ImplDX9_CreateWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||
ImGui_ImplDX9_ViewportData* vd = IM_NEW(ImGui_ImplDX9_ViewportData)();
|
||||
viewport->RendererUserData = vd;
|
||||
|
||||
// PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL_Window*).
|
||||
// Some backends will leave PlatformHandleRaw NULL, in which case we assume PlatformHandle will contain the HWND.
|
||||
HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle;
|
||||
IM_ASSERT(hwnd != 0);
|
||||
|
||||
ZeroMemory(&vd->d3dpp, sizeof(D3DPRESENT_PARAMETERS));
|
||||
vd->d3dpp.Windowed = TRUE;
|
||||
vd->d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
||||
vd->d3dpp.BackBufferWidth = (UINT)viewport->Size.x;
|
||||
vd->d3dpp.BackBufferHeight = (UINT)viewport->Size.y;
|
||||
vd->d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
|
||||
vd->d3dpp.hDeviceWindow = hwnd;
|
||||
vd->d3dpp.EnableAutoDepthStencil = FALSE;
|
||||
vd->d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
|
||||
vd->d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; // Present without vsync
|
||||
|
||||
HRESULT hr = bd->pd3dDevice->CreateAdditionalSwapChain(&vd->d3dpp, &vd->SwapChain); IM_UNUSED(hr);
|
||||
IM_ASSERT(hr == D3D_OK);
|
||||
IM_ASSERT(vd->SwapChain != NULL);
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX9_DestroyWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
// The main viewport (owned by the application) will always have RendererUserData == NULL since we didn't create the data for it.
|
||||
if (ImGui_ImplDX9_ViewportData* vd = (ImGui_ImplDX9_ViewportData*)viewport->RendererUserData)
|
||||
{
|
||||
if (vd->SwapChain)
|
||||
vd->SwapChain->Release();
|
||||
vd->SwapChain = NULL;
|
||||
ZeroMemory(&vd->d3dpp, sizeof(D3DPRESENT_PARAMETERS));
|
||||
IM_DELETE(vd);
|
||||
}
|
||||
viewport->RendererUserData = NULL;
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX9_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
|
||||
{
|
||||
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||
ImGui_ImplDX9_ViewportData* vd = (ImGui_ImplDX9_ViewportData*)viewport->RendererUserData;
|
||||
if (vd->SwapChain)
|
||||
{
|
||||
vd->SwapChain->Release();
|
||||
vd->SwapChain = NULL;
|
||||
vd->d3dpp.BackBufferWidth = (UINT)size.x;
|
||||
vd->d3dpp.BackBufferHeight = (UINT)size.y;
|
||||
HRESULT hr = bd->pd3dDevice->CreateAdditionalSwapChain(&vd->d3dpp, &vd->SwapChain); IM_UNUSED(hr);
|
||||
IM_ASSERT(hr == D3D_OK);
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX9_RenderWindow(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||
ImGui_ImplDX9_ViewportData* vd = (ImGui_ImplDX9_ViewportData*)viewport->RendererUserData;
|
||||
ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
LPDIRECT3DSURFACE9 render_target = NULL;
|
||||
LPDIRECT3DSURFACE9 last_render_target = NULL;
|
||||
LPDIRECT3DSURFACE9 last_depth_stencil = NULL;
|
||||
vd->SwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &render_target);
|
||||
bd->pd3dDevice->GetRenderTarget(0, &last_render_target);
|
||||
bd->pd3dDevice->GetDepthStencilSurface(&last_depth_stencil);
|
||||
bd->pd3dDevice->SetRenderTarget(0, render_target);
|
||||
bd->pd3dDevice->SetDepthStencilSurface(NULL);
|
||||
|
||||
if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
|
||||
{
|
||||
D3DCOLOR clear_col_dx = D3DCOLOR_RGBA((int)(clear_color.x*255.0f), (int)(clear_color.y*255.0f), (int)(clear_color.z*255.0f), (int)(clear_color.w*255.0f));
|
||||
bd->pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, clear_col_dx, 1.0f, 0);
|
||||
}
|
||||
|
||||
ImGui_ImplDX9_RenderDrawData(viewport->DrawData);
|
||||
|
||||
// Restore render target
|
||||
bd->pd3dDevice->SetRenderTarget(0, last_render_target);
|
||||
bd->pd3dDevice->SetDepthStencilSurface(last_depth_stencil);
|
||||
render_target->Release();
|
||||
last_render_target->Release();
|
||||
if (last_depth_stencil) last_depth_stencil->Release();
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX9_SwapBuffers(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplDX9_ViewportData* vd = (ImGui_ImplDX9_ViewportData*)viewport->RendererUserData;
|
||||
HRESULT hr = vd->SwapChain->Present(NULL, NULL, vd->d3dpp.hDeviceWindow, NULL, 0);
|
||||
// Let main application handle D3DERR_DEVICELOST by resetting the device.
|
||||
IM_ASSERT(hr == D3D_OK || hr == D3DERR_DEVICELOST);
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX9_InitPlatformInterface()
|
||||
{
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Renderer_CreateWindow = ImGui_ImplDX9_CreateWindow;
|
||||
platform_io.Renderer_DestroyWindow = ImGui_ImplDX9_DestroyWindow;
|
||||
platform_io.Renderer_SetWindowSize = ImGui_ImplDX9_SetWindowSize;
|
||||
platform_io.Renderer_RenderWindow = ImGui_ImplDX9_RenderWindow;
|
||||
platform_io.Renderer_SwapBuffers = ImGui_ImplDX9_SwapBuffers;
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX9_ShutdownPlatformInterface()
|
||||
{
|
||||
ImGui::DestroyPlatformWindows();
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX9_CreateDeviceObjectsForPlatformWindows()
|
||||
{
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
for (int i = 1; i < platform_io.Viewports.Size; i++)
|
||||
if (!platform_io.Viewports[i]->RendererUserData)
|
||||
ImGui_ImplDX9_CreateWindow(platform_io.Viewports[i]);
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX9_InvalidateDeviceObjectsForPlatformWindows()
|
||||
{
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
for (int i = 1; i < platform_io.Viewports.Size; i++)
|
||||
if (platform_io.Viewports[i]->RendererUserData)
|
||||
ImGui_ImplDX9_DestroyWindow(platform_io.Viewports[i]);
|
||||
}
|
||||
26
samples/external/Imgui/imgui-docking/backends/imgui_impl_dx9.h
vendored
Normal file
26
samples/external/Imgui/imgui-docking/backends/imgui_impl_dx9.h
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
// dear imgui: Renderer Backend for DirectX9
|
||||
// This needs to be used along with a Platform Backend (e.g. Win32)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Multi-viewport support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
struct IDirect3DDevice9;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplDX9_Init(IDirect3DDevice9* device);
|
||||
IMGUI_IMPL_API void ImGui_ImplDX9_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplDX9_NewFrame();
|
||||
IMGUI_IMPL_API void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data);
|
||||
|
||||
// Use if you want to reset your rendering device without losing Dear ImGui state.
|
||||
IMGUI_IMPL_API bool ImGui_ImplDX9_CreateDeviceObjects();
|
||||
IMGUI_IMPL_API void ImGui_ImplDX9_InvalidateDeviceObjects();
|
||||
965
samples/external/Imgui/imgui-docking/backends/imgui_impl_glfw.cpp
vendored
Normal file
965
samples/external/Imgui/imgui-docking/backends/imgui_impl_glfw.cpp
vendored
Normal file
@@ -0,0 +1,965 @@
|
||||
// dear imgui: Platform Backend for GLFW
|
||||
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..)
|
||||
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
|
||||
// (Requires: GLFW 3.1+. Prefer GLFW 3.3+ for full feature support.)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Clipboard support.
|
||||
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
|
||||
// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
|
||||
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
|
||||
// Issues:
|
||||
// [ ] Platform: Multi-viewport support: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor).
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
|
||||
// 2021-08-17: *BREAKING CHANGE*: Now using glfwSetWindowFocusCallback() to calling io.AddFocusEvent(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() and forward it to the backend via ImGui_ImplGlfw_WindowFocusCallback().
|
||||
// 2021-07-29: *BREAKING CHANGE*: Now using glfwSetCursorEnterCallback(). MousePos is correctly reported when the host platform window is hovered but not focused. If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() callback and forward it to the backend via ImGui_ImplGlfw_CursorEnterCallback().
|
||||
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||
// 2020-01-17: Inputs: Disable error callback while assigning mouse cursors because some X11 setup don't have them and it generates errors.
|
||||
// 2019-12-05: Inputs: Added support for new mouse cursors added in GLFW 3.4+ (resizing cursors, not allowed cursor).
|
||||
// 2019-10-18: Misc: Previously installed user callbacks are now restored on shutdown.
|
||||
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
|
||||
// 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter().
|
||||
// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
|
||||
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
|
||||
// 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them.
|
||||
// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
|
||||
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
|
||||
// 2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples.
|
||||
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
|
||||
// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value, passed to glfwSetCursor()).
|
||||
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
|
||||
// 2018-01-25: Inputs: Added gamepad support if ImGuiConfigFlags_NavEnableGamepad is set.
|
||||
// 2018-01-25: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
|
||||
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
|
||||
// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
|
||||
// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
|
||||
// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_glfw.h"
|
||||
|
||||
// GLFW
|
||||
#include <GLFW/glfw3.h>
|
||||
#ifdef _WIN32
|
||||
#undef APIENTRY
|
||||
#define GLFW_EXPOSE_NATIVE_WIN32
|
||||
#include <GLFW/glfw3native.h> // for glfwGetWin32Window
|
||||
#endif
|
||||
#define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ GLFW_FLOATING
|
||||
#define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_HOVERED
|
||||
#define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwSetWindowOpacity
|
||||
#define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorContentScale
|
||||
#define GLFW_HAS_VULKAN (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwCreateWindowSurface
|
||||
#define GLFW_HAS_FOCUS_WINDOW (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwFocusWindow
|
||||
#define GLFW_HAS_FOCUS_ON_SHOW (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_FOCUS_ON_SHOW
|
||||
#define GLFW_HAS_MONITOR_WORK_AREA (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorWorkarea
|
||||
#define GLFW_HAS_OSX_WINDOW_POS_FIX (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 + GLFW_VERSION_REVISION * 10 >= 3310) // 3.3.1+ Fixed: Resizing window repositions it on MacOS #1553
|
||||
#ifdef GLFW_RESIZE_NESW_CURSOR // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released?
|
||||
#define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR
|
||||
#else
|
||||
#define GLFW_HAS_NEW_CURSORS (0)
|
||||
#endif
|
||||
#ifdef GLFW_MOUSE_PASSTHROUGH // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2020-07-17 (passthrough)
|
||||
#define GLFW_HAS_MOUSE_PASSTHROUGH (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_MOUSE_PASSTHROUGH
|
||||
#else
|
||||
#define GLFW_HAS_MOUSE_PASSTHROUGH (0)
|
||||
#endif
|
||||
|
||||
// GLFW data
|
||||
enum GlfwClientApi
|
||||
{
|
||||
GlfwClientApi_Unknown,
|
||||
GlfwClientApi_OpenGL,
|
||||
GlfwClientApi_Vulkan
|
||||
};
|
||||
|
||||
struct ImGui_ImplGlfw_Data
|
||||
{
|
||||
GLFWwindow* Window;
|
||||
GlfwClientApi ClientApi;
|
||||
double Time;
|
||||
GLFWwindow* MouseWindow;
|
||||
bool MouseJustPressed[ImGuiMouseButton_COUNT];
|
||||
GLFWcursor* MouseCursors[ImGuiMouseCursor_COUNT];
|
||||
GLFWwindow* KeyOwnerWindows[512];
|
||||
bool InstalledCallbacks;
|
||||
bool WantUpdateMonitors;
|
||||
|
||||
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
|
||||
GLFWwindowfocusfun PrevUserCallbackWindowFocus;
|
||||
GLFWcursorenterfun PrevUserCallbackCursorEnter;
|
||||
GLFWmousebuttonfun PrevUserCallbackMousebutton;
|
||||
GLFWscrollfun PrevUserCallbackScroll;
|
||||
GLFWkeyfun PrevUserCallbackKey;
|
||||
GLFWcharfun PrevUserCallbackChar;
|
||||
GLFWmonitorfun PrevUserCallbackMonitor;
|
||||
|
||||
ImGui_ImplGlfw_Data() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
|
||||
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||
// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
|
||||
// - Because glfwPollEvents() process all windows and some events may be called outside of it, you will need to register your own callbacks
|
||||
// (passing install_callbacks=false in ImGui_ImplGlfw_InitXXX functions), set the current dear imgui context and then call our callbacks.
|
||||
// - Otherwise we may need to store a GLFWWindow* -> ImGuiContext* map and handle this in the backend, adding a little bit of extra complexity to it.
|
||||
// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
|
||||
static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData()
|
||||
{
|
||||
return ImGui::GetCurrentContext() ? (ImGui_ImplGlfw_Data*)ImGui::GetIO().BackendPlatformUserData : NULL;
|
||||
}
|
||||
|
||||
// Forward Declarations
|
||||
static void ImGui_ImplGlfw_UpdateMonitors();
|
||||
static void ImGui_ImplGlfw_InitPlatformInterface();
|
||||
static void ImGui_ImplGlfw_ShutdownPlatformInterface();
|
||||
|
||||
// Functions
|
||||
static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
|
||||
{
|
||||
return glfwGetClipboardString((GLFWwindow*)user_data);
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
|
||||
{
|
||||
glfwSetClipboardString((GLFWwindow*)user_data, text);
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
if (bd->PrevUserCallbackMousebutton != NULL && window == bd->Window)
|
||||
bd->PrevUserCallbackMousebutton(window, button, action, mods);
|
||||
|
||||
if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(bd->MouseJustPressed))
|
||||
bd->MouseJustPressed[button] = true;
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
if (bd->PrevUserCallbackScroll != NULL && window == bd->Window)
|
||||
bd->PrevUserCallbackScroll(window, xoffset, yoffset);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.MouseWheelH += (float)xoffset;
|
||||
io.MouseWheel += (float)yoffset;
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
if (bd->PrevUserCallbackKey != NULL && window == bd->Window)
|
||||
bd->PrevUserCallbackKey(window, key, scancode, action, mods);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (key >= 0 && key < IM_ARRAYSIZE(io.KeysDown))
|
||||
{
|
||||
if (action == GLFW_PRESS)
|
||||
{
|
||||
io.KeysDown[key] = true;
|
||||
bd->KeyOwnerWindows[key] = window;
|
||||
}
|
||||
if (action == GLFW_RELEASE)
|
||||
{
|
||||
io.KeysDown[key] = false;
|
||||
bd->KeyOwnerWindows[key] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Modifiers are not reliable across systems
|
||||
io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL];
|
||||
io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT];
|
||||
io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT];
|
||||
#ifdef _WIN32
|
||||
io.KeySuper = false;
|
||||
#else
|
||||
io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];
|
||||
#endif
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
if (bd->PrevUserCallbackWindowFocus != NULL && window == bd->Window)
|
||||
bd->PrevUserCallbackWindowFocus(window, focused);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.AddFocusEvent(focused != 0);
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
if (bd->PrevUserCallbackCursorEnter != NULL && window == bd->Window)
|
||||
bd->PrevUserCallbackCursorEnter(window, entered);
|
||||
|
||||
if (entered)
|
||||
bd->MouseWindow = window;
|
||||
if (!entered && bd->MouseWindow == window)
|
||||
bd->MouseWindow = NULL;
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
if (bd->PrevUserCallbackChar != NULL && window == bd->Window)
|
||||
bd->PrevUserCallbackChar(window, c);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.AddInputCharacter(c);
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
bd->WantUpdateMonitors = true;
|
||||
}
|
||||
|
||||
static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IM_ASSERT(io.BackendPlatformUserData == NULL && "Already initialized a platform backend!");
|
||||
|
||||
// Setup backend capabilities flags
|
||||
ImGui_ImplGlfw_Data* bd = IM_NEW(ImGui_ImplGlfw_Data)();
|
||||
io.BackendPlatformUserData = (void*)bd;
|
||||
io.BackendPlatformName = "imgui_impl_glfw";
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||
io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
|
||||
#if GLFW_HAS_MOUSE_PASSTHROUGH || (GLFW_HAS_WINDOW_HOVERED && defined(_WIN32))
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can set io.MouseHoveredViewport correctly (optional, not easy)
|
||||
#endif
|
||||
|
||||
bd->Window = window;
|
||||
bd->Time = 0.0;
|
||||
bd->WantUpdateMonitors = true;
|
||||
|
||||
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
|
||||
io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
|
||||
io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
|
||||
io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
|
||||
io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
|
||||
io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
|
||||
io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP;
|
||||
io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN;
|
||||
io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
|
||||
io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
|
||||
io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT;
|
||||
io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
|
||||
io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
|
||||
io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE;
|
||||
io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
|
||||
io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
|
||||
io.KeyMap[ImGuiKey_KeyPadEnter] = GLFW_KEY_KP_ENTER;
|
||||
io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
|
||||
io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
|
||||
io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
|
||||
io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
|
||||
io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
|
||||
io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
|
||||
|
||||
io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
|
||||
io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
|
||||
io.ClipboardUserData = bd->Window;
|
||||
|
||||
// Create mouse cursors
|
||||
// (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist,
|
||||
// GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting.
|
||||
// Missing cursors will return NULL and our _UpdateMouseCursor() function will use the Arrow cursor instead.)
|
||||
GLFWerrorfun prev_error_callback = glfwSetErrorCallback(NULL);
|
||||
bd->MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||
bd->MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
|
||||
bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR);
|
||||
bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR);
|
||||
bd->MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
|
||||
#if GLFW_HAS_NEW_CURSORS
|
||||
bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR);
|
||||
bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_RESIZE_NESW_CURSOR);
|
||||
bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR);
|
||||
bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_NOT_ALLOWED_CURSOR);
|
||||
#else
|
||||
bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||
bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||
bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||
bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||
#endif
|
||||
glfwSetErrorCallback(prev_error_callback);
|
||||
|
||||
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
|
||||
bd->PrevUserCallbackWindowFocus = NULL;
|
||||
bd->PrevUserCallbackMousebutton = NULL;
|
||||
bd->PrevUserCallbackScroll = NULL;
|
||||
bd->PrevUserCallbackKey = NULL;
|
||||
bd->PrevUserCallbackChar = NULL;
|
||||
bd->PrevUserCallbackMonitor = NULL;
|
||||
if (install_callbacks)
|
||||
{
|
||||
bd->InstalledCallbacks = true;
|
||||
bd->PrevUserCallbackWindowFocus = glfwSetWindowFocusCallback(window, ImGui_ImplGlfw_WindowFocusCallback);
|
||||
bd->PrevUserCallbackCursorEnter = glfwSetCursorEnterCallback(window, ImGui_ImplGlfw_CursorEnterCallback);
|
||||
bd->PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
|
||||
bd->PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
|
||||
bd->PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
|
||||
bd->PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
|
||||
bd->PrevUserCallbackMonitor = glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback);
|
||||
}
|
||||
|
||||
// Update monitors the first time (note: monitor callback are broken in GLFW 3.2 and earlier, see github.com/glfw/glfw/issues/784)
|
||||
ImGui_ImplGlfw_UpdateMonitors();
|
||||
glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback);
|
||||
|
||||
// Our mouse update function expect PlatformHandle to be filled for the main viewport
|
||||
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
||||
main_viewport->PlatformHandle = (void*)bd->Window;
|
||||
#ifdef _WIN32
|
||||
main_viewport->PlatformHandleRaw = glfwGetWin32Window(bd->Window);
|
||||
#endif
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
ImGui_ImplGlfw_InitPlatformInterface();
|
||||
|
||||
bd->ClientApi = client_api;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks)
|
||||
{
|
||||
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_OpenGL);
|
||||
}
|
||||
|
||||
bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks)
|
||||
{
|
||||
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan);
|
||||
}
|
||||
|
||||
bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks)
|
||||
{
|
||||
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Unknown);
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_Shutdown()
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
IM_ASSERT(bd != NULL && "No platform backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui_ImplGlfw_ShutdownPlatformInterface();
|
||||
|
||||
if (bd->InstalledCallbacks)
|
||||
{
|
||||
glfwSetWindowFocusCallback(bd->Window, bd->PrevUserCallbackWindowFocus);
|
||||
glfwSetCursorEnterCallback(bd->Window, bd->PrevUserCallbackCursorEnter);
|
||||
glfwSetMouseButtonCallback(bd->Window, bd->PrevUserCallbackMousebutton);
|
||||
glfwSetScrollCallback(bd->Window, bd->PrevUserCallbackScroll);
|
||||
glfwSetKeyCallback(bd->Window, bd->PrevUserCallbackKey);
|
||||
glfwSetCharCallback(bd->Window, bd->PrevUserCallbackChar);
|
||||
glfwSetMonitorCallback(bd->PrevUserCallbackMonitor);
|
||||
}
|
||||
|
||||
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
|
||||
glfwDestroyCursor(bd->MouseCursors[cursor_n]);
|
||||
|
||||
io.BackendPlatformName = NULL;
|
||||
io.BackendPlatformUserData = NULL;
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_UpdateMousePosAndButtons()
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
|
||||
const ImVec2 mouse_pos_prev = io.MousePos;
|
||||
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
||||
io.MouseHoveredViewport = 0;
|
||||
|
||||
// Update mouse buttons
|
||||
// (if a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame)
|
||||
for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
|
||||
{
|
||||
io.MouseDown[i] = bd->MouseJustPressed[i] || glfwGetMouseButton(bd->Window, i) != 0;
|
||||
bd->MouseJustPressed[i] = false;
|
||||
}
|
||||
|
||||
for (int n = 0; n < platform_io.Viewports.Size; n++)
|
||||
{
|
||||
ImGuiViewport* viewport = platform_io.Viewports[n];
|
||||
GLFWwindow* window = (GLFWwindow*)viewport->PlatformHandle;
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
const bool focused = true;
|
||||
#else
|
||||
const bool focused = glfwGetWindowAttrib(window, GLFW_FOCUSED) != 0;
|
||||
#endif
|
||||
GLFWwindow* mouse_window = (bd->MouseWindow == window || focused) ? window : NULL;
|
||||
|
||||
// Update mouse buttons
|
||||
if (focused)
|
||||
for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
|
||||
io.MouseDown[i] |= glfwGetMouseButton(window, i) != 0;
|
||||
|
||||
// Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
|
||||
// (When multi-viewports are enabled, all Dear ImGui positions are same as OS positions)
|
||||
if (io.WantSetMousePos && focused)
|
||||
glfwSetCursorPos(window, (double)(mouse_pos_prev.x - viewport->Pos.x), (double)(mouse_pos_prev.y - viewport->Pos.y));
|
||||
|
||||
// Set Dear ImGui mouse position from OS position
|
||||
if (mouse_window != NULL)
|
||||
{
|
||||
double mouse_x, mouse_y;
|
||||
glfwGetCursorPos(mouse_window, &mouse_x, &mouse_y);
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
{
|
||||
// Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
|
||||
int window_x, window_y;
|
||||
glfwGetWindowPos(window, &window_x, &window_y);
|
||||
io.MousePos = ImVec2((float)mouse_x + window_x, (float)mouse_y + window_y);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window)
|
||||
io.MousePos = ImVec2((float)mouse_x, (float)mouse_y);
|
||||
}
|
||||
}
|
||||
|
||||
// (Optional) When using multiple viewports: set io.MouseHoveredViewport to the viewport the OS mouse cursor is hovering.
|
||||
// Important: this information is not easy to provide and many high-level windowing library won't be able to provide it correctly, because
|
||||
// - This is _ignoring_ viewports with the ImGuiViewportFlags_NoInputs flag (pass-through windows).
|
||||
// - This is _regardless_ of whether another viewport is focused or being dragged from.
|
||||
// If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, imgui will ignore this field and infer the information by relying on the
|
||||
// rectangles and last focused time of every viewports it knows about. It will be unaware of other windows that may be sitting between or over your windows.
|
||||
// [GLFW] FIXME: This is currently only correct on Win32. See what we do below with the WM_NCHITTEST, missing an equivalent for other systems.
|
||||
// See https://github.com/glfw/glfw/issues/1236 if you want to help in making this a GLFW feature.
|
||||
#if GLFW_HAS_MOUSE_PASSTHROUGH || (GLFW_HAS_WINDOW_HOVERED && defined(_WIN32))
|
||||
const bool window_no_input = (viewport->Flags & ImGuiViewportFlags_NoInputs) != 0;
|
||||
#if GLFW_HAS_MOUSE_PASSTHROUGH
|
||||
glfwSetWindowAttrib(window, GLFW_MOUSE_PASSTHROUGH, window_no_input);
|
||||
#endif
|
||||
if (glfwGetWindowAttrib(window, GLFW_HOVERED) && !window_no_input)
|
||||
io.MouseHoveredViewport = viewport->ID;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_UpdateMouseCursor()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(bd->Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
|
||||
return;
|
||||
|
||||
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
for (int n = 0; n < platform_io.Viewports.Size; n++)
|
||||
{
|
||||
GLFWwindow* window = (GLFWwindow*)platform_io.Viewports[n]->PlatformHandle;
|
||||
if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
|
||||
{
|
||||
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
||||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Show OS mouse cursor
|
||||
// FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
|
||||
glfwSetCursor(window, bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]);
|
||||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_UpdateGamepads()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
memset(io.NavInputs, 0, sizeof(io.NavInputs));
|
||||
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
|
||||
return;
|
||||
|
||||
// Update gamepad inputs
|
||||
#define MAP_BUTTON(NAV_NO, BUTTON_NO) { if (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS) io.NavInputs[NAV_NO] = 1.0f; }
|
||||
#define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); if (v > 1.0f) v = 1.0f; if (io.NavInputs[NAV_NO] < v) io.NavInputs[NAV_NO] = v; }
|
||||
int axes_count = 0, buttons_count = 0;
|
||||
const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count);
|
||||
const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count);
|
||||
MAP_BUTTON(ImGuiNavInput_Activate, 0); // Cross / A
|
||||
MAP_BUTTON(ImGuiNavInput_Cancel, 1); // Circle / B
|
||||
MAP_BUTTON(ImGuiNavInput_Menu, 2); // Square / X
|
||||
MAP_BUTTON(ImGuiNavInput_Input, 3); // Triangle / Y
|
||||
MAP_BUTTON(ImGuiNavInput_DpadLeft, 13); // D-Pad Left
|
||||
MAP_BUTTON(ImGuiNavInput_DpadRight, 11); // D-Pad Right
|
||||
MAP_BUTTON(ImGuiNavInput_DpadUp, 10); // D-Pad Up
|
||||
MAP_BUTTON(ImGuiNavInput_DpadDown, 12); // D-Pad Down
|
||||
MAP_BUTTON(ImGuiNavInput_FocusPrev, 4); // L1 / LB
|
||||
MAP_BUTTON(ImGuiNavInput_FocusNext, 5); // R1 / RB
|
||||
MAP_BUTTON(ImGuiNavInput_TweakSlow, 4); // L1 / LB
|
||||
MAP_BUTTON(ImGuiNavInput_TweakFast, 5); // R1 / RB
|
||||
MAP_ANALOG(ImGuiNavInput_LStickLeft, 0, -0.3f, -0.9f);
|
||||
MAP_ANALOG(ImGuiNavInput_LStickRight,0, +0.3f, +0.9f);
|
||||
MAP_ANALOG(ImGuiNavInput_LStickUp, 1, +0.3f, +0.9f);
|
||||
MAP_ANALOG(ImGuiNavInput_LStickDown, 1, -0.3f, -0.9f);
|
||||
#undef MAP_BUTTON
|
||||
#undef MAP_ANALOG
|
||||
if (axes_count > 0 && buttons_count > 0)
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
|
||||
else
|
||||
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_UpdateMonitors()
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
int monitors_count = 0;
|
||||
GLFWmonitor** glfw_monitors = glfwGetMonitors(&monitors_count);
|
||||
platform_io.Monitors.resize(0);
|
||||
for (int n = 0; n < monitors_count; n++)
|
||||
{
|
||||
ImGuiPlatformMonitor monitor;
|
||||
int x, y;
|
||||
glfwGetMonitorPos(glfw_monitors[n], &x, &y);
|
||||
const GLFWvidmode* vid_mode = glfwGetVideoMode(glfw_monitors[n]);
|
||||
monitor.MainPos = monitor.WorkPos = ImVec2((float)x, (float)y);
|
||||
monitor.MainSize = monitor.WorkSize = ImVec2((float)vid_mode->width, (float)vid_mode->height);
|
||||
#if GLFW_HAS_MONITOR_WORK_AREA
|
||||
int w, h;
|
||||
glfwGetMonitorWorkarea(glfw_monitors[n], &x, &y, &w, &h);
|
||||
if (w > 0 && h > 0) // Workaround a small GLFW issue reporting zero on monitor changes: https://github.com/glfw/glfw/pull/1761
|
||||
{
|
||||
monitor.WorkPos = ImVec2((float)x, (float)y);
|
||||
monitor.WorkSize = ImVec2((float)w, (float)h);
|
||||
}
|
||||
#endif
|
||||
#if GLFW_HAS_PER_MONITOR_DPI
|
||||
// Warning: the validity of monitor DPI information on Windows depends on the application DPI awareness settings, which generally needs to be set in the manifest or at runtime.
|
||||
float x_scale, y_scale;
|
||||
glfwGetMonitorContentScale(glfw_monitors[n], &x_scale, &y_scale);
|
||||
monitor.DpiScale = x_scale;
|
||||
#endif
|
||||
platform_io.Monitors.push_back(monitor);
|
||||
}
|
||||
bd->WantUpdateMonitors = false;
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_NewFrame()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplGlfw_InitForXXX()?");
|
||||
|
||||
// Setup display size (every frame to accommodate for window resizing)
|
||||
int w, h;
|
||||
int display_w, display_h;
|
||||
glfwGetWindowSize(bd->Window, &w, &h);
|
||||
glfwGetFramebufferSize(bd->Window, &display_w, &display_h);
|
||||
io.DisplaySize = ImVec2((float)w, (float)h);
|
||||
if (w > 0 && h > 0)
|
||||
io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);
|
||||
if (bd->WantUpdateMonitors)
|
||||
ImGui_ImplGlfw_UpdateMonitors();
|
||||
|
||||
// Setup time step
|
||||
double current_time = glfwGetTime();
|
||||
io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f);
|
||||
bd->Time = current_time;
|
||||
|
||||
ImGui_ImplGlfw_UpdateMousePosAndButtons();
|
||||
ImGui_ImplGlfw_UpdateMouseCursor();
|
||||
|
||||
// Update game controllers (if enabled and available)
|
||||
ImGui_ImplGlfw_UpdateGamepads();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
|
||||
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
|
||||
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Helper structure we store in the void* RenderUserData field of each ImGuiViewport to easily retrieve our backend data.
|
||||
struct ImGui_ImplGlfw_ViewportData
|
||||
{
|
||||
GLFWwindow* Window;
|
||||
bool WindowOwned;
|
||||
int IgnoreWindowPosEventFrame;
|
||||
int IgnoreWindowSizeEventFrame;
|
||||
|
||||
ImGui_ImplGlfw_ViewportData() { Window = NULL; WindowOwned = false; IgnoreWindowSizeEventFrame = IgnoreWindowPosEventFrame = -1; }
|
||||
~ImGui_ImplGlfw_ViewportData() { IM_ASSERT(Window == NULL); }
|
||||
};
|
||||
|
||||
static void ImGui_ImplGlfw_WindowCloseCallback(GLFWwindow* window)
|
||||
{
|
||||
if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window))
|
||||
viewport->PlatformRequestClose = true;
|
||||
}
|
||||
|
||||
// GLFW may dispatch window pos/size events after calling glfwSetWindowPos()/glfwSetWindowSize().
|
||||
// However: depending on the platform the callback may be invoked at different time:
|
||||
// - on Windows it appears to be called within the glfwSetWindowPos()/glfwSetWindowSize() call
|
||||
// - on Linux it is queued and invoked during glfwPollEvents()
|
||||
// Because the event doesn't always fire on glfwSetWindowXXX() we use a frame counter tag to only
|
||||
// ignore recent glfwSetWindowXXX() calls.
|
||||
static void ImGui_ImplGlfw_WindowPosCallback(GLFWwindow* window, int, int)
|
||||
{
|
||||
if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window))
|
||||
{
|
||||
if (ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData)
|
||||
{
|
||||
bool ignore_event = (ImGui::GetFrameCount() <= vd->IgnoreWindowPosEventFrame + 1);
|
||||
//data->IgnoreWindowPosEventFrame = -1;
|
||||
if (ignore_event)
|
||||
return;
|
||||
}
|
||||
viewport->PlatformRequestMove = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_WindowSizeCallback(GLFWwindow* window, int, int)
|
||||
{
|
||||
if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window))
|
||||
{
|
||||
if (ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData)
|
||||
{
|
||||
bool ignore_event = (ImGui::GetFrameCount() <= vd->IgnoreWindowSizeEventFrame + 1);
|
||||
//data->IgnoreWindowSizeEventFrame = -1;
|
||||
if (ignore_event)
|
||||
return;
|
||||
}
|
||||
viewport->PlatformRequestResize = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_CreateWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
ImGui_ImplGlfw_ViewportData* vd = IM_NEW(ImGui_ImplGlfw_ViewportData)();
|
||||
viewport->PlatformUserData = vd;
|
||||
|
||||
// GLFW 3.2 unfortunately always set focus on glfwCreateWindow() if GLFW_VISIBLE is set, regardless of GLFW_FOCUSED
|
||||
// With GLFW 3.3, the hint GLFW_FOCUS_ON_SHOW fixes this problem
|
||||
glfwWindowHint(GLFW_VISIBLE, false);
|
||||
glfwWindowHint(GLFW_FOCUSED, false);
|
||||
#if GLFW_HAS_FOCUS_ON_SHOW
|
||||
glfwWindowHint(GLFW_FOCUS_ON_SHOW, false);
|
||||
#endif
|
||||
glfwWindowHint(GLFW_DECORATED, (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? false : true);
|
||||
#if GLFW_HAS_WINDOW_TOPMOST
|
||||
glfwWindowHint(GLFW_FLOATING, (viewport->Flags & ImGuiViewportFlags_TopMost) ? true : false);
|
||||
#endif
|
||||
GLFWwindow* share_window = (bd->ClientApi == GlfwClientApi_OpenGL) ? bd->Window : NULL;
|
||||
vd->Window = glfwCreateWindow((int)viewport->Size.x, (int)viewport->Size.y, "No Title Yet", NULL, share_window);
|
||||
vd->WindowOwned = true;
|
||||
viewport->PlatformHandle = (void*)vd->Window;
|
||||
#ifdef _WIN32
|
||||
viewport->PlatformHandleRaw = glfwGetWin32Window(vd->Window);
|
||||
#endif
|
||||
glfwSetWindowPos(vd->Window, (int)viewport->Pos.x, (int)viewport->Pos.y);
|
||||
|
||||
// Install GLFW callbacks for secondary viewports
|
||||
glfwSetWindowFocusCallback(vd->Window, ImGui_ImplGlfw_WindowFocusCallback);
|
||||
glfwSetCursorEnterCallback(vd->Window, ImGui_ImplGlfw_CursorEnterCallback);
|
||||
glfwSetMouseButtonCallback(vd->Window, ImGui_ImplGlfw_MouseButtonCallback);
|
||||
glfwSetScrollCallback(vd->Window, ImGui_ImplGlfw_ScrollCallback);
|
||||
glfwSetKeyCallback(vd->Window, ImGui_ImplGlfw_KeyCallback);
|
||||
glfwSetCharCallback(vd->Window, ImGui_ImplGlfw_CharCallback);
|
||||
glfwSetWindowCloseCallback(vd->Window, ImGui_ImplGlfw_WindowCloseCallback);
|
||||
glfwSetWindowPosCallback(vd->Window, ImGui_ImplGlfw_WindowPosCallback);
|
||||
glfwSetWindowSizeCallback(vd->Window, ImGui_ImplGlfw_WindowSizeCallback);
|
||||
if (bd->ClientApi == GlfwClientApi_OpenGL)
|
||||
{
|
||||
glfwMakeContextCurrent(vd->Window);
|
||||
glfwSwapInterval(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_DestroyWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
if (ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData)
|
||||
{
|
||||
if (vd->WindowOwned)
|
||||
{
|
||||
#if !GLFW_HAS_MOUSE_PASSTHROUGH && GLFW_HAS_WINDOW_HOVERED && defined(_WIN32)
|
||||
HWND hwnd = (HWND)viewport->PlatformHandleRaw;
|
||||
::RemovePropA(hwnd, "IMGUI_VIEWPORT");
|
||||
#endif
|
||||
|
||||
// Release any keys that were pressed in the window being destroyed and are still held down,
|
||||
// because we will not receive any release events after window is destroyed.
|
||||
for (int i = 0; i < IM_ARRAYSIZE(bd->KeyOwnerWindows); i++)
|
||||
if (bd->KeyOwnerWindows[i] == vd->Window)
|
||||
ImGui_ImplGlfw_KeyCallback(vd->Window, i, 0, GLFW_RELEASE, 0); // Later params are only used for main viewport, on which this function is never called.
|
||||
|
||||
glfwDestroyWindow(vd->Window);
|
||||
}
|
||||
vd->Window = NULL;
|
||||
IM_DELETE(vd);
|
||||
}
|
||||
viewport->PlatformUserData = viewport->PlatformHandle = NULL;
|
||||
}
|
||||
|
||||
// We have submitted https://github.com/glfw/glfw/pull/1568 to allow GLFW to support "transparent inputs".
|
||||
// In the meanwhile we implement custom per-platform workarounds here (FIXME-VIEWPORT: Implement same work-around for Linux/OSX!)
|
||||
#if !GLFW_HAS_MOUSE_PASSTHROUGH && GLFW_HAS_WINDOW_HOVERED && defined(_WIN32)
|
||||
static WNDPROC g_GlfwWndProc = NULL;
|
||||
static LRESULT CALLBACK WndProcNoInputs(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (msg == WM_NCHITTEST)
|
||||
{
|
||||
// Let mouse pass-through the window. This will allow the backend to set io.MouseHoveredViewport properly (which is OPTIONAL).
|
||||
// The ImGuiViewportFlags_NoInputs flag is set while dragging a viewport, as want to detect the window behind the one we are dragging.
|
||||
// If you cannot easily access those viewport flags from your windowing/event code: you may manually synchronize its state e.g. in
|
||||
// your main loop after calling UpdatePlatformWindows(). Iterate all viewports/platform windows and pass the flag to your windowing system.
|
||||
ImGuiViewport* viewport = (ImGuiViewport*)::GetPropA(hWnd, "IMGUI_VIEWPORT");
|
||||
if (viewport->Flags & ImGuiViewportFlags_NoInputs)
|
||||
return HTTRANSPARENT;
|
||||
}
|
||||
return ::CallWindowProc(g_GlfwWndProc, hWnd, msg, wParam, lParam);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ImGui_ImplGlfw_ShowWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
|
||||
#if defined(_WIN32)
|
||||
// GLFW hack: Hide icon from task bar
|
||||
HWND hwnd = (HWND)viewport->PlatformHandleRaw;
|
||||
if (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon)
|
||||
{
|
||||
LONG ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
|
||||
ex_style &= ~WS_EX_APPWINDOW;
|
||||
ex_style |= WS_EX_TOOLWINDOW;
|
||||
::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style);
|
||||
}
|
||||
|
||||
// GLFW hack: install hook for WM_NCHITTEST message handler
|
||||
#if !GLFW_HAS_MOUSE_PASSTHROUGH && GLFW_HAS_WINDOW_HOVERED && defined(_WIN32)
|
||||
::SetPropA(hwnd, "IMGUI_VIEWPORT", viewport);
|
||||
if (g_GlfwWndProc == NULL)
|
||||
g_GlfwWndProc = (WNDPROC)::GetWindowLongPtr(hwnd, GWLP_WNDPROC);
|
||||
::SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)WndProcNoInputs);
|
||||
#endif
|
||||
|
||||
#if !GLFW_HAS_FOCUS_ON_SHOW
|
||||
// GLFW hack: GLFW 3.2 has a bug where glfwShowWindow() also activates/focus the window.
|
||||
// The fix was pushed to GLFW repository on 2018/01/09 and should be included in GLFW 3.3 via a GLFW_FOCUS_ON_SHOW window attribute.
|
||||
// See https://github.com/glfw/glfw/issues/1189
|
||||
// FIXME-VIEWPORT: Implement same work-around for Linux/OSX in the meanwhile.
|
||||
if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing)
|
||||
{
|
||||
::ShowWindow(hwnd, SW_SHOWNA);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
glfwShowWindow(vd->Window);
|
||||
}
|
||||
|
||||
static ImVec2 ImGui_ImplGlfw_GetWindowPos(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
int x = 0, y = 0;
|
||||
glfwGetWindowPos(vd->Window, &x, &y);
|
||||
return ImVec2((float)x, (float)y);
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos)
|
||||
{
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
vd->IgnoreWindowPosEventFrame = ImGui::GetFrameCount();
|
||||
glfwSetWindowPos(vd->Window, (int)pos.x, (int)pos.y);
|
||||
}
|
||||
|
||||
static ImVec2 ImGui_ImplGlfw_GetWindowSize(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
int w = 0, h = 0;
|
||||
glfwGetWindowSize(vd->Window, &w, &h);
|
||||
return ImVec2((float)w, (float)h);
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
|
||||
{
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
#if __APPLE__ && !GLFW_HAS_OSX_WINDOW_POS_FIX
|
||||
// Native OS windows are positioned from the bottom-left corner on macOS, whereas on other platforms they are
|
||||
// positioned from the upper-left corner. GLFW makes an effort to convert macOS style coordinates, however it
|
||||
// doesn't handle it when changing size. We are manually moving the window in order for changes of size to be based
|
||||
// on the upper-left corner.
|
||||
int x, y, width, height;
|
||||
glfwGetWindowPos(vd->Window, &x, &y);
|
||||
glfwGetWindowSize(vd->Window, &width, &height);
|
||||
glfwSetWindowPos(vd->Window, x, y - height + size.y);
|
||||
#endif
|
||||
vd->IgnoreWindowSizeEventFrame = ImGui::GetFrameCount();
|
||||
glfwSetWindowSize(vd->Window, (int)size.x, (int)size.y);
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_SetWindowTitle(ImGuiViewport* viewport, const char* title)
|
||||
{
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
glfwSetWindowTitle(vd->Window, title);
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_SetWindowFocus(ImGuiViewport* viewport)
|
||||
{
|
||||
#if GLFW_HAS_FOCUS_WINDOW
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
glfwFocusWindow(vd->Window);
|
||||
#else
|
||||
// FIXME: What are the effect of not having this function? At the moment imgui doesn't actually call SetWindowFocus - we set that up ahead, will answer that question later.
|
||||
(void)viewport;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool ImGui_ImplGlfw_GetWindowFocus(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
return glfwGetWindowAttrib(vd->Window, GLFW_FOCUSED) != 0;
|
||||
}
|
||||
|
||||
static bool ImGui_ImplGlfw_GetWindowMinimized(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
return glfwGetWindowAttrib(vd->Window, GLFW_ICONIFIED) != 0;
|
||||
}
|
||||
|
||||
#if GLFW_HAS_WINDOW_ALPHA
|
||||
static void ImGui_ImplGlfw_SetWindowAlpha(ImGuiViewport* viewport, float alpha)
|
||||
{
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
glfwSetWindowOpacity(vd->Window, alpha);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ImGui_ImplGlfw_RenderWindow(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
if (bd->ClientApi == GlfwClientApi_OpenGL)
|
||||
glfwMakeContextCurrent(vd->Window);
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_SwapBuffers(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
if (bd->ClientApi == GlfwClientApi_OpenGL)
|
||||
{
|
||||
glfwMakeContextCurrent(vd->Window);
|
||||
glfwSwapBuffers(vd->Window);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// IME (Input Method Editor) basic support for e.g. Asian language users
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
// We provide a Win32 implementation because this is such a common issue for IME users
|
||||
#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)
|
||||
#define HAS_WIN32_IME 1
|
||||
#include <imm.h>
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "imm32")
|
||||
#endif
|
||||
static void ImGui_ImplWin32_SetImeInputPos(ImGuiViewport* viewport, ImVec2 pos)
|
||||
{
|
||||
COMPOSITIONFORM cf = { CFS_FORCE_POSITION, { (LONG)(pos.x - viewport->Pos.x), (LONG)(pos.y - viewport->Pos.y) }, { 0, 0, 0, 0 } };
|
||||
if (HWND hwnd = (HWND)viewport->PlatformHandleRaw)
|
||||
if (HIMC himc = ::ImmGetContext(hwnd))
|
||||
{
|
||||
::ImmSetCompositionWindow(himc, &cf);
|
||||
::ImmReleaseContext(hwnd, himc);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define HAS_WIN32_IME 0
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// Vulkan support (the Vulkan renderer needs to call a platform-side support function to create the surface)
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Avoid including <vulkan.h> so we can build without it
|
||||
#if GLFW_HAS_VULKAN
|
||||
#ifndef VULKAN_H_
|
||||
#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
|
||||
#if defined(__LP64__) || defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
|
||||
#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object;
|
||||
#else
|
||||
#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;
|
||||
#endif
|
||||
VK_DEFINE_HANDLE(VkInstance)
|
||||
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR)
|
||||
struct VkAllocationCallbacks;
|
||||
enum VkResult { VK_RESULT_MAX_ENUM = 0x7FFFFFFF };
|
||||
#endif // VULKAN_H_
|
||||
extern "C" { extern GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); }
|
||||
static int ImGui_ImplGlfw_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_instance, const void* vk_allocator, ImU64* out_vk_surface)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
IM_UNUSED(bd);
|
||||
IM_ASSERT(bd->ClientApi == GlfwClientApi_Vulkan);
|
||||
VkResult err = glfwCreateWindowSurface((VkInstance)vk_instance, vd->Window, (const VkAllocationCallbacks*)vk_allocator, (VkSurfaceKHR*)out_vk_surface);
|
||||
return (int)err;
|
||||
}
|
||||
#endif // GLFW_HAS_VULKAN
|
||||
|
||||
static void ImGui_ImplGlfw_InitPlatformInterface()
|
||||
{
|
||||
// Register platform interface (will be coupled with a renderer interface)
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Platform_CreateWindow = ImGui_ImplGlfw_CreateWindow;
|
||||
platform_io.Platform_DestroyWindow = ImGui_ImplGlfw_DestroyWindow;
|
||||
platform_io.Platform_ShowWindow = ImGui_ImplGlfw_ShowWindow;
|
||||
platform_io.Platform_SetWindowPos = ImGui_ImplGlfw_SetWindowPos;
|
||||
platform_io.Platform_GetWindowPos = ImGui_ImplGlfw_GetWindowPos;
|
||||
platform_io.Platform_SetWindowSize = ImGui_ImplGlfw_SetWindowSize;
|
||||
platform_io.Platform_GetWindowSize = ImGui_ImplGlfw_GetWindowSize;
|
||||
platform_io.Platform_SetWindowFocus = ImGui_ImplGlfw_SetWindowFocus;
|
||||
platform_io.Platform_GetWindowFocus = ImGui_ImplGlfw_GetWindowFocus;
|
||||
platform_io.Platform_GetWindowMinimized = ImGui_ImplGlfw_GetWindowMinimized;
|
||||
platform_io.Platform_SetWindowTitle = ImGui_ImplGlfw_SetWindowTitle;
|
||||
platform_io.Platform_RenderWindow = ImGui_ImplGlfw_RenderWindow;
|
||||
platform_io.Platform_SwapBuffers = ImGui_ImplGlfw_SwapBuffers;
|
||||
#if GLFW_HAS_WINDOW_ALPHA
|
||||
platform_io.Platform_SetWindowAlpha = ImGui_ImplGlfw_SetWindowAlpha;
|
||||
#endif
|
||||
#if GLFW_HAS_VULKAN
|
||||
platform_io.Platform_CreateVkSurface = ImGui_ImplGlfw_CreateVkSurface;
|
||||
#endif
|
||||
#if HAS_WIN32_IME
|
||||
platform_io.Platform_SetImeInputPos = ImGui_ImplWin32_SetImeInputPos;
|
||||
#endif
|
||||
|
||||
// Register main window handle (which is owned by the main application, not by us)
|
||||
// This is mostly for simplicity and consistency, so that our code (e.g. mouse handling etc.) can use same logic for main and secondary viewports.
|
||||
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
||||
ImGui_ImplGlfw_ViewportData* vd = IM_NEW(ImGui_ImplGlfw_ViewportData)();
|
||||
vd->Window = bd->Window;
|
||||
vd->WindowOwned = false;
|
||||
main_viewport->PlatformUserData = vd;
|
||||
main_viewport->PlatformHandle = (void*)bd->Window;
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_ShutdownPlatformInterface()
|
||||
{
|
||||
ImGui::DestroyPlatformWindows();
|
||||
}
|
||||
45
samples/external/Imgui/imgui-docking/backends/imgui_impl_glfw.h
vendored
Normal file
45
samples/external/Imgui/imgui-docking/backends/imgui_impl_glfw.h
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
// dear imgui: Platform Backend for GLFW
|
||||
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..)
|
||||
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Clipboard support.
|
||||
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW.
|
||||
// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
|
||||
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
|
||||
// Issues:
|
||||
// [ ] Platform: Multi-viewport support: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor).
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// About GLSL version:
|
||||
// The 'glsl_version' initialization parameter defaults to "#version 150" if NULL.
|
||||
// Only override if your GL version doesn't handle this GLSL version. Keep NULL if unsure!
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
struct GLFWwindow;
|
||||
struct GLFWmonitor;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks);
|
||||
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks);
|
||||
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame();
|
||||
|
||||
// GLFW callbacks
|
||||
// - When calling Init with 'install_callbacks=true': GLFW callbacks will be installed for you. They will call user's previously installed callbacks, if any.
|
||||
// - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call those function yourself from your own GLFW callbacks.
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor* monitor, int event);
|
||||
217
samples/external/Imgui/imgui-docking/backends/imgui_impl_glut.cpp
vendored
Normal file
217
samples/external/Imgui/imgui-docking/backends/imgui_impl_glut.cpp
vendored
Normal file
@@ -0,0 +1,217 @@
|
||||
// dear imgui: Platform Backend for GLUT/FreeGLUT
|
||||
// This needs to be used along with a Renderer (e.g. OpenGL2)
|
||||
|
||||
// !!! GLUT/FreeGLUT IS OBSOLETE PREHISTORIC SOFTWARE. Using GLUT is not recommended unless you really miss the 90's. !!!
|
||||
// !!! If someone or something is teaching you GLUT today, you are being abused. Please show some resistance. !!!
|
||||
// !!! Nowadays, prefer using GLFW or SDL instead!
|
||||
|
||||
// Issues:
|
||||
// [ ] Platform: GLUT is unable to distinguish e.g. Backspace from CTRL+H or TAB from CTRL+I
|
||||
// [ ] Platform: Missing mouse cursor shape/visibility support.
|
||||
// [ ] Platform: Missing clipboard support (not supported by Glut).
|
||||
// [ ] Platform: Missing gamepad support.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2019-04-03: Misc: Renamed imgui_impl_freeglut.cpp/.h to imgui_impl_glut.cpp/.h.
|
||||
// 2019-03-25: Misc: Made io.DeltaTime always above zero.
|
||||
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
|
||||
// 2018-03-22: Added GLUT Platform binding.
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_glut.h"
|
||||
#ifdef __APPLE__
|
||||
#include <GLUT/glut.h>
|
||||
#else
|
||||
#include <GL/freeglut.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
|
||||
#endif
|
||||
|
||||
static int g_Time = 0; // Current time, in milliseconds
|
||||
|
||||
bool ImGui_ImplGLUT_Init()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
#ifdef FREEGLUT
|
||||
io.BackendPlatformName = "imgui_impl_glut (freeglut)";
|
||||
#else
|
||||
io.BackendPlatformName = "imgui_impl_glut";
|
||||
#endif
|
||||
|
||||
g_Time = 0;
|
||||
|
||||
// Glut has 1 function for characters and one for "special keys". We map the characters in the 0..255 range and the keys above.
|
||||
io.KeyMap[ImGuiKey_Tab] = '\t'; // == 9 == CTRL+I
|
||||
io.KeyMap[ImGuiKey_LeftArrow] = 256 + GLUT_KEY_LEFT;
|
||||
io.KeyMap[ImGuiKey_RightArrow] = 256 + GLUT_KEY_RIGHT;
|
||||
io.KeyMap[ImGuiKey_UpArrow] = 256 + GLUT_KEY_UP;
|
||||
io.KeyMap[ImGuiKey_DownArrow] = 256 + GLUT_KEY_DOWN;
|
||||
io.KeyMap[ImGuiKey_PageUp] = 256 + GLUT_KEY_PAGE_UP;
|
||||
io.KeyMap[ImGuiKey_PageDown] = 256 + GLUT_KEY_PAGE_DOWN;
|
||||
io.KeyMap[ImGuiKey_Home] = 256 + GLUT_KEY_HOME;
|
||||
io.KeyMap[ImGuiKey_End] = 256 + GLUT_KEY_END;
|
||||
io.KeyMap[ImGuiKey_Insert] = 256 + GLUT_KEY_INSERT;
|
||||
io.KeyMap[ImGuiKey_Delete] = 127;
|
||||
io.KeyMap[ImGuiKey_Backspace] = 8; // == CTRL+H
|
||||
io.KeyMap[ImGuiKey_Space] = ' ';
|
||||
io.KeyMap[ImGuiKey_Enter] = 13; // == CTRL+M
|
||||
io.KeyMap[ImGuiKey_Escape] = 27;
|
||||
io.KeyMap[ImGuiKey_KeyPadEnter] = 13; // == CTRL+M
|
||||
io.KeyMap[ImGuiKey_A] = 'A';
|
||||
io.KeyMap[ImGuiKey_C] = 'C';
|
||||
io.KeyMap[ImGuiKey_V] = 'V';
|
||||
io.KeyMap[ImGuiKey_X] = 'X';
|
||||
io.KeyMap[ImGuiKey_Y] = 'Y';
|
||||
io.KeyMap[ImGuiKey_Z] = 'Z';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplGLUT_InstallFuncs()
|
||||
{
|
||||
glutReshapeFunc(ImGui_ImplGLUT_ReshapeFunc);
|
||||
glutMotionFunc(ImGui_ImplGLUT_MotionFunc);
|
||||
glutPassiveMotionFunc(ImGui_ImplGLUT_MotionFunc);
|
||||
glutMouseFunc(ImGui_ImplGLUT_MouseFunc);
|
||||
#ifdef __FREEGLUT_EXT_H__
|
||||
glutMouseWheelFunc(ImGui_ImplGLUT_MouseWheelFunc);
|
||||
#endif
|
||||
glutKeyboardFunc(ImGui_ImplGLUT_KeyboardFunc);
|
||||
glutKeyboardUpFunc(ImGui_ImplGLUT_KeyboardUpFunc);
|
||||
glutSpecialFunc(ImGui_ImplGLUT_SpecialFunc);
|
||||
glutSpecialUpFunc(ImGui_ImplGLUT_SpecialUpFunc);
|
||||
}
|
||||
|
||||
void ImGui_ImplGLUT_Shutdown()
|
||||
{
|
||||
}
|
||||
|
||||
void ImGui_ImplGLUT_NewFrame()
|
||||
{
|
||||
// Setup time step
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
int current_time = glutGet(GLUT_ELAPSED_TIME);
|
||||
int delta_time_ms = (current_time - g_Time);
|
||||
if (delta_time_ms <= 0)
|
||||
delta_time_ms = 1;
|
||||
io.DeltaTime = delta_time_ms / 1000.0f;
|
||||
g_Time = current_time;
|
||||
|
||||
// Start the frame
|
||||
ImGui::NewFrame();
|
||||
}
|
||||
|
||||
static void ImGui_ImplGLUT_UpdateKeyboardMods()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
int mods = glutGetModifiers();
|
||||
io.KeyCtrl = (mods & GLUT_ACTIVE_CTRL) != 0;
|
||||
io.KeyShift = (mods & GLUT_ACTIVE_SHIFT) != 0;
|
||||
io.KeyAlt = (mods & GLUT_ACTIVE_ALT) != 0;
|
||||
}
|
||||
|
||||
void ImGui_ImplGLUT_KeyboardFunc(unsigned char c, int x, int y)
|
||||
{
|
||||
// Send character to imgui
|
||||
//printf("char_down_func %d '%c'\n", c, c);
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (c >= 32)
|
||||
io.AddInputCharacter((unsigned int)c);
|
||||
|
||||
// Store letters in KeysDown[] array as both uppercase and lowercase + Handle GLUT translating CTRL+A..CTRL+Z as 1..26.
|
||||
// This is a hacky mess but GLUT is unable to distinguish e.g. a TAB key from CTRL+I so this is probably the best we can do here.
|
||||
if (c >= 1 && c <= 26)
|
||||
io.KeysDown[c] = io.KeysDown[c - 1 + 'a'] = io.KeysDown[c - 1 + 'A'] = true;
|
||||
else if (c >= 'a' && c <= 'z')
|
||||
io.KeysDown[c] = io.KeysDown[c - 'a' + 'A'] = true;
|
||||
else if (c >= 'A' && c <= 'Z')
|
||||
io.KeysDown[c] = io.KeysDown[c - 'A' + 'a'] = true;
|
||||
else
|
||||
io.KeysDown[c] = true;
|
||||
ImGui_ImplGLUT_UpdateKeyboardMods();
|
||||
(void)x; (void)y; // Unused
|
||||
}
|
||||
|
||||
void ImGui_ImplGLUT_KeyboardUpFunc(unsigned char c, int x, int y)
|
||||
{
|
||||
//printf("char_up_func %d '%c'\n", c, c);
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (c >= 1 && c <= 26)
|
||||
io.KeysDown[c] = io.KeysDown[c - 1 + 'a'] = io.KeysDown[c - 1 + 'A'] = false;
|
||||
else if (c >= 'a' && c <= 'z')
|
||||
io.KeysDown[c] = io.KeysDown[c - 'a' + 'A'] = false;
|
||||
else if (c >= 'A' && c <= 'Z')
|
||||
io.KeysDown[c] = io.KeysDown[c - 'A' + 'a'] = false;
|
||||
else
|
||||
io.KeysDown[c] = false;
|
||||
ImGui_ImplGLUT_UpdateKeyboardMods();
|
||||
(void)x; (void)y; // Unused
|
||||
}
|
||||
|
||||
void ImGui_ImplGLUT_SpecialFunc(int key, int x, int y)
|
||||
{
|
||||
//printf("key_down_func %d\n", key);
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (key + 256 < IM_ARRAYSIZE(io.KeysDown))
|
||||
io.KeysDown[key + 256] = true;
|
||||
ImGui_ImplGLUT_UpdateKeyboardMods();
|
||||
(void)x; (void)y; // Unused
|
||||
}
|
||||
|
||||
void ImGui_ImplGLUT_SpecialUpFunc(int key, int x, int y)
|
||||
{
|
||||
//printf("key_up_func %d\n", key);
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (key + 256 < IM_ARRAYSIZE(io.KeysDown))
|
||||
io.KeysDown[key + 256] = false;
|
||||
ImGui_ImplGLUT_UpdateKeyboardMods();
|
||||
(void)x; (void)y; // Unused
|
||||
}
|
||||
|
||||
void ImGui_ImplGLUT_MouseFunc(int glut_button, int state, int x, int y)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.MousePos = ImVec2((float)x, (float)y);
|
||||
int button = -1;
|
||||
if (glut_button == GLUT_LEFT_BUTTON) button = 0;
|
||||
if (glut_button == GLUT_RIGHT_BUTTON) button = 1;
|
||||
if (glut_button == GLUT_MIDDLE_BUTTON) button = 2;
|
||||
if (button != -1 && state == GLUT_DOWN)
|
||||
io.MouseDown[button] = true;
|
||||
if (button != -1 && state == GLUT_UP)
|
||||
io.MouseDown[button] = false;
|
||||
}
|
||||
|
||||
#ifdef __FREEGLUT_EXT_H__
|
||||
void ImGui_ImplGLUT_MouseWheelFunc(int button, int dir, int x, int y)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.MousePos = ImVec2((float)x, (float)y);
|
||||
if (dir > 0)
|
||||
io.MouseWheel += 1.0;
|
||||
else if (dir < 0)
|
||||
io.MouseWheel -= 1.0;
|
||||
(void)button; // Unused
|
||||
}
|
||||
#endif
|
||||
|
||||
void ImGui_ImplGLUT_ReshapeFunc(int w, int h)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.DisplaySize = ImVec2((float)w, (float)h);
|
||||
}
|
||||
|
||||
void ImGui_ImplGLUT_MotionFunc(int x, int y)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.MousePos = ImVec2((float)x, (float)y);
|
||||
}
|
||||
37
samples/external/Imgui/imgui-docking/backends/imgui_impl_glut.h
vendored
Normal file
37
samples/external/Imgui/imgui-docking/backends/imgui_impl_glut.h
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
// dear imgui: Platform Backend for GLUT/FreeGLUT
|
||||
// This needs to be used along with a Renderer (e.g. OpenGL2)
|
||||
|
||||
// !!! GLUT/FreeGLUT IS OBSOLETE PREHISTORIC SOFTWARE. Using GLUT is not recommended unless you really miss the 90's. !!!
|
||||
// !!! If someone or something is teaching you GLUT today, you are being abused. Please show some resistance. !!!
|
||||
// !!! Nowadays, prefer using GLFW or SDL instead!
|
||||
|
||||
// Issues:
|
||||
// [ ] Platform: GLUT is unable to distinguish e.g. Backspace from CTRL+H or TAB from CTRL+I
|
||||
// [ ] Platform: Missing mouse cursor shape/visibility support.
|
||||
// [ ] Platform: Missing clipboard support (not supported by Glut).
|
||||
// [ ] Platform: Missing gamepad support.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplGLUT_Init();
|
||||
IMGUI_IMPL_API void ImGui_ImplGLUT_InstallFuncs();
|
||||
IMGUI_IMPL_API void ImGui_ImplGLUT_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplGLUT_NewFrame();
|
||||
|
||||
// You can call ImGui_ImplGLUT_InstallFuncs() to get all those functions installed automatically,
|
||||
// or call them yourself from your own GLUT handlers. We are using the same weird names as GLUT for consistency..
|
||||
//---------------------------------------- GLUT name --------------------------------------------- Decent Name ---------
|
||||
IMGUI_IMPL_API void ImGui_ImplGLUT_ReshapeFunc(int w, int h); // ~ ResizeFunc
|
||||
IMGUI_IMPL_API void ImGui_ImplGLUT_MotionFunc(int x, int y); // ~ MouseMoveFunc
|
||||
IMGUI_IMPL_API void ImGui_ImplGLUT_MouseFunc(int button, int state, int x, int y); // ~ MouseButtonFunc
|
||||
IMGUI_IMPL_API void ImGui_ImplGLUT_MouseWheelFunc(int button, int dir, int x, int y); // ~ MouseWheelFunc
|
||||
IMGUI_IMPL_API void ImGui_ImplGLUT_KeyboardFunc(unsigned char c, int x, int y); // ~ CharPressedFunc
|
||||
IMGUI_IMPL_API void ImGui_ImplGLUT_KeyboardUpFunc(unsigned char c, int x, int y); // ~ CharReleasedFunc
|
||||
IMGUI_IMPL_API void ImGui_ImplGLUT_SpecialFunc(int key, int x, int y); // ~ KeyPressedFunc
|
||||
IMGUI_IMPL_API void ImGui_ImplGLUT_SpecialUpFunc(int key, int x, int y); // ~ KeyReleasedFunc
|
||||
318
samples/external/Imgui/imgui-docking/backends/imgui_impl_marmalade.cpp
vendored
Normal file
318
samples/external/Imgui/imgui-docking/backends/imgui_impl_marmalade.cpp
vendored
Normal file
@@ -0,0 +1,318 @@
|
||||
// dear imgui: Renderer + Platform Backend for Marmalade + IwGx
|
||||
// Marmalade code: Copyright (C) 2015 by Giovanni Zito (this file is part of Dear ImGui)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'CIwTexture*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// Missing features:
|
||||
// [ ] Renderer: Clipping rectangles are not honored.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2021-05-19: Renderer: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
|
||||
// 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter().
|
||||
// 2018-11-30: Misc: Setting up io.BackendPlatformName/io.BackendRendererName so they can be displayed in the About Window.
|
||||
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_Marmalade_RenderDrawData() in the .h file so you can call it yourself.
|
||||
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_marmalade.h"
|
||||
|
||||
#include <s3eClipboard.h>
|
||||
#include <s3ePointer.h>
|
||||
#include <s3eKeyboard.h>
|
||||
#include <IwTexture.h>
|
||||
#include <IwGx.h>
|
||||
|
||||
// Data
|
||||
static double g_Time = 0.0f;
|
||||
static bool g_MousePressed[3] = { false, false, false };
|
||||
static CIwTexture* g_FontTexture = NULL;
|
||||
static char* g_ClipboardText = NULL;
|
||||
static bool g_osdKeyboardEnabled = false;
|
||||
|
||||
// use this setting to scale the interface - e.g. on device you could use 2 or 3 scale factor
|
||||
static ImVec2 g_RenderScale = ImVec2(1.0f, 1.0f);
|
||||
|
||||
// Render function.
|
||||
void ImGui_Marmalade_RenderDrawData(ImDrawData* draw_data)
|
||||
{
|
||||
// Avoid rendering when minimized
|
||||
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
||||
return;
|
||||
|
||||
// Render command lists
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;
|
||||
const int nVert = cmd_list->VtxBuffer.Size;
|
||||
CIwFVec2* pVertStream = IW_GX_ALLOC(CIwFVec2, nVert);
|
||||
CIwFVec2* pUVStream = IW_GX_ALLOC(CIwFVec2, nVert);
|
||||
CIwColour* pColStream = IW_GX_ALLOC(CIwColour, nVert);
|
||||
|
||||
for (int i = 0; i < nVert; i++)
|
||||
{
|
||||
// FIXME-OPT: optimize multiplication on GPU using vertex shader/projection matrix.
|
||||
pVertStream[i].x = cmd_list->VtxBuffer[i].pos.x * g_RenderScale.x;
|
||||
pVertStream[i].y = cmd_list->VtxBuffer[i].pos.y * g_RenderScale.y;
|
||||
pUVStream[i].x = cmd_list->VtxBuffer[i].uv.x;
|
||||
pUVStream[i].y = cmd_list->VtxBuffer[i].uv.y;
|
||||
pColStream[i] = cmd_list->VtxBuffer[i].col;
|
||||
}
|
||||
|
||||
IwGxSetVertStreamScreenSpace(pVertStream, nVert);
|
||||
IwGxSetUVStream(pUVStream);
|
||||
IwGxSetColStream(pColStream, nVert);
|
||||
IwGxSetNormStream(0);
|
||||
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||
if (pcmd->UserCallback)
|
||||
{
|
||||
pcmd->UserCallback(cmd_list, pcmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: Not honoring ClipRect fields.
|
||||
CIwMaterial* pCurrentMaterial = IW_GX_ALLOC_MATERIAL();
|
||||
pCurrentMaterial->SetShadeMode(CIwMaterial::SHADE_FLAT);
|
||||
pCurrentMaterial->SetCullMode(CIwMaterial::CULL_NONE);
|
||||
pCurrentMaterial->SetFiltering(false);
|
||||
pCurrentMaterial->SetAlphaMode(CIwMaterial::ALPHA_BLEND);
|
||||
pCurrentMaterial->SetDepthWriteMode(CIwMaterial::DEPTH_WRITE_NORMAL);
|
||||
pCurrentMaterial->SetAlphaTestMode(CIwMaterial::ALPHATEST_DISABLED);
|
||||
pCurrentMaterial->SetTexture((CIwTexture*)pcmd->GetTexID());
|
||||
IwGxSetMaterial(pCurrentMaterial);
|
||||
IwGxDrawPrims(IW_GX_TRI_LIST, (uint16*)idx_buffer, pcmd->ElemCount);
|
||||
}
|
||||
idx_buffer += pcmd->ElemCount;
|
||||
}
|
||||
IwGxFlush();
|
||||
}
|
||||
|
||||
// TODO: restore modified state (i.e. mvp matrix)
|
||||
}
|
||||
|
||||
static const char* ImGui_Marmalade_GetClipboardText(void* /*user_data*/)
|
||||
{
|
||||
if (!s3eClipboardAvailable())
|
||||
return NULL;
|
||||
|
||||
if (int size = s3eClipboardGetText(NULL, 0))
|
||||
{
|
||||
if (g_ClipboardText)
|
||||
delete[] g_ClipboardText;
|
||||
g_ClipboardText = new char[size];
|
||||
g_ClipboardText[0] = '\0';
|
||||
s3eClipboardGetText(g_ClipboardText, size);
|
||||
}
|
||||
|
||||
return g_ClipboardText;
|
||||
}
|
||||
|
||||
static void ImGui_Marmalade_SetClipboardText(void* /*user_data*/, const char* text)
|
||||
{
|
||||
if (s3eClipboardAvailable())
|
||||
s3eClipboardSetText(text);
|
||||
}
|
||||
|
||||
int32 ImGui_Marmalade_PointerButtonEventCallback(void* system_data, void* user_data)
|
||||
{
|
||||
// pEvent->m_Button is of type s3ePointerButton and indicates which mouse
|
||||
// button was pressed. For touchscreen this should always have the value
|
||||
// S3E_POINTER_BUTTON_SELECT
|
||||
s3ePointerEvent* pEvent = (s3ePointerEvent*)system_data;
|
||||
|
||||
if (pEvent->m_Pressed == 1)
|
||||
{
|
||||
if (pEvent->m_Button == S3E_POINTER_BUTTON_LEFTMOUSE)
|
||||
g_MousePressed[0] = true;
|
||||
if (pEvent->m_Button == S3E_POINTER_BUTTON_RIGHTMOUSE)
|
||||
g_MousePressed[1] = true;
|
||||
if (pEvent->m_Button == S3E_POINTER_BUTTON_MIDDLEMOUSE)
|
||||
g_MousePressed[2] = true;
|
||||
if (pEvent->m_Button == S3E_POINTER_BUTTON_MOUSEWHEELUP)
|
||||
io.MouseWheel += pEvent->m_y;
|
||||
if (pEvent->m_Button == S3E_POINTER_BUTTON_MOUSEWHEELDOWN)
|
||||
io.MouseWheel += pEvent->m_y;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 ImGui_Marmalade_KeyCallback(void* system_data, void* user_data)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
s3eKeyboardEvent* e = (s3eKeyboardEvent*)system_data;
|
||||
if (e->m_Pressed == 1)
|
||||
io.KeysDown[e->m_Key] = true;
|
||||
if (e->m_Pressed == 0)
|
||||
io.KeysDown[e->m_Key] = false;
|
||||
|
||||
io.KeyCtrl = s3eKeyboardGetState(s3eKeyLeftControl) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightControl) == S3E_KEY_STATE_DOWN;
|
||||
io.KeyShift = s3eKeyboardGetState(s3eKeyLeftShift) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightShift) == S3E_KEY_STATE_DOWN;
|
||||
io.KeyAlt = s3eKeyboardGetState(s3eKeyLeftAlt) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightAlt) == S3E_KEY_STATE_DOWN;
|
||||
io.KeySuper = s3eKeyboardGetState(s3eKeyLeftWindows) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightWindows) == S3E_KEY_STATE_DOWN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 ImGui_Marmalade_CharCallback(void* system_data, void* user_data)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
s3eKeyboardCharEvent* e = (s3eKeyboardCharEvent*)system_data;
|
||||
io.AddInputCharacter((unsigned int)e->m_Char);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ImGui_Marmalade_CreateDeviceObjects()
|
||||
{
|
||||
// Build texture atlas
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
unsigned char* pixels;
|
||||
int width, height;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||
|
||||
// Upload texture to graphics system
|
||||
g_FontTexture = new CIwTexture();
|
||||
g_FontTexture->SetModifiable(true);
|
||||
CIwImage& image = g_FontTexture->GetImage();
|
||||
image.SetFormat(CIwImage::ARGB_8888);
|
||||
image.SetWidth(width);
|
||||
image.SetHeight(height);
|
||||
image.SetBuffers(); // allocates and own buffers
|
||||
image.ReadTexels(pixels);
|
||||
g_FontTexture->SetMipMapping(false);
|
||||
g_FontTexture->SetFiltering(false);
|
||||
g_FontTexture->Upload();
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->SetTexID((ImTextureID)g_FontTexture);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_Marmalade_InvalidateDeviceObjects()
|
||||
{
|
||||
if (g_ClipboardText)
|
||||
{
|
||||
delete[] g_ClipboardText;
|
||||
g_ClipboardText = NULL;
|
||||
}
|
||||
|
||||
if (g_FontTexture)
|
||||
{
|
||||
ImGui::GetIO().Fonts->SetTexID(0);
|
||||
delete g_FontTexture;
|
||||
g_FontTexture = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool ImGui_Marmalade_Init(bool install_callbacks)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.BackendPlatformName = io.BackendRendererName = "imgui_impl_marmalade";
|
||||
|
||||
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
|
||||
io.KeyMap[ImGuiKey_Tab] = s3eKeyTab
|
||||
io.KeyMap[ImGuiKey_LeftArrow] = s3eKeyLeft;
|
||||
io.KeyMap[ImGuiKey_RightArrow] = s3eKeyRight;
|
||||
io.KeyMap[ImGuiKey_UpArrow] = s3eKeyUp;
|
||||
io.KeyMap[ImGuiKey_DownArrow] = s3eKeyDown;
|
||||
io.KeyMap[ImGuiKey_PageUp] = s3eKeyPageUp;
|
||||
io.KeyMap[ImGuiKey_PageDown] = s3eKeyPageDown;
|
||||
io.KeyMap[ImGuiKey_Home] = s3eKeyHome;
|
||||
io.KeyMap[ImGuiKey_End] = s3eKeyEnd;
|
||||
io.KeyMap[ImGuiKey_Insert] = s3eKeyInsert;
|
||||
io.KeyMap[ImGuiKey_Delete] = s3eKeyDelete;
|
||||
io.KeyMap[ImGuiKey_Backspace] = s3eKeyBackspace;
|
||||
io.KeyMap[ImGuiKey_Space] = s3eKeySpace;
|
||||
io.KeyMap[ImGuiKey_Enter] = s3eKeyEnter;
|
||||
io.KeyMap[ImGuiKey_Escape] = s3eKeyEsc;
|
||||
io.KeyMap[ImGuiKey_KeyPadEnter] = s3eKeyNumPadEnter;
|
||||
io.KeyMap[ImGuiKey_A] = s3eKeyA;
|
||||
io.KeyMap[ImGuiKey_C] = s3eKeyC;
|
||||
io.KeyMap[ImGuiKey_V] = s3eKeyV;
|
||||
io.KeyMap[ImGuiKey_X] = s3eKeyX;
|
||||
io.KeyMap[ImGuiKey_Y] = s3eKeyY;
|
||||
io.KeyMap[ImGuiKey_Z] = s3eKeyZ;
|
||||
|
||||
io.SetClipboardTextFn = ImGui_Marmalade_SetClipboardText;
|
||||
io.GetClipboardTextFn = ImGui_Marmalade_GetClipboardText;
|
||||
|
||||
if (install_callbacks)
|
||||
{
|
||||
s3ePointerRegister(S3E_POINTER_BUTTON_EVENT, ImGui_Marmalade_PointerButtonEventCallback, 0);
|
||||
s3eKeyboardRegister(S3E_KEYBOARD_KEY_EVENT, ImGui_Marmalade_KeyCallback, 0);
|
||||
s3eKeyboardRegister(S3E_KEYBOARD_CHAR_EVENT, ImGui_Marmalade_CharCallback, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_Marmalade_Shutdown()
|
||||
{
|
||||
ImGui_Marmalade_InvalidateDeviceObjects();
|
||||
}
|
||||
|
||||
void ImGui_Marmalade_NewFrame()
|
||||
{
|
||||
if (!g_FontTexture)
|
||||
ImGui_Marmalade_CreateDeviceObjects();
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
// Setup display size (every frame to accommodate for window resizing)
|
||||
int w = IwGxGetScreenWidth(), h = IwGxGetScreenHeight();
|
||||
io.DisplaySize = ImVec2((float)w, (float)h);
|
||||
// For retina display or other situations where window coordinates are different from framebuffer coordinates. User storage only, presently not used by ImGui.
|
||||
io.DisplayFramebufferScale = g_scale;
|
||||
|
||||
// Setup time step
|
||||
double current_time = s3eTimerGetUST() / 1000.0f;
|
||||
io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f);
|
||||
g_Time = current_time;
|
||||
|
||||
double mouse_x, mouse_y;
|
||||
mouse_x = s3ePointerGetX();
|
||||
mouse_y = s3ePointerGetY();
|
||||
io.MousePos = ImVec2((float)mouse_x / g_scale.x, (float)mouse_y / g_scale.y); // Mouse position (set to -FLT_MAX,-FLT_MAX if no mouse / on another screen, etc.)
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
io.MouseDown[i] = g_MousePressed[i] || s3ePointerGetState((s3ePointerButton)i) != S3E_POINTER_STATE_UP; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
|
||||
g_MousePressed[i] = false;
|
||||
}
|
||||
|
||||
// TODO: Hide OS mouse cursor if ImGui is drawing it
|
||||
// s3ePointerSetInt(S3E_POINTER_HIDE_CURSOR,(io.MouseDrawCursor ? 0 : 1));
|
||||
|
||||
// Show/hide OSD keyboard
|
||||
if (io.WantTextInput)
|
||||
{
|
||||
// Some text input widget is active?
|
||||
if (!g_osdKeyboardEnabled)
|
||||
{
|
||||
g_osdKeyboardEnabled = true;
|
||||
s3eKeyboardSetInt(S3E_KEYBOARD_GET_CHAR, 1); // show OSD keyboard
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No text input widget is active
|
||||
if (g_osdKeyboardEnabled)
|
||||
{
|
||||
g_osdKeyboardEnabled = false;
|
||||
s3eKeyboardSetInt(S3E_KEYBOARD_GET_CHAR, 0); // hide OSD keyboard
|
||||
}
|
||||
}
|
||||
}
|
||||
28
samples/external/Imgui/imgui-docking/backends/imgui_impl_marmalade.h
vendored
Normal file
28
samples/external/Imgui/imgui-docking/backends/imgui_impl_marmalade.h
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
// dear imgui: Renderer + Platform Backend for Marmalade + IwGx
|
||||
// Marmalade code: Copyright (C) 2015 by Giovanni Zito (this file is part of Dear ImGui)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'CIwTexture*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_Marmalade_Init(bool install_callbacks);
|
||||
IMGUI_IMPL_API void ImGui_Marmalade_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_Marmalade_NewFrame();
|
||||
IMGUI_IMPL_API void ImGui_Marmalade_RenderDrawData(ImDrawData* draw_data);
|
||||
|
||||
// Use if you want to reset your rendering device without losing Dear ImGui state.
|
||||
IMGUI_IMPL_API void ImGui_Marmalade_InvalidateDeviceObjects();
|
||||
IMGUI_IMPL_API bool ImGui_Marmalade_CreateDeviceObjects();
|
||||
|
||||
// Callbacks (installed by default if you enable 'install_callbacks' during initialization)
|
||||
// You can also handle inputs yourself and use those as a reference.
|
||||
IMGUI_IMPL_API int32 ImGui_Marmalade_PointerButtonEventCallback(void* system_data, void* user_data);
|
||||
IMGUI_IMPL_API int32 ImGui_Marmalade_KeyCallback(void* system_data, void* user_data);
|
||||
IMGUI_IMPL_API int32 ImGui_Marmalade_CharCallback(void* system_data, void* user_data);
|
||||
31
samples/external/Imgui/imgui-docking/backends/imgui_impl_metal.h
vendored
Normal file
31
samples/external/Imgui/imgui-docking/backends/imgui_impl_metal.h
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
// dear imgui: Renderer Backend for Metal
|
||||
// This needs to be used along with a Platform Backend (e.g. OSX)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'MTLTexture' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
// Missing features:
|
||||
// [ ] Renderer: Multi-viewport / platform windows.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
@class MTLRenderPassDescriptor;
|
||||
@protocol MTLDevice, MTLCommandBuffer, MTLRenderCommandEncoder;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplMetal_Init(id<MTLDevice> device);
|
||||
IMGUI_IMPL_API void ImGui_ImplMetal_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor);
|
||||
IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data,
|
||||
id<MTLCommandBuffer> commandBuffer,
|
||||
id<MTLRenderCommandEncoder> commandEncoder);
|
||||
|
||||
// Called by Init/NewFrame/Shutdown
|
||||
IMGUI_IMPL_API bool ImGui_ImplMetal_CreateFontsTexture(id<MTLDevice> device);
|
||||
IMGUI_IMPL_API void ImGui_ImplMetal_DestroyFontsTexture();
|
||||
IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(id<MTLDevice> device);
|
||||
IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects();
|
||||
558
samples/external/Imgui/imgui-docking/backends/imgui_impl_metal.mm
vendored
Normal file
558
samples/external/Imgui/imgui-docking/backends/imgui_impl_metal.mm
vendored
Normal file
@@ -0,0 +1,558 @@
|
||||
// dear imgui: Renderer Backend for Metal
|
||||
// This needs to be used along with a Platform Backend (e.g. OSX)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'MTLTexture' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
// Missing features:
|
||||
// [ ] Renderer: Multi-viewport / platform windows.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2021-08-24: Metal: Fixed a crash when clipping rect larger than framebuffer is submitted. (#4464)
|
||||
// 2021-05-19: Metal: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||
// 2021-02-18: Metal: Change blending equation to preserve alpha in output buffer.
|
||||
// 2021-01-25: Metal: Fixed texture storage mode when building on Mac Catalyst.
|
||||
// 2019-05-29: Metal: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||
// 2019-04-30: Metal: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||
// 2019-02-11: Metal: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
|
||||
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||
// 2018-07-05: Metal: Added new Metal backend implementation.
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_metal.h"
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
// #import <QuartzCore/CAMetalLayer.h> // Not supported in XCode 9.2. Maybe a macro to detect the SDK version can be used (something like #if MACOS_SDK >= 10.13 ...)
|
||||
#import <simd/simd.h>
|
||||
|
||||
#pragma mark - Support classes
|
||||
|
||||
// A wrapper around a MTLBuffer object that knows the last time it was reused
|
||||
@interface MetalBuffer : NSObject
|
||||
@property (nonatomic, strong) id<MTLBuffer> buffer;
|
||||
@property (nonatomic, assign) NSTimeInterval lastReuseTime;
|
||||
- (instancetype)initWithBuffer:(id<MTLBuffer>)buffer;
|
||||
@end
|
||||
|
||||
// An object that encapsulates the data necessary to uniquely identify a
|
||||
// render pipeline state. These are used as cache keys.
|
||||
@interface FramebufferDescriptor : NSObject<NSCopying>
|
||||
@property (nonatomic, assign) unsigned long sampleCount;
|
||||
@property (nonatomic, assign) MTLPixelFormat colorPixelFormat;
|
||||
@property (nonatomic, assign) MTLPixelFormat depthPixelFormat;
|
||||
@property (nonatomic, assign) MTLPixelFormat stencilPixelFormat;
|
||||
- (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor *)renderPassDescriptor;
|
||||
@end
|
||||
|
||||
// A singleton that stores long-lived objects that are needed by the Metal
|
||||
// renderer backend. Stores the render pipeline state cache and the default
|
||||
// font texture, and manages the reusable buffer cache.
|
||||
@interface MetalContext : NSObject
|
||||
@property (nonatomic, strong) id<MTLDepthStencilState> depthStencilState;
|
||||
@property (nonatomic, strong) FramebufferDescriptor *framebufferDescriptor; // framebuffer descriptor for current frame; transient
|
||||
@property (nonatomic, strong) NSMutableDictionary *renderPipelineStateCache; // pipeline cache; keyed on framebuffer descriptors
|
||||
@property (nonatomic, strong, nullable) id<MTLTexture> fontTexture;
|
||||
@property (nonatomic, strong) NSMutableArray<MetalBuffer *> *bufferCache;
|
||||
@property (nonatomic, assign) NSTimeInterval lastBufferCachePurge;
|
||||
- (void)makeDeviceObjectsWithDevice:(id<MTLDevice>)device;
|
||||
- (void)makeFontTextureWithDevice:(id<MTLDevice>)device;
|
||||
- (MetalBuffer *)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device;
|
||||
- (void)enqueueReusableBuffer:(MetalBuffer *)buffer;
|
||||
- (id<MTLRenderPipelineState>)renderPipelineStateForFrameAndDevice:(id<MTLDevice>)device;
|
||||
- (void)emptyRenderPipelineStateCache;
|
||||
- (void)setupRenderState:(ImDrawData *)drawData
|
||||
commandBuffer:(id<MTLCommandBuffer>)commandBuffer
|
||||
commandEncoder:(id<MTLRenderCommandEncoder>)commandEncoder
|
||||
renderPipelineState:(id<MTLRenderPipelineState>)renderPipelineState
|
||||
vertexBuffer:(MetalBuffer *)vertexBuffer
|
||||
vertexBufferOffset:(size_t)vertexBufferOffset;
|
||||
- (void)renderDrawData:(ImDrawData *)drawData
|
||||
commandBuffer:(id<MTLCommandBuffer>)commandBuffer
|
||||
commandEncoder:(id<MTLRenderCommandEncoder>)commandEncoder;
|
||||
@end
|
||||
|
||||
static MetalContext *g_sharedMetalContext = nil;
|
||||
|
||||
#pragma mark - ImGui API implementation
|
||||
|
||||
bool ImGui_ImplMetal_Init(id<MTLDevice> device)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.BackendRendererName = "imgui_impl_metal";
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
g_sharedMetalContext = [[MetalContext alloc] init];
|
||||
});
|
||||
|
||||
ImGui_ImplMetal_CreateDeviceObjects(device);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplMetal_Shutdown()
|
||||
{
|
||||
ImGui_ImplMetal_DestroyDeviceObjects();
|
||||
}
|
||||
|
||||
void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor *renderPassDescriptor)
|
||||
{
|
||||
IM_ASSERT(g_sharedMetalContext != nil && "No Metal context. Did you call ImGui_ImplMetal_Init() ?");
|
||||
|
||||
g_sharedMetalContext.framebufferDescriptor = [[FramebufferDescriptor alloc] initWithRenderPassDescriptor:renderPassDescriptor];
|
||||
}
|
||||
|
||||
// Metal Render function.
|
||||
void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id<MTLCommandBuffer> commandBuffer, id<MTLRenderCommandEncoder> commandEncoder)
|
||||
{
|
||||
[g_sharedMetalContext renderDrawData:draw_data commandBuffer:commandBuffer commandEncoder:commandEncoder];
|
||||
}
|
||||
|
||||
bool ImGui_ImplMetal_CreateFontsTexture(id<MTLDevice> device)
|
||||
{
|
||||
[g_sharedMetalContext makeFontTextureWithDevice:device];
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.Fonts->SetTexID((__bridge void *)g_sharedMetalContext.fontTexture); // ImTextureID == void*
|
||||
|
||||
return (g_sharedMetalContext.fontTexture != nil);
|
||||
}
|
||||
|
||||
void ImGui_ImplMetal_DestroyFontsTexture()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
g_sharedMetalContext.fontTexture = nil;
|
||||
io.Fonts->SetTexID(nullptr);
|
||||
}
|
||||
|
||||
bool ImGui_ImplMetal_CreateDeviceObjects(id<MTLDevice> device)
|
||||
{
|
||||
[g_sharedMetalContext makeDeviceObjectsWithDevice:device];
|
||||
|
||||
ImGui_ImplMetal_CreateFontsTexture(device);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplMetal_DestroyDeviceObjects()
|
||||
{
|
||||
ImGui_ImplMetal_DestroyFontsTexture();
|
||||
[g_sharedMetalContext emptyRenderPipelineStateCache];
|
||||
}
|
||||
|
||||
#pragma mark - MetalBuffer implementation
|
||||
|
||||
@implementation MetalBuffer
|
||||
- (instancetype)initWithBuffer:(id<MTLBuffer>)buffer
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
_buffer = buffer;
|
||||
_lastReuseTime = [NSDate date].timeIntervalSince1970;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
||||
#pragma mark - FramebufferDescriptor implementation
|
||||
|
||||
@implementation FramebufferDescriptor
|
||||
- (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor *)renderPassDescriptor
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
_sampleCount = renderPassDescriptor.colorAttachments[0].texture.sampleCount;
|
||||
_colorPixelFormat = renderPassDescriptor.colorAttachments[0].texture.pixelFormat;
|
||||
_depthPixelFormat = renderPassDescriptor.depthAttachment.texture.pixelFormat;
|
||||
_stencilPixelFormat = renderPassDescriptor.stencilAttachment.texture.pixelFormat;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (nonnull id)copyWithZone:(nullable NSZone *)zone
|
||||
{
|
||||
FramebufferDescriptor *copy = [[FramebufferDescriptor allocWithZone:zone] init];
|
||||
copy.sampleCount = self.sampleCount;
|
||||
copy.colorPixelFormat = self.colorPixelFormat;
|
||||
copy.depthPixelFormat = self.depthPixelFormat;
|
||||
copy.stencilPixelFormat = self.stencilPixelFormat;
|
||||
return copy;
|
||||
}
|
||||
|
||||
- (NSUInteger)hash
|
||||
{
|
||||
NSUInteger sc = _sampleCount & 0x3;
|
||||
NSUInteger cf = _colorPixelFormat & 0x3FF;
|
||||
NSUInteger df = _depthPixelFormat & 0x3FF;
|
||||
NSUInteger sf = _stencilPixelFormat & 0x3FF;
|
||||
NSUInteger hash = (sf << 22) | (df << 12) | (cf << 2) | sc;
|
||||
return hash;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object
|
||||
{
|
||||
FramebufferDescriptor *other = object;
|
||||
if (![other isKindOfClass:[FramebufferDescriptor class]])
|
||||
return NO;
|
||||
return other.sampleCount == self.sampleCount &&
|
||||
other.colorPixelFormat == self.colorPixelFormat &&
|
||||
other.depthPixelFormat == self.depthPixelFormat &&
|
||||
other.stencilPixelFormat == self.stencilPixelFormat;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - MetalContext implementation
|
||||
|
||||
@implementation MetalContext
|
||||
- (instancetype)init {
|
||||
if ((self = [super init]))
|
||||
{
|
||||
_renderPipelineStateCache = [NSMutableDictionary dictionary];
|
||||
_bufferCache = [NSMutableArray array];
|
||||
_lastBufferCachePurge = [NSDate date].timeIntervalSince1970;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)makeDeviceObjectsWithDevice:(id<MTLDevice>)device
|
||||
{
|
||||
MTLDepthStencilDescriptor *depthStencilDescriptor = [[MTLDepthStencilDescriptor alloc] init];
|
||||
depthStencilDescriptor.depthWriteEnabled = NO;
|
||||
depthStencilDescriptor.depthCompareFunction = MTLCompareFunctionAlways;
|
||||
self.depthStencilState = [device newDepthStencilStateWithDescriptor:depthStencilDescriptor];
|
||||
}
|
||||
|
||||
// We are retrieving and uploading the font atlas as a 4-channels RGBA texture here.
|
||||
// In theory we could call GetTexDataAsAlpha8() and upload a 1-channel texture to save on memory access bandwidth.
|
||||
// However, using a shader designed for 1-channel texture would make it less obvious to use the ImTextureID facility to render users own textures.
|
||||
// You can make that change in your implementation.
|
||||
- (void)makeFontTextureWithDevice:(id<MTLDevice>)device
|
||||
{
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
unsigned char* pixels;
|
||||
int width, height;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||
MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
|
||||
width:(NSUInteger)width
|
||||
height:(NSUInteger)height
|
||||
mipmapped:NO];
|
||||
textureDescriptor.usage = MTLTextureUsageShaderRead;
|
||||
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
|
||||
textureDescriptor.storageMode = MTLStorageModeManaged;
|
||||
#else
|
||||
textureDescriptor.storageMode = MTLStorageModeShared;
|
||||
#endif
|
||||
id <MTLTexture> texture = [device newTextureWithDescriptor:textureDescriptor];
|
||||
[texture replaceRegion:MTLRegionMake2D(0, 0, (NSUInteger)width, (NSUInteger)height) mipmapLevel:0 withBytes:pixels bytesPerRow:(NSUInteger)width * 4];
|
||||
self.fontTexture = texture;
|
||||
}
|
||||
|
||||
- (MetalBuffer *)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device
|
||||
{
|
||||
NSTimeInterval now = [NSDate date].timeIntervalSince1970;
|
||||
|
||||
// Purge old buffers that haven't been useful for a while
|
||||
if (now - self.lastBufferCachePurge > 1.0)
|
||||
{
|
||||
NSMutableArray *survivors = [NSMutableArray array];
|
||||
for (MetalBuffer *candidate in self.bufferCache)
|
||||
{
|
||||
if (candidate.lastReuseTime > self.lastBufferCachePurge)
|
||||
{
|
||||
[survivors addObject:candidate];
|
||||
}
|
||||
}
|
||||
self.bufferCache = [survivors mutableCopy];
|
||||
self.lastBufferCachePurge = now;
|
||||
}
|
||||
|
||||
// See if we have a buffer we can reuse
|
||||
MetalBuffer *bestCandidate = nil;
|
||||
for (MetalBuffer *candidate in self.bufferCache)
|
||||
if (candidate.buffer.length >= length && (bestCandidate == nil || bestCandidate.lastReuseTime > candidate.lastReuseTime))
|
||||
bestCandidate = candidate;
|
||||
|
||||
if (bestCandidate != nil)
|
||||
{
|
||||
[self.bufferCache removeObject:bestCandidate];
|
||||
bestCandidate.lastReuseTime = now;
|
||||
return bestCandidate;
|
||||
}
|
||||
|
||||
// No luck; make a new buffer
|
||||
id<MTLBuffer> backing = [device newBufferWithLength:length options:MTLResourceStorageModeShared];
|
||||
return [[MetalBuffer alloc] initWithBuffer:backing];
|
||||
}
|
||||
|
||||
- (void)enqueueReusableBuffer:(MetalBuffer *)buffer
|
||||
{
|
||||
[self.bufferCache addObject:buffer];
|
||||
}
|
||||
|
||||
- (_Nullable id<MTLRenderPipelineState>)renderPipelineStateForFrameAndDevice:(id<MTLDevice>)device
|
||||
{
|
||||
// Try to retrieve a render pipeline state that is compatible with the framebuffer config for this frame
|
||||
// The hit rate for this cache should be very near 100%.
|
||||
id<MTLRenderPipelineState> renderPipelineState = self.renderPipelineStateCache[self.framebufferDescriptor];
|
||||
|
||||
if (renderPipelineState == nil)
|
||||
{
|
||||
// No luck; make a new render pipeline state
|
||||
renderPipelineState = [self _renderPipelineStateForFramebufferDescriptor:self.framebufferDescriptor device:device];
|
||||
// Cache render pipeline state for later reuse
|
||||
self.renderPipelineStateCache[self.framebufferDescriptor] = renderPipelineState;
|
||||
}
|
||||
|
||||
return renderPipelineState;
|
||||
}
|
||||
|
||||
- (id<MTLRenderPipelineState>)_renderPipelineStateForFramebufferDescriptor:(FramebufferDescriptor *)descriptor device:(id<MTLDevice>)device
|
||||
{
|
||||
NSError *error = nil;
|
||||
|
||||
NSString *shaderSource = @""
|
||||
"#include <metal_stdlib>\n"
|
||||
"using namespace metal;\n"
|
||||
"\n"
|
||||
"struct Uniforms {\n"
|
||||
" float4x4 projectionMatrix;\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"struct VertexIn {\n"
|
||||
" float2 position [[attribute(0)]];\n"
|
||||
" float2 texCoords [[attribute(1)]];\n"
|
||||
" uchar4 color [[attribute(2)]];\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"struct VertexOut {\n"
|
||||
" float4 position [[position]];\n"
|
||||
" float2 texCoords;\n"
|
||||
" float4 color;\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"vertex VertexOut vertex_main(VertexIn in [[stage_in]],\n"
|
||||
" constant Uniforms &uniforms [[buffer(1)]]) {\n"
|
||||
" VertexOut out;\n"
|
||||
" out.position = uniforms.projectionMatrix * float4(in.position, 0, 1);\n"
|
||||
" out.texCoords = in.texCoords;\n"
|
||||
" out.color = float4(in.color) / float4(255.0);\n"
|
||||
" return out;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"fragment half4 fragment_main(VertexOut in [[stage_in]],\n"
|
||||
" texture2d<half, access::sample> texture [[texture(0)]]) {\n"
|
||||
" constexpr sampler linearSampler(coord::normalized, min_filter::linear, mag_filter::linear, mip_filter::linear);\n"
|
||||
" half4 texColor = texture.sample(linearSampler, in.texCoords);\n"
|
||||
" return half4(in.color) * texColor;\n"
|
||||
"}\n";
|
||||
|
||||
id<MTLLibrary> library = [device newLibraryWithSource:shaderSource options:nil error:&error];
|
||||
if (library == nil)
|
||||
{
|
||||
NSLog(@"Error: failed to create Metal library: %@", error);
|
||||
return nil;
|
||||
}
|
||||
|
||||
id<MTLFunction> vertexFunction = [library newFunctionWithName:@"vertex_main"];
|
||||
id<MTLFunction> fragmentFunction = [library newFunctionWithName:@"fragment_main"];
|
||||
|
||||
if (vertexFunction == nil || fragmentFunction == nil)
|
||||
{
|
||||
NSLog(@"Error: failed to find Metal shader functions in library: %@", error);
|
||||
return nil;
|
||||
}
|
||||
|
||||
MTLVertexDescriptor *vertexDescriptor = [MTLVertexDescriptor vertexDescriptor];
|
||||
vertexDescriptor.attributes[0].offset = IM_OFFSETOF(ImDrawVert, pos);
|
||||
vertexDescriptor.attributes[0].format = MTLVertexFormatFloat2; // position
|
||||
vertexDescriptor.attributes[0].bufferIndex = 0;
|
||||
vertexDescriptor.attributes[1].offset = IM_OFFSETOF(ImDrawVert, uv);
|
||||
vertexDescriptor.attributes[1].format = MTLVertexFormatFloat2; // texCoords
|
||||
vertexDescriptor.attributes[1].bufferIndex = 0;
|
||||
vertexDescriptor.attributes[2].offset = IM_OFFSETOF(ImDrawVert, col);
|
||||
vertexDescriptor.attributes[2].format = MTLVertexFormatUChar4; // color
|
||||
vertexDescriptor.attributes[2].bufferIndex = 0;
|
||||
vertexDescriptor.layouts[0].stepRate = 1;
|
||||
vertexDescriptor.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;
|
||||
vertexDescriptor.layouts[0].stride = sizeof(ImDrawVert);
|
||||
|
||||
MTLRenderPipelineDescriptor *pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
|
||||
pipelineDescriptor.vertexFunction = vertexFunction;
|
||||
pipelineDescriptor.fragmentFunction = fragmentFunction;
|
||||
pipelineDescriptor.vertexDescriptor = vertexDescriptor;
|
||||
pipelineDescriptor.sampleCount = self.framebufferDescriptor.sampleCount;
|
||||
pipelineDescriptor.colorAttachments[0].pixelFormat = self.framebufferDescriptor.colorPixelFormat;
|
||||
pipelineDescriptor.colorAttachments[0].blendingEnabled = YES;
|
||||
pipelineDescriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
|
||||
pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
|
||||
pipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
||||
pipelineDescriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
|
||||
pipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne;
|
||||
pipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
|
||||
pipelineDescriptor.depthAttachmentPixelFormat = self.framebufferDescriptor.depthPixelFormat;
|
||||
pipelineDescriptor.stencilAttachmentPixelFormat = self.framebufferDescriptor.stencilPixelFormat;
|
||||
|
||||
id<MTLRenderPipelineState> renderPipelineState = [device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error];
|
||||
if (error != nil)
|
||||
{
|
||||
NSLog(@"Error: failed to create Metal pipeline state: %@", error);
|
||||
}
|
||||
|
||||
return renderPipelineState;
|
||||
}
|
||||
|
||||
- (void)emptyRenderPipelineStateCache
|
||||
{
|
||||
[self.renderPipelineStateCache removeAllObjects];
|
||||
}
|
||||
|
||||
- (void)setupRenderState:(ImDrawData *)drawData
|
||||
commandBuffer:(id<MTLCommandBuffer>)commandBuffer
|
||||
commandEncoder:(id<MTLRenderCommandEncoder>)commandEncoder
|
||||
renderPipelineState:(id<MTLRenderPipelineState>)renderPipelineState
|
||||
vertexBuffer:(MetalBuffer *)vertexBuffer
|
||||
vertexBufferOffset:(size_t)vertexBufferOffset
|
||||
{
|
||||
[commandEncoder setCullMode:MTLCullModeNone];
|
||||
[commandEncoder setDepthStencilState:g_sharedMetalContext.depthStencilState];
|
||||
|
||||
// Setup viewport, orthographic projection matrix
|
||||
// Our visible imgui space lies from draw_data->DisplayPos (top left) to
|
||||
// draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps.
|
||||
MTLViewport viewport =
|
||||
{
|
||||
.originX = 0.0,
|
||||
.originY = 0.0,
|
||||
.width = (double)(drawData->DisplaySize.x * drawData->FramebufferScale.x),
|
||||
.height = (double)(drawData->DisplaySize.y * drawData->FramebufferScale.y),
|
||||
.znear = 0.0,
|
||||
.zfar = 1.0
|
||||
};
|
||||
[commandEncoder setViewport:viewport];
|
||||
|
||||
float L = drawData->DisplayPos.x;
|
||||
float R = drawData->DisplayPos.x + drawData->DisplaySize.x;
|
||||
float T = drawData->DisplayPos.y;
|
||||
float B = drawData->DisplayPos.y + drawData->DisplaySize.y;
|
||||
float N = (float)viewport.znear;
|
||||
float F = (float)viewport.zfar;
|
||||
const float ortho_projection[4][4] =
|
||||
{
|
||||
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
|
||||
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
|
||||
{ 0.0f, 0.0f, 1/(F-N), 0.0f },
|
||||
{ (R+L)/(L-R), (T+B)/(B-T), N/(F-N), 1.0f },
|
||||
};
|
||||
[commandEncoder setVertexBytes:&ortho_projection length:sizeof(ortho_projection) atIndex:1];
|
||||
|
||||
[commandEncoder setRenderPipelineState:renderPipelineState];
|
||||
|
||||
[commandEncoder setVertexBuffer:vertexBuffer.buffer offset:0 atIndex:0];
|
||||
[commandEncoder setVertexBufferOffset:vertexBufferOffset atIndex:0];
|
||||
}
|
||||
|
||||
- (void)renderDrawData:(ImDrawData *)drawData
|
||||
commandBuffer:(id<MTLCommandBuffer>)commandBuffer
|
||||
commandEncoder:(id<MTLRenderCommandEncoder>)commandEncoder
|
||||
{
|
||||
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||
int fb_width = (int)(drawData->DisplaySize.x * drawData->FramebufferScale.x);
|
||||
int fb_height = (int)(drawData->DisplaySize.y * drawData->FramebufferScale.y);
|
||||
if (fb_width <= 0 || fb_height <= 0 || drawData->CmdListsCount == 0)
|
||||
return;
|
||||
|
||||
id<MTLRenderPipelineState> renderPipelineState = [self renderPipelineStateForFrameAndDevice:commandBuffer.device];
|
||||
|
||||
size_t vertexBufferLength = (size_t)drawData->TotalVtxCount * sizeof(ImDrawVert);
|
||||
size_t indexBufferLength = (size_t)drawData->TotalIdxCount * sizeof(ImDrawIdx);
|
||||
MetalBuffer* vertexBuffer = [self dequeueReusableBufferOfLength:vertexBufferLength device:commandBuffer.device];
|
||||
MetalBuffer* indexBuffer = [self dequeueReusableBufferOfLength:indexBufferLength device:commandBuffer.device];
|
||||
|
||||
[self setupRenderState:drawData commandBuffer:commandBuffer commandEncoder:commandEncoder renderPipelineState:renderPipelineState vertexBuffer:vertexBuffer vertexBufferOffset:0];
|
||||
|
||||
// Will project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_off = drawData->DisplayPos; // (0,0) unless using multi-viewports
|
||||
ImVec2 clip_scale = drawData->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
|
||||
|
||||
// Render command lists
|
||||
size_t vertexBufferOffset = 0;
|
||||
size_t indexBufferOffset = 0;
|
||||
for (int n = 0; n < drawData->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = drawData->CmdLists[n];
|
||||
|
||||
memcpy((char *)vertexBuffer.buffer.contents + vertexBufferOffset, cmd_list->VtxBuffer.Data, (size_t)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
|
||||
memcpy((char *)indexBuffer.buffer.contents + indexBufferOffset, cmd_list->IdxBuffer.Data, (size_t)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
|
||||
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||
if (pcmd->UserCallback)
|
||||
{
|
||||
// User callback, registered via ImDrawList::AddCallback()
|
||||
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||
[self setupRenderState:drawData commandBuffer:commandBuffer commandEncoder:commandEncoder renderPipelineState:renderPipelineState vertexBuffer:vertexBuffer vertexBufferOffset:vertexBufferOffset];
|
||||
else
|
||||
pcmd->UserCallback(cmd_list, pcmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
|
||||
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
|
||||
|
||||
// Clamp to viewport as setScissorRect() won't accept values that are off bounds
|
||||
if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
|
||||
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
|
||||
if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }
|
||||
if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }
|
||||
if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
|
||||
continue;
|
||||
|
||||
// Apply scissor/clipping rectangle
|
||||
MTLScissorRect scissorRect =
|
||||
{
|
||||
.x = NSUInteger(clip_min.x),
|
||||
.y = NSUInteger(clip_min.y),
|
||||
.width = NSUInteger(clip_max.x - clip_min.x),
|
||||
.height = NSUInteger(clip_max.y - clip_min.y)
|
||||
};
|
||||
[commandEncoder setScissorRect:scissorRect];
|
||||
|
||||
// Bind texture, Draw
|
||||
if (ImTextureID tex_id = pcmd->GetTexID())
|
||||
[commandEncoder setFragmentTexture:(__bridge id<MTLTexture>)(tex_id) atIndex:0];
|
||||
|
||||
[commandEncoder setVertexBufferOffset:(vertexBufferOffset + pcmd->VtxOffset * sizeof(ImDrawVert)) atIndex:0];
|
||||
[commandEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle
|
||||
indexCount:pcmd->ElemCount
|
||||
indexType:sizeof(ImDrawIdx) == 2 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32
|
||||
indexBuffer:indexBuffer.buffer
|
||||
indexBufferOffset:indexBufferOffset + pcmd->IdxOffset * sizeof(ImDrawIdx)];
|
||||
}
|
||||
}
|
||||
|
||||
vertexBufferOffset += (size_t)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert);
|
||||
indexBufferOffset += (size_t)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx);
|
||||
}
|
||||
|
||||
__weak id weakSelf = self;
|
||||
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer>)
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[weakSelf enqueueReusableBuffer:vertexBuffer];
|
||||
[weakSelf enqueueReusableBuffer:indexBuffer];
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
324
samples/external/Imgui/imgui-docking/backends/imgui_impl_opengl2.cpp
vendored
Normal file
324
samples/external/Imgui/imgui-docking/backends/imgui_impl_opengl2.cpp
vendored
Normal file
@@ -0,0 +1,324 @@
|
||||
// dear imgui: Renderer Backend for OpenGL2 (legacy OpenGL, fixed pipeline)
|
||||
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Multi-viewport support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)**
|
||||
// **Prefer using the code in imgui_impl_opengl3.cpp**
|
||||
// This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read.
|
||||
// If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more
|
||||
// complicated, will require your code to reset every single OpenGL attributes to their initial state, and might
|
||||
// confuse your GPU driver.
|
||||
// The GL2 code is unable to reset attributes or even call e.g. "glUseProgram(0)" because they don't exist in that API.
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
|
||||
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||
// 2021-05-19: OpenGL: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||
// 2021-01-03: OpenGL: Backup, setup and restore GL_SHADE_MODEL state, disable GL_STENCIL_TEST and disable GL_NORMAL_ARRAY client state to increase compatibility with legacy OpenGL applications.
|
||||
// 2020-01-23: OpenGL: Backup, setup and restore GL_TEXTURE_ENV to increase compatibility with legacy OpenGL applications.
|
||||
// 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||
// 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
|
||||
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||
// 2018-08-03: OpenGL: Disabling/restoring GL_LIGHTING and GL_COLOR_MATERIAL to increase compatibility with legacy OpenGL applications.
|
||||
// 2018-06-08: Misc: Extracted imgui_impl_opengl2.cpp/.h away from the old combined GLFW/SDL+OpenGL2 examples.
|
||||
// 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
||||
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplOpenGL2_RenderDrawData() in the .h file so you can call it yourself.
|
||||
// 2017-09-01: OpenGL: Save and restore current polygon mode.
|
||||
// 2016-09-10: OpenGL: Uploading font texture as RGBA32 to increase compatibility with users shaders (not ideal).
|
||||
// 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle.
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_opengl2.h"
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
|
||||
#include <stddef.h> // intptr_t
|
||||
#else
|
||||
#include <stdint.h> // intptr_t
|
||||
#endif
|
||||
|
||||
// Include OpenGL header (without an OpenGL loader) requires a bit of fiddling
|
||||
#if defined(_WIN32) && !defined(APIENTRY)
|
||||
#define APIENTRY __stdcall // It is customary to use APIENTRY for OpenGL function pointer declarations on all platforms. Additionally, the Windows OpenGL header needs APIENTRY.
|
||||
#endif
|
||||
#if defined(_WIN32) && !defined(WINGDIAPI)
|
||||
#define WINGDIAPI __declspec(dllimport) // Some Windows OpenGL headers need this
|
||||
#endif
|
||||
#if defined(__APPLE__)
|
||||
#define GL_SILENCE_DEPRECATION
|
||||
#include <OpenGL/gl.h>
|
||||
#else
|
||||
#include <GL/gl.h>
|
||||
#endif
|
||||
|
||||
struct ImGui_ImplOpenGL2_Data
|
||||
{
|
||||
GLuint FontTexture;
|
||||
|
||||
ImGui_ImplOpenGL2_Data() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||
static ImGui_ImplOpenGL2_Data* ImGui_ImplOpenGL2_GetBackendData()
|
||||
{
|
||||
return ImGui::GetCurrentContext() ? (ImGui_ImplOpenGL2_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
|
||||
}
|
||||
|
||||
// Forward Declarations
|
||||
static void ImGui_ImplOpenGL2_InitPlatformInterface();
|
||||
static void ImGui_ImplOpenGL2_ShutdownPlatformInterface();
|
||||
|
||||
// Functions
|
||||
bool ImGui_ImplOpenGL2_Init()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
|
||||
|
||||
// Setup backend capabilities flags
|
||||
ImGui_ImplOpenGL2_Data* bd = IM_NEW(ImGui_ImplOpenGL2_Data)();
|
||||
io.BackendRendererUserData = (void*)bd;
|
||||
io.BackendRendererName = "imgui_impl_opengl2";
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
|
||||
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
ImGui_ImplOpenGL2_InitPlatformInterface();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL2_Shutdown()
|
||||
{
|
||||
ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData();
|
||||
IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui_ImplOpenGL2_ShutdownPlatformInterface();
|
||||
ImGui_ImplOpenGL2_DestroyDeviceObjects();
|
||||
io.BackendRendererName = NULL;
|
||||
io.BackendRendererUserData = NULL;
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL2_NewFrame()
|
||||
{
|
||||
ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData();
|
||||
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplOpenGL2_Init()?");
|
||||
|
||||
if (!bd->FontTexture)
|
||||
ImGui_ImplOpenGL2_CreateDeviceObjects();
|
||||
}
|
||||
|
||||
static void ImGui_ImplOpenGL2_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height)
|
||||
{
|
||||
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers, polygon fill.
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
//glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // In order to composite our output buffer we need to preserve alpha
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glDisable(GL_LIGHTING);
|
||||
glDisable(GL_COLOR_MATERIAL);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
glShadeModel(GL_SMOOTH);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
|
||||
// If you are using this code with non-legacy OpenGL header/contexts (which you should not, prefer using imgui_impl_opengl3.cpp!!),
|
||||
// you may need to backup/reset/restore other state, e.g. for current shader using the commented lines below.
|
||||
// (DO NOT MODIFY THIS FILE! Add the code in your calling function)
|
||||
// GLint last_program;
|
||||
// glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
|
||||
// glUseProgram(0);
|
||||
// ImGui_ImplOpenGL2_RenderDrawData(...);
|
||||
// glUseProgram(last_program)
|
||||
// There are potentially many more states you could need to clear/setup that we can't access from default headers.
|
||||
// e.g. glBindBuffer(GL_ARRAY_BUFFER, 0), glDisable(GL_TEXTURE_CUBE_MAP).
|
||||
|
||||
// Setup viewport, orthographic projection matrix
|
||||
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||
glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glOrtho(draw_data->DisplayPos.x, draw_data->DisplayPos.x + draw_data->DisplaySize.x, draw_data->DisplayPos.y + draw_data->DisplaySize.y, draw_data->DisplayPos.y, -1.0f, +1.0f);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
// OpenGL2 Render function.
|
||||
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly.
|
||||
// This is in order to be able to run within an OpenGL engine that doesn't do so.
|
||||
void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data)
|
||||
{
|
||||
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
|
||||
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
|
||||
if (fb_width == 0 || fb_height == 0)
|
||||
return;
|
||||
|
||||
// Backup GL state
|
||||
GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||
GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
|
||||
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
|
||||
GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
|
||||
GLint last_shade_model; glGetIntegerv(GL_SHADE_MODEL, &last_shade_model);
|
||||
GLint last_tex_env_mode; glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &last_tex_env_mode);
|
||||
glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT);
|
||||
|
||||
// Setup desired GL state
|
||||
ImGui_ImplOpenGL2_SetupRenderState(draw_data, fb_width, fb_height);
|
||||
|
||||
// Will project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
|
||||
ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
|
||||
|
||||
// Render command lists
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data;
|
||||
const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, pos)));
|
||||
glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, uv)));
|
||||
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, col)));
|
||||
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||
if (pcmd->UserCallback)
|
||||
{
|
||||
// User callback, registered via ImDrawList::AddCallback()
|
||||
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||
ImGui_ImplOpenGL2_SetupRenderState(draw_data, fb_width, fb_height);
|
||||
else
|
||||
pcmd->UserCallback(cmd_list, pcmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
|
||||
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
|
||||
if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
|
||||
continue;
|
||||
|
||||
// Apply scissor/clipping rectangle (Y is inverted in OpenGL)
|
||||
glScissor((int)clip_min.x, (int)(fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y));
|
||||
|
||||
// Bind texture, Draw
|
||||
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID());
|
||||
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer);
|
||||
}
|
||||
idx_buffer += pcmd->ElemCount;
|
||||
}
|
||||
}
|
||||
|
||||
// Restore modified GL state
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glBindTexture(GL_TEXTURE_2D, (GLuint)last_texture);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glPopAttrib();
|
||||
glPolygonMode(GL_FRONT, (GLenum)last_polygon_mode[0]); glPolygonMode(GL_BACK, (GLenum)last_polygon_mode[1]);
|
||||
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
|
||||
glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
|
||||
glShadeModel(last_shade_model);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, last_tex_env_mode);
|
||||
}
|
||||
|
||||
bool ImGui_ImplOpenGL2_CreateFontsTexture()
|
||||
{
|
||||
// Build texture atlas
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData();
|
||||
unsigned char* pixels;
|
||||
int width, height;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
|
||||
|
||||
// Upload texture to graphics system
|
||||
GLint last_texture;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||
glGenTextures(1, &bd->FontTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, bd->FontTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture);
|
||||
|
||||
// Restore state
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL2_DestroyFontsTexture()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData();
|
||||
if (bd->FontTexture)
|
||||
{
|
||||
glDeleteTextures(1, &bd->FontTexture);
|
||||
io.Fonts->SetTexID(0);
|
||||
bd->FontTexture = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool ImGui_ImplOpenGL2_CreateDeviceObjects()
|
||||
{
|
||||
return ImGui_ImplOpenGL2_CreateFontsTexture();
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL2_DestroyDeviceObjects()
|
||||
{
|
||||
ImGui_ImplOpenGL2_DestroyFontsTexture();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
|
||||
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
|
||||
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
static void ImGui_ImplOpenGL2_RenderWindow(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
|
||||
{
|
||||
ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
ImGui_ImplOpenGL2_RenderDrawData(viewport->DrawData);
|
||||
}
|
||||
|
||||
static void ImGui_ImplOpenGL2_InitPlatformInterface()
|
||||
{
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Renderer_RenderWindow = ImGui_ImplOpenGL2_RenderWindow;
|
||||
}
|
||||
|
||||
static void ImGui_ImplOpenGL2_ShutdownPlatformInterface()
|
||||
{
|
||||
ImGui::DestroyPlatformWindows();
|
||||
}
|
||||
33
samples/external/Imgui/imgui-docking/backends/imgui_impl_opengl2.h
vendored
Normal file
33
samples/external/Imgui/imgui-docking/backends/imgui_impl_opengl2.h
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
// dear imgui: Renderer Backend for OpenGL2 (legacy OpenGL, fixed pipeline)
|
||||
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Multi-viewport support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)**
|
||||
// **Prefer using the code in imgui_impl_opengl3.cpp**
|
||||
// This code is mostly provided as a reference to learn how ImGui integration works, because it is shorter to read.
|
||||
// If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more
|
||||
// complicated, will require your code to reset every single OpenGL attributes to their initial state, and might
|
||||
// confuse your GPU driver.
|
||||
// The GL2 code is unable to reset attributes or even call e.g. "glUseProgram(0)" because they don't exist in that API.
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplOpenGL2_Init();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL2_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL2_NewFrame();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data);
|
||||
|
||||
// Called by Init/NewFrame/Shutdown
|
||||
IMGUI_IMPL_API bool ImGui_ImplOpenGL2_CreateFontsTexture();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL2_DestroyFontsTexture();
|
||||
IMGUI_IMPL_API bool ImGui_ImplOpenGL2_CreateDeviceObjects();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL2_DestroyDeviceObjects();
|
||||
817
samples/external/Imgui/imgui-docking/backends/imgui_impl_opengl3.cpp
vendored
Normal file
817
samples/external/Imgui/imgui-docking/backends/imgui_impl_opengl3.cpp
vendored
Normal file
@@ -0,0 +1,817 @@
|
||||
// dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline
|
||||
// - Desktop GL: 2.x 3.x 4.x
|
||||
// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
|
||||
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Multi-viewport support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
|
||||
// 2021-08-23: OpenGL: Fixed ES 3.0 shader ("#version 300 es") use normal precision floats to avoid wobbly rendering at HD resolutions.
|
||||
// 2021-08-19: OpenGL: Embed and use our own minimal GL loader (imgui_impl_opengl3_loader.h), removing requirement and support for third-party loader.
|
||||
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||
// 2021-06-25: OpenGL: Use OES_vertex_array extension on Emscripten + backup/restore current state.
|
||||
// 2021-06-21: OpenGL: Destroy individual vertex/fragment shader objects right after they are linked into the main shader.
|
||||
// 2021-05-24: OpenGL: Access GL_CLIP_ORIGIN when "GL_ARB_clip_control" extension is detected, inside of just OpenGL 4.5 version.
|
||||
// 2021-05-19: OpenGL: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||
// 2021-04-06: OpenGL: Don't try to read GL_CLIP_ORIGIN unless we're OpenGL 4.5 or greater.
|
||||
// 2021-02-18: OpenGL: Change blending equation to preserve alpha in output buffer.
|
||||
// 2021-01-03: OpenGL: Backup, setup and restore GL_STENCIL_TEST state.
|
||||
// 2020-10-23: OpenGL: Backup, setup and restore GL_PRIMITIVE_RESTART state.
|
||||
// 2020-10-15: OpenGL: Use glGetString(GL_VERSION) instead of glGetIntegerv(GL_MAJOR_VERSION, ...) when the later returns zero (e.g. Desktop GL 2.x)
|
||||
// 2020-09-17: OpenGL: Fix to avoid compiling/calling glBindSampler() on ES or pre 3.3 context which have the defines set by a loader.
|
||||
// 2020-07-10: OpenGL: Added support for glad2 OpenGL loader.
|
||||
// 2020-05-08: OpenGL: Made default GLSL version 150 (instead of 130) on OSX.
|
||||
// 2020-04-21: OpenGL: Fixed handling of glClipControl(GL_UPPER_LEFT) by inverting projection matrix.
|
||||
// 2020-04-12: OpenGL: Fixed context version check mistakenly testing for 4.0+ instead of 3.2+ to enable ImGuiBackendFlags_RendererHasVtxOffset.
|
||||
// 2020-03-24: OpenGL: Added support for glbinding 2.x OpenGL loader.
|
||||
// 2020-01-07: OpenGL: Added support for glbinding 3.x OpenGL loader.
|
||||
// 2019-10-25: OpenGL: Using a combination of GL define and runtime GL version to decide whether to use glDrawElementsBaseVertex(). Fix building with pre-3.2 GL loaders.
|
||||
// 2019-09-22: OpenGL: Detect default GL loader using __has_include compiler facility.
|
||||
// 2019-09-16: OpenGL: Tweak initialization code to allow application calling ImGui_ImplOpenGL3_CreateFontsTexture() before the first NewFrame() call.
|
||||
// 2019-05-29: OpenGL: Desktop GL only: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||
// 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||
// 2019-03-29: OpenGL: Not calling glBindBuffer more than necessary in the render loop.
|
||||
// 2019-03-15: OpenGL: Added a GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early.
|
||||
// 2019-03-03: OpenGL: Fix support for ES 2.0 (WebGL 1.0).
|
||||
// 2019-02-20: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN even if defined by the headers/loader.
|
||||
// 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
|
||||
// 2019-02-01: OpenGL: Using GLSL 410 shaders for any version over 410 (e.g. 430, 450).
|
||||
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||
// 2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT) / GL_CLIP_ORIGIN.
|
||||
// 2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used.
|
||||
// 2018-08-09: OpenGL: Default to OpenGL ES 3 on iOS and Android. GLSL version default to "#version 300 ES".
|
||||
// 2018-07-30: OpenGL: Support for GLSL 300 ES and 410 core. Fixes for Emscripten compilation.
|
||||
// 2018-07-10: OpenGL: Support for more GLSL versions (based on the GLSL version string). Added error output when shaders fail to compile/link.
|
||||
// 2018-06-08: Misc: Extracted imgui_impl_opengl3.cpp/.h away from the old combined GLFW/SDL+OpenGL3 examples.
|
||||
// 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
||||
// 2018-05-25: OpenGL: Removed unnecessary backup/restore of GL_ELEMENT_ARRAY_BUFFER_BINDING since this is part of the VAO state.
|
||||
// 2018-05-14: OpenGL: Making the call to glBindSampler() optional so 3.2 context won't fail if the function is a NULL pointer.
|
||||
// 2018-03-06: OpenGL: Added const char* glsl_version parameter to ImGui_ImplOpenGL3_Init() so user can override the GLSL version e.g. "#version 150".
|
||||
// 2018-02-23: OpenGL: Create the VAO in the render function so the setup can more easily be used with multiple shared GL context.
|
||||
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplSdlGL3_RenderDrawData() in the .h file so you can call it yourself.
|
||||
// 2018-01-07: OpenGL: Changed GLSL shader version from 330 to 150.
|
||||
// 2017-09-01: OpenGL: Save and restore current bound sampler. Save and restore current polygon mode.
|
||||
// 2017-05-01: OpenGL: Fixed save and restore of current blend func state.
|
||||
// 2017-05-01: OpenGL: Fixed save and restore of current GL_ACTIVE_TEXTURE.
|
||||
// 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle.
|
||||
// 2016-07-29: OpenGL: Explicitly setting GL_UNPACK_ROW_LENGTH to reduce issues because SDL changes it. (#752)
|
||||
|
||||
//----------------------------------------
|
||||
// OpenGL GLSL GLSL
|
||||
// version version string
|
||||
//----------------------------------------
|
||||
// 2.0 110 "#version 110"
|
||||
// 2.1 120 "#version 120"
|
||||
// 3.0 130 "#version 130"
|
||||
// 3.1 140 "#version 140"
|
||||
// 3.2 150 "#version 150"
|
||||
// 3.3 330 "#version 330 core"
|
||||
// 4.0 400 "#version 400 core"
|
||||
// 4.1 410 "#version 410 core"
|
||||
// 4.2 420 "#version 410 core"
|
||||
// 4.3 430 "#version 430 core"
|
||||
// ES 2.0 100 "#version 100" = WebGL 1.0
|
||||
// ES 3.0 300 "#version 300 es" = WebGL 2.0
|
||||
//----------------------------------------
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_opengl3.h"
|
||||
#include <stdio.h>
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
|
||||
#include <stddef.h> // intptr_t
|
||||
#else
|
||||
#include <stdint.h> // intptr_t
|
||||
#endif
|
||||
|
||||
// GL includes
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
#include <GLES2/gl2.h>
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
#ifndef GL_GLEXT_PROTOTYPES
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#endif
|
||||
#include <GLES2/gl2ext.h>
|
||||
#endif
|
||||
#elif defined(IMGUI_IMPL_OPENGL_ES3)
|
||||
#if defined(__APPLE__)
|
||||
#include <TargetConditionals.h>
|
||||
#endif
|
||||
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))
|
||||
#include <OpenGLES/ES3/gl.h> // Use GL ES 3
|
||||
#else
|
||||
#include <GLES3/gl3.h> // Use GL ES 3
|
||||
#endif
|
||||
#elif !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
|
||||
// Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
|
||||
// Helper libraries are often used for this purpose! Here we are using our own minimal custom loader based on gl3w.
|
||||
// In the rest of your app/engine, you can use another loader of your choice (gl3w, glew, glad, glbinding, glext, glLoadGen, etc.).
|
||||
// If you happen to be developing a new feature for this backend (imgui_impl_opengl3.cpp):
|
||||
// - You may need to regenerate imgui_impl_opengl3_loader.h to add new symbols. See https://github.com/dearimgui/gl3w_stripped
|
||||
// - You can temporarily use an unstripped version. See https://github.com/dearimgui/gl3w_stripped/releases
|
||||
// Changes to this backend using new APIs should be accompanied by a regenerated stripped loader version.
|
||||
#define IMGL3W_IMPL
|
||||
#include "imgui_impl_opengl3_loader.h"
|
||||
#endif
|
||||
|
||||
// Vertex arrays are not supported on ES2/WebGL1 unless Emscripten which uses an extension
|
||||
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||
#define IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
#define IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
#define glBindVertexArray glBindVertexArrayOES
|
||||
#define glGenVertexArrays glGenVertexArraysOES
|
||||
#define glDeleteVertexArrays glDeleteVertexArraysOES
|
||||
#define GL_VERTEX_ARRAY_BINDING GL_VERTEX_ARRAY_BINDING_OES
|
||||
#endif
|
||||
|
||||
// Desktop GL 2.0+ has glPolygonMode() which GL ES and WebGL don't have.
|
||||
#ifdef GL_POLYGON_MODE
|
||||
#define IMGUI_IMPL_HAS_POLYGON_MODE
|
||||
#endif
|
||||
|
||||
// Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have.
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_2)
|
||||
#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||
#endif
|
||||
|
||||
// Desktop GL 3.3+ has glBindSampler()
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_3)
|
||||
#define IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||
#endif
|
||||
|
||||
// Desktop GL 3.1+ has GL_PRIMITIVE_RESTART state
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_1)
|
||||
#define IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||
#endif
|
||||
|
||||
// Desktop GL use extension detection
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3)
|
||||
#define IMGUI_IMPL_OPENGL_MAY_HAVE_EXTENSIONS
|
||||
#endif
|
||||
|
||||
// OpenGL Data
|
||||
struct ImGui_ImplOpenGL3_Data
|
||||
{
|
||||
GLuint GlVersion; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
|
||||
char GlslVersionString[32]; // Specified by user or detected based on compile time GL settings.
|
||||
GLuint FontTexture;
|
||||
GLuint ShaderHandle;
|
||||
GLint AttribLocationTex; // Uniforms location
|
||||
GLint AttribLocationProjMtx;
|
||||
GLuint AttribLocationVtxPos; // Vertex attributes location
|
||||
GLuint AttribLocationVtxUV;
|
||||
GLuint AttribLocationVtxColor;
|
||||
unsigned int VboHandle, ElementsHandle;
|
||||
bool HasClipOrigin;
|
||||
|
||||
ImGui_ImplOpenGL3_Data() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||
static ImGui_ImplOpenGL3_Data* ImGui_ImplOpenGL3_GetBackendData()
|
||||
{
|
||||
return ImGui::GetCurrentContext() ? (ImGui_ImplOpenGL3_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
|
||||
}
|
||||
|
||||
// Forward Declarations
|
||||
static void ImGui_ImplOpenGL3_InitPlatformInterface();
|
||||
static void ImGui_ImplOpenGL3_ShutdownPlatformInterface();
|
||||
|
||||
// Functions
|
||||
bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
|
||||
|
||||
// Initialize our loader
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
|
||||
if (imgl3wInit() != 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to initialize OpenGL loader!\n");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Setup backend capabilities flags
|
||||
ImGui_ImplOpenGL3_Data* bd = IM_NEW(ImGui_ImplOpenGL3_Data)();
|
||||
io.BackendRendererUserData = (void*)bd;
|
||||
io.BackendRendererName = "imgui_impl_opengl3";
|
||||
|
||||
// Query for GL version (e.g. 320 for GL 3.2)
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
GLint major = 0;
|
||||
GLint minor = 0;
|
||||
glGetIntegerv(GL_MAJOR_VERSION, &major);
|
||||
glGetIntegerv(GL_MINOR_VERSION, &minor);
|
||||
if (major == 0 && minor == 0)
|
||||
{
|
||||
// Query GL_VERSION in desktop GL 2.x, the string will start with "<major>.<minor>"
|
||||
const char* gl_version = (const char*)glGetString(GL_VERSION);
|
||||
sscanf(gl_version, "%d.%d", &major, &minor);
|
||||
}
|
||||
bd->GlVersion = (GLuint)(major * 100 + minor * 10);
|
||||
#else
|
||||
bd->GlVersion = 200; // GLES 2
|
||||
#endif
|
||||
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||
if (bd->GlVersion >= 320)
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
#endif
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
|
||||
|
||||
// Store GLSL version string so we can refer to it later in case we recreate shaders.
|
||||
// Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure.
|
||||
if (glsl_version == NULL)
|
||||
{
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
glsl_version = "#version 100";
|
||||
#elif defined(IMGUI_IMPL_OPENGL_ES3)
|
||||
glsl_version = "#version 300 es";
|
||||
#elif defined(__APPLE__)
|
||||
glsl_version = "#version 150";
|
||||
#else
|
||||
glsl_version = "#version 130";
|
||||
#endif
|
||||
}
|
||||
IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(bd->GlslVersionString));
|
||||
strcpy(bd->GlslVersionString, glsl_version);
|
||||
strcat(bd->GlslVersionString, "\n");
|
||||
|
||||
// Make an arbitrary GL call (we don't actually need the result)
|
||||
// IF YOU GET A CRASH HERE: it probably means the OpenGL function loader didn't do its job. Let us know!
|
||||
GLint current_texture;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture);
|
||||
|
||||
// Detect extensions we support
|
||||
bd->HasClipOrigin = (bd->GlVersion >= 450);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_EXTENSIONS
|
||||
GLint num_extensions = 0;
|
||||
glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
|
||||
for (GLint i = 0; i < num_extensions; i++)
|
||||
{
|
||||
const char* extension = (const char*)glGetStringi(GL_EXTENSIONS, i);
|
||||
if (extension != NULL && strcmp(extension, "GL_ARB_clip_control") == 0)
|
||||
bd->HasClipOrigin = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
ImGui_ImplOpenGL3_InitPlatformInterface();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_Shutdown()
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui_ImplOpenGL3_ShutdownPlatformInterface();
|
||||
ImGui_ImplOpenGL3_DestroyDeviceObjects();
|
||||
io.BackendRendererName = NULL;
|
||||
io.BackendRendererUserData = NULL;
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_NewFrame()
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplOpenGL3_Init()?");
|
||||
|
||||
if (!bd->ShaderHandle)
|
||||
ImGui_ImplOpenGL3_CreateDeviceObjects();
|
||||
}
|
||||
|
||||
static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
|
||||
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
|
||||
glEnable(GL_BLEND);
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||
if (bd->GlVersion >= 310)
|
||||
glDisable(GL_PRIMITIVE_RESTART);
|
||||
#endif
|
||||
#ifdef IMGUI_IMPL_HAS_POLYGON_MODE
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
#endif
|
||||
|
||||
// Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)
|
||||
#if defined(GL_CLIP_ORIGIN)
|
||||
bool clip_origin_lower_left = true;
|
||||
if (bd->HasClipOrigin)
|
||||
{
|
||||
GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)¤t_clip_origin);
|
||||
if (current_clip_origin == GL_UPPER_LEFT)
|
||||
clip_origin_lower_left = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Setup viewport, orthographic projection matrix
|
||||
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||
glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
|
||||
float L = draw_data->DisplayPos.x;
|
||||
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||
float T = draw_data->DisplayPos.y;
|
||||
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
|
||||
#if defined(GL_CLIP_ORIGIN)
|
||||
if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left
|
||||
#endif
|
||||
const float ortho_projection[4][4] =
|
||||
{
|
||||
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
|
||||
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
|
||||
{ 0.0f, 0.0f, -1.0f, 0.0f },
|
||||
{ (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f },
|
||||
};
|
||||
glUseProgram(bd->ShaderHandle);
|
||||
glUniform1i(bd->AttribLocationTex, 0);
|
||||
glUniformMatrix4fv(bd->AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
|
||||
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||
if (bd->GlVersion >= 330)
|
||||
glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.
|
||||
#endif
|
||||
|
||||
(void)vertex_array_object;
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
glBindVertexArray(vertex_array_object);
|
||||
#endif
|
||||
|
||||
// Bind vertex/index buffers and setup attributes for ImDrawVert
|
||||
glBindBuffer(GL_ARRAY_BUFFER, bd->VboHandle);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bd->ElementsHandle);
|
||||
glEnableVertexAttribArray(bd->AttribLocationVtxPos);
|
||||
glEnableVertexAttribArray(bd->AttribLocationVtxUV);
|
||||
glEnableVertexAttribArray(bd->AttribLocationVtxColor);
|
||||
glVertexAttribPointer(bd->AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos));
|
||||
glVertexAttribPointer(bd->AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv));
|
||||
glVertexAttribPointer(bd->AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col));
|
||||
}
|
||||
|
||||
// OpenGL3 Render function.
|
||||
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly.
|
||||
// This is in order to be able to run within an OpenGL engine that doesn't do so.
|
||||
void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
|
||||
{
|
||||
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
|
||||
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
|
||||
if (fb_width <= 0 || fb_height <= 0)
|
||||
return;
|
||||
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
|
||||
// Backup GL state
|
||||
GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
GLuint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&last_program);
|
||||
GLuint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&last_texture);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||
GLuint last_sampler; if (bd->GlVersion >= 330) { glGetIntegerv(GL_SAMPLER_BINDING, (GLint*)&last_sampler); } else { last_sampler = 0; }
|
||||
#endif
|
||||
GLuint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&last_array_buffer);
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
GLuint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (GLint*)&last_vertex_array_object);
|
||||
#endif
|
||||
#ifdef IMGUI_IMPL_HAS_POLYGON_MODE
|
||||
GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
|
||||
#endif
|
||||
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
|
||||
GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
|
||||
GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb);
|
||||
GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb);
|
||||
GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha);
|
||||
GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha);
|
||||
GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb);
|
||||
GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha);
|
||||
GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
|
||||
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
|
||||
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
|
||||
GLboolean last_enable_stencil_test = glIsEnabled(GL_STENCIL_TEST);
|
||||
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||
GLboolean last_enable_primitive_restart = (bd->GlVersion >= 310) ? glIsEnabled(GL_PRIMITIVE_RESTART) : GL_FALSE;
|
||||
#endif
|
||||
|
||||
// Setup desired GL state
|
||||
// Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts)
|
||||
// The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.
|
||||
GLuint vertex_array_object = 0;
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
glGenVertexArrays(1, &vertex_array_object);
|
||||
#endif
|
||||
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
|
||||
|
||||
// Will project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
|
||||
ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
|
||||
|
||||
// Render command lists
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
|
||||
// Upload vertex/index buffers
|
||||
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * (int)sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW);
|
||||
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||
if (pcmd->UserCallback != NULL)
|
||||
{
|
||||
// User callback, registered via ImDrawList::AddCallback()
|
||||
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
|
||||
else
|
||||
pcmd->UserCallback(cmd_list, pcmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
|
||||
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
|
||||
if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
|
||||
continue;
|
||||
|
||||
// Apply scissor/clipping rectangle (Y is inverted in OpenGL)
|
||||
glScissor((int)clip_min.x, (int)(fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y));
|
||||
|
||||
// Bind texture, Draw
|
||||
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID());
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||
if (bd->GlVersion >= 320)
|
||||
glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset);
|
||||
else
|
||||
#endif
|
||||
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Destroy the temporary VAO
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
glDeleteVertexArrays(1, &vertex_array_object);
|
||||
#endif
|
||||
|
||||
// Restore modified GL state
|
||||
glUseProgram(last_program);
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||
if (bd->GlVersion >= 330)
|
||||
glBindSampler(0, last_sampler);
|
||||
#endif
|
||||
glActiveTexture(last_active_texture);
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
glBindVertexArray(last_vertex_array_object);
|
||||
#endif
|
||||
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||
glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
|
||||
glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);
|
||||
if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
|
||||
if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
|
||||
if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
|
||||
if (last_enable_stencil_test) glEnable(GL_STENCIL_TEST); else glDisable(GL_STENCIL_TEST);
|
||||
if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||
if (bd->GlVersion >= 310) { if (last_enable_primitive_restart) glEnable(GL_PRIMITIVE_RESTART); else glDisable(GL_PRIMITIVE_RESTART); }
|
||||
#endif
|
||||
|
||||
#ifdef IMGUI_IMPL_HAS_POLYGON_MODE
|
||||
glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);
|
||||
#endif
|
||||
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
|
||||
glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
|
||||
(void)bd; // Not all compilation paths use this
|
||||
}
|
||||
|
||||
bool ImGui_ImplOpenGL3_CreateFontsTexture()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
|
||||
// Build texture atlas
|
||||
unsigned char* pixels;
|
||||
int width, height;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
|
||||
|
||||
// Upload texture to graphics system
|
||||
GLint last_texture;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||
glGenTextures(1, &bd->FontTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, bd->FontTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
#ifdef GL_UNPACK_ROW_LENGTH // Not on WebGL/ES
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
#endif
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture);
|
||||
|
||||
// Restore state
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_DestroyFontsTexture()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
if (bd->FontTexture)
|
||||
{
|
||||
glDeleteTextures(1, &bd->FontTexture);
|
||||
io.Fonts->SetTexID(0);
|
||||
bd->FontTexture = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file.
|
||||
static bool CheckShader(GLuint handle, const char* desc)
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
GLint status = 0, log_length = 0;
|
||||
glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
|
||||
glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);
|
||||
if ((GLboolean)status == GL_FALSE)
|
||||
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s! With GLSL: %s\n", desc, bd->GlslVersionString);
|
||||
if (log_length > 1)
|
||||
{
|
||||
ImVector<char> buf;
|
||||
buf.resize((int)(log_length + 1));
|
||||
glGetShaderInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
|
||||
fprintf(stderr, "%s\n", buf.begin());
|
||||
}
|
||||
return (GLboolean)status == GL_TRUE;
|
||||
}
|
||||
|
||||
// If you get an error please report on GitHub. You may try different GL context version or GLSL version.
|
||||
static bool CheckProgram(GLuint handle, const char* desc)
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
GLint status = 0, log_length = 0;
|
||||
glGetProgramiv(handle, GL_LINK_STATUS, &status);
|
||||
glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);
|
||||
if ((GLboolean)status == GL_FALSE)
|
||||
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! With GLSL %s\n", desc, bd->GlslVersionString);
|
||||
if (log_length > 1)
|
||||
{
|
||||
ImVector<char> buf;
|
||||
buf.resize((int)(log_length + 1));
|
||||
glGetProgramInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
|
||||
fprintf(stderr, "%s\n", buf.begin());
|
||||
}
|
||||
return (GLboolean)status == GL_TRUE;
|
||||
}
|
||||
|
||||
bool ImGui_ImplOpenGL3_CreateDeviceObjects()
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
|
||||
// Backup GL state
|
||||
GLint last_texture, last_array_buffer;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
GLint last_vertex_array;
|
||||
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
|
||||
#endif
|
||||
|
||||
// Parse GLSL version string
|
||||
int glsl_version = 130;
|
||||
sscanf(bd->GlslVersionString, "#version %d", &glsl_version);
|
||||
|
||||
const GLchar* vertex_shader_glsl_120 =
|
||||
"uniform mat4 ProjMtx;\n"
|
||||
"attribute vec2 Position;\n"
|
||||
"attribute vec2 UV;\n"
|
||||
"attribute vec4 Color;\n"
|
||||
"varying vec2 Frag_UV;\n"
|
||||
"varying vec4 Frag_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Frag_UV = UV;\n"
|
||||
" Frag_Color = Color;\n"
|
||||
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* vertex_shader_glsl_130 =
|
||||
"uniform mat4 ProjMtx;\n"
|
||||
"in vec2 Position;\n"
|
||||
"in vec2 UV;\n"
|
||||
"in vec4 Color;\n"
|
||||
"out vec2 Frag_UV;\n"
|
||||
"out vec4 Frag_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Frag_UV = UV;\n"
|
||||
" Frag_Color = Color;\n"
|
||||
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* vertex_shader_glsl_300_es =
|
||||
"precision highp float;\n"
|
||||
"layout (location = 0) in vec2 Position;\n"
|
||||
"layout (location = 1) in vec2 UV;\n"
|
||||
"layout (location = 2) in vec4 Color;\n"
|
||||
"uniform mat4 ProjMtx;\n"
|
||||
"out vec2 Frag_UV;\n"
|
||||
"out vec4 Frag_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Frag_UV = UV;\n"
|
||||
" Frag_Color = Color;\n"
|
||||
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* vertex_shader_glsl_410_core =
|
||||
"layout (location = 0) in vec2 Position;\n"
|
||||
"layout (location = 1) in vec2 UV;\n"
|
||||
"layout (location = 2) in vec4 Color;\n"
|
||||
"uniform mat4 ProjMtx;\n"
|
||||
"out vec2 Frag_UV;\n"
|
||||
"out vec4 Frag_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Frag_UV = UV;\n"
|
||||
" Frag_Color = Color;\n"
|
||||
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* fragment_shader_glsl_120 =
|
||||
"#ifdef GL_ES\n"
|
||||
" precision mediump float;\n"
|
||||
"#endif\n"
|
||||
"uniform sampler2D Texture;\n"
|
||||
"varying vec2 Frag_UV;\n"
|
||||
"varying vec4 Frag_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* fragment_shader_glsl_130 =
|
||||
"uniform sampler2D Texture;\n"
|
||||
"in vec2 Frag_UV;\n"
|
||||
"in vec4 Frag_Color;\n"
|
||||
"out vec4 Out_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* fragment_shader_glsl_300_es =
|
||||
"precision mediump float;\n"
|
||||
"uniform sampler2D Texture;\n"
|
||||
"in vec2 Frag_UV;\n"
|
||||
"in vec4 Frag_Color;\n"
|
||||
"layout (location = 0) out vec4 Out_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* fragment_shader_glsl_410_core =
|
||||
"in vec2 Frag_UV;\n"
|
||||
"in vec4 Frag_Color;\n"
|
||||
"uniform sampler2D Texture;\n"
|
||||
"layout (location = 0) out vec4 Out_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
|
||||
"}\n";
|
||||
|
||||
// Select shaders matching our GLSL versions
|
||||
const GLchar* vertex_shader = NULL;
|
||||
const GLchar* fragment_shader = NULL;
|
||||
if (glsl_version < 130)
|
||||
{
|
||||
vertex_shader = vertex_shader_glsl_120;
|
||||
fragment_shader = fragment_shader_glsl_120;
|
||||
}
|
||||
else if (glsl_version >= 410)
|
||||
{
|
||||
vertex_shader = vertex_shader_glsl_410_core;
|
||||
fragment_shader = fragment_shader_glsl_410_core;
|
||||
}
|
||||
else if (glsl_version == 300)
|
||||
{
|
||||
vertex_shader = vertex_shader_glsl_300_es;
|
||||
fragment_shader = fragment_shader_glsl_300_es;
|
||||
}
|
||||
else
|
||||
{
|
||||
vertex_shader = vertex_shader_glsl_130;
|
||||
fragment_shader = fragment_shader_glsl_130;
|
||||
}
|
||||
|
||||
// Create shaders
|
||||
const GLchar* vertex_shader_with_version[2] = { bd->GlslVersionString, vertex_shader };
|
||||
GLuint vert_handle = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(vert_handle, 2, vertex_shader_with_version, NULL);
|
||||
glCompileShader(vert_handle);
|
||||
CheckShader(vert_handle, "vertex shader");
|
||||
|
||||
const GLchar* fragment_shader_with_version[2] = { bd->GlslVersionString, fragment_shader };
|
||||
GLuint frag_handle = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(frag_handle, 2, fragment_shader_with_version, NULL);
|
||||
glCompileShader(frag_handle);
|
||||
CheckShader(frag_handle, "fragment shader");
|
||||
|
||||
// Link
|
||||
bd->ShaderHandle = glCreateProgram();
|
||||
glAttachShader(bd->ShaderHandle, vert_handle);
|
||||
glAttachShader(bd->ShaderHandle, frag_handle);
|
||||
glLinkProgram(bd->ShaderHandle);
|
||||
CheckProgram(bd->ShaderHandle, "shader program");
|
||||
|
||||
glDetachShader(bd->ShaderHandle, vert_handle);
|
||||
glDetachShader(bd->ShaderHandle, frag_handle);
|
||||
glDeleteShader(vert_handle);
|
||||
glDeleteShader(frag_handle);
|
||||
|
||||
bd->AttribLocationTex = glGetUniformLocation(bd->ShaderHandle, "Texture");
|
||||
bd->AttribLocationProjMtx = glGetUniformLocation(bd->ShaderHandle, "ProjMtx");
|
||||
bd->AttribLocationVtxPos = (GLuint)glGetAttribLocation(bd->ShaderHandle, "Position");
|
||||
bd->AttribLocationVtxUV = (GLuint)glGetAttribLocation(bd->ShaderHandle, "UV");
|
||||
bd->AttribLocationVtxColor = (GLuint)glGetAttribLocation(bd->ShaderHandle, "Color");
|
||||
|
||||
// Create buffers
|
||||
glGenBuffers(1, &bd->VboHandle);
|
||||
glGenBuffers(1, &bd->ElementsHandle);
|
||||
|
||||
ImGui_ImplOpenGL3_CreateFontsTexture();
|
||||
|
||||
// Restore modified GL state
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
glBindVertexArray(last_vertex_array);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_DestroyDeviceObjects()
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
if (bd->VboHandle) { glDeleteBuffers(1, &bd->VboHandle); bd->VboHandle = 0; }
|
||||
if (bd->ElementsHandle) { glDeleteBuffers(1, &bd->ElementsHandle); bd->ElementsHandle = 0; }
|
||||
if (bd->ShaderHandle) { glDeleteProgram(bd->ShaderHandle); bd->ShaderHandle = 0; }
|
||||
ImGui_ImplOpenGL3_DestroyFontsTexture();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
|
||||
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
|
||||
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
static void ImGui_ImplOpenGL3_RenderWindow(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
|
||||
{
|
||||
ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
ImGui_ImplOpenGL3_RenderDrawData(viewport->DrawData);
|
||||
}
|
||||
|
||||
static void ImGui_ImplOpenGL3_InitPlatformInterface()
|
||||
{
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Renderer_RenderWindow = ImGui_ImplOpenGL3_RenderWindow;
|
||||
}
|
||||
|
||||
static void ImGui_ImplOpenGL3_ShutdownPlatformInterface()
|
||||
{
|
||||
ImGui::DestroyPlatformWindows();
|
||||
}
|
||||
56
samples/external/Imgui/imgui-docking/backends/imgui_impl_opengl3.h
vendored
Normal file
56
samples/external/Imgui/imgui-docking/backends/imgui_impl_opengl3.h
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
// dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline
|
||||
// - Desktop GL: 2.x 3.x 4.x
|
||||
// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
|
||||
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Multi-viewport support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// About GLSL version:
|
||||
// The 'glsl_version' initialization parameter should be NULL (default) or a "#version XXX" string.
|
||||
// On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es"
|
||||
// Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp.
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
// Backend API
|
||||
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = NULL);
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data);
|
||||
|
||||
// (Optional) Called by Init/NewFrame/Shutdown
|
||||
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture();
|
||||
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects();
|
||||
|
||||
// Specific OpenGL ES versions
|
||||
//#define IMGUI_IMPL_OPENGL_ES2 // Auto-detected on Emscripten
|
||||
//#define IMGUI_IMPL_OPENGL_ES3 // Auto-detected on iOS/Android
|
||||
|
||||
// You can explicitly select GLES2 or GLES3 API by using one of the '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) \
|
||||
&& !defined(IMGUI_IMPL_OPENGL_ES3)
|
||||
|
||||
// Try to detect GLES on matching platforms
|
||||
#if defined(__APPLE__)
|
||||
#include <TargetConditionals.h>
|
||||
#endif
|
||||
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__))
|
||||
#define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es"
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
#define IMGUI_IMPL_OPENGL_ES2 // Emscripten -> GL ES 2, "#version 100"
|
||||
#else
|
||||
// Otherwise imgui_impl_opengl3_loader.h will be used.
|
||||
#endif
|
||||
|
||||
#endif
|
||||
752
samples/external/Imgui/imgui-docking/backends/imgui_impl_opengl3_loader.h
vendored
Normal file
752
samples/external/Imgui/imgui-docking/backends/imgui_impl_opengl3_loader.h
vendored
Normal file
@@ -0,0 +1,752 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// About imgui_impl_opengl3_loader.h:
|
||||
//
|
||||
// We embed our own OpenGL loader to not require user to provide their own or to have to use ours,
|
||||
// which proved to be endless problems for users.
|
||||
// Our loader is custom-generated, based on gl3w but automatically filtered to only include
|
||||
// enums/functions that we use in our imgui_impl_opengl3.cpp source file in order to be small.
|
||||
//
|
||||
// YOU SHOULD NOT NEED TO INCLUDE/USE THIS DIRECTLY. THIS IS USED BY imgui_impl_opengl3.cpp ONLY.
|
||||
// THE REST OF YOUR APP SHOULD USE A DIFFERENT GL LOADER: ANY GL LOADER OF YOUR CHOICE.
|
||||
//
|
||||
// Regenerate with:
|
||||
// python gl3w_gen.py --output ../imgui/backends/imgui_impl_opengl3_loader.h --ref ../imgui/backends/imgui_impl_opengl3.cpp ./extra_symbols.txt
|
||||
//
|
||||
// More info:
|
||||
// https://github.com/dearimgui/gl3w_stripped
|
||||
// https://github.com/ocornut/imgui/issues/4445
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* This file was generated with gl3w_gen.py, part of imgl3w
|
||||
* (hosted at https://github.com/dearimgui/gl3w_stripped)
|
||||
*
|
||||
* This is free and unencumbered software released into the public domain.
|
||||
*
|
||||
* Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
* distribute this software, either in source code form or as a compiled
|
||||
* binary, for any purpose, commercial or non-commercial, and by any
|
||||
* means.
|
||||
*
|
||||
* In jurisdictions that recognize copyright laws, the author or authors
|
||||
* of this software dedicate any and all copyright interest in the
|
||||
* software to the public domain. We make this dedication for the benefit
|
||||
* of the public at large and to the detriment of our heirs and
|
||||
* successors. We intend this dedication to be an overt act of
|
||||
* relinquishment in perpetuity of all present and future rights to this
|
||||
* software under copyright law.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __gl3w_h_
|
||||
#define __gl3w_h_
|
||||
|
||||
// Adapted from KHR/khrplatform.h to avoid including entire file.
|
||||
#ifndef __khrplatform_h_
|
||||
typedef float khronos_float_t;
|
||||
typedef signed char khronos_int8_t;
|
||||
typedef unsigned char khronos_uint8_t;
|
||||
typedef signed short int khronos_int16_t;
|
||||
typedef unsigned short int khronos_uint16_t;
|
||||
#ifdef _WIN64
|
||||
typedef signed long long int khronos_intptr_t;
|
||||
typedef signed long long int khronos_ssize_t;
|
||||
#else
|
||||
typedef signed long int khronos_intptr_t;
|
||||
typedef signed long int khronos_ssize_t;
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
typedef signed __int64 khronos_int64_t;
|
||||
typedef unsigned __int64 khronos_uint64_t;
|
||||
#elif (defined(__clang__) || defined(__GNUC__)) && (__cplusplus < 201100)
|
||||
#include <stdint.h>
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#else
|
||||
typedef signed long long khronos_int64_t;
|
||||
typedef unsigned long long khronos_uint64_t;
|
||||
#endif
|
||||
#endif // __khrplatform_h_
|
||||
|
||||
#ifndef __gl_glcorearb_h_
|
||||
#define __gl_glcorearb_h_ 1
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
** Copyright 2013-2020 The Khronos Group Inc.
|
||||
** SPDX-License-Identifier: MIT
|
||||
**
|
||||
** This header is generated from the Khronos OpenGL / OpenGL ES XML
|
||||
** API Registry. The current version of the Registry, generator scripts
|
||||
** used to make the header, and the header can be found at
|
||||
** https://github.com/KhronosGroup/OpenGL-Registry
|
||||
*/
|
||||
#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#ifndef APIENTRY
|
||||
#define APIENTRY
|
||||
#endif
|
||||
#ifndef APIENTRYP
|
||||
#define APIENTRYP APIENTRY *
|
||||
#endif
|
||||
#ifndef GLAPI
|
||||
#define GLAPI extern
|
||||
#endif
|
||||
/* glcorearb.h is for use with OpenGL core profile implementations.
|
||||
** It should should be placed in the same directory as gl.h and
|
||||
** included as <GL/glcorearb.h>.
|
||||
**
|
||||
** glcorearb.h includes only APIs in the latest OpenGL core profile
|
||||
** implementation together with APIs in newer ARB extensions which
|
||||
** can be supported by the core profile. It does not, and never will
|
||||
** include functionality removed from the core profile, such as
|
||||
** fixed-function vertex and fragment processing.
|
||||
**
|
||||
** Do not #include both <GL/glcorearb.h> and either of <GL/gl.h> or
|
||||
** <GL/glext.h> in the same source file.
|
||||
*/
|
||||
/* Generated C header for:
|
||||
* API: gl
|
||||
* Profile: core
|
||||
* Versions considered: .*
|
||||
* Versions emitted: .*
|
||||
* Default extensions included: glcore
|
||||
* Additional extensions included: _nomatch_^
|
||||
* Extensions removed: _nomatch_^
|
||||
*/
|
||||
#ifndef GL_VERSION_1_0
|
||||
typedef void GLvoid;
|
||||
typedef unsigned int GLenum;
|
||||
|
||||
typedef khronos_float_t GLfloat;
|
||||
typedef int GLint;
|
||||
typedef int GLsizei;
|
||||
typedef unsigned int GLbitfield;
|
||||
typedef double GLdouble;
|
||||
typedef unsigned int GLuint;
|
||||
typedef unsigned char GLboolean;
|
||||
typedef khronos_uint8_t GLubyte;
|
||||
#define GL_COLOR_BUFFER_BIT 0x00004000
|
||||
#define GL_FALSE 0
|
||||
#define GL_TRUE 1
|
||||
#define GL_TRIANGLES 0x0004
|
||||
#define GL_ONE 1
|
||||
#define GL_SRC_ALPHA 0x0302
|
||||
#define GL_ONE_MINUS_SRC_ALPHA 0x0303
|
||||
#define GL_FRONT_AND_BACK 0x0408
|
||||
#define GL_POLYGON_MODE 0x0B40
|
||||
#define GL_CULL_FACE 0x0B44
|
||||
#define GL_DEPTH_TEST 0x0B71
|
||||
#define GL_STENCIL_TEST 0x0B90
|
||||
#define GL_VIEWPORT 0x0BA2
|
||||
#define GL_BLEND 0x0BE2
|
||||
#define GL_SCISSOR_BOX 0x0C10
|
||||
#define GL_SCISSOR_TEST 0x0C11
|
||||
#define GL_UNPACK_ROW_LENGTH 0x0CF2
|
||||
#define GL_PACK_ALIGNMENT 0x0D05
|
||||
#define GL_TEXTURE_2D 0x0DE1
|
||||
#define GL_UNSIGNED_BYTE 0x1401
|
||||
#define GL_UNSIGNED_SHORT 0x1403
|
||||
#define GL_UNSIGNED_INT 0x1405
|
||||
#define GL_FLOAT 0x1406
|
||||
#define GL_RGBA 0x1908
|
||||
#define GL_FILL 0x1B02
|
||||
#define GL_VERSION 0x1F02
|
||||
#define GL_EXTENSIONS 0x1F03
|
||||
#define GL_LINEAR 0x2601
|
||||
#define GL_TEXTURE_MAG_FILTER 0x2800
|
||||
#define GL_TEXTURE_MIN_FILTER 0x2801
|
||||
typedef void (APIENTRYP PFNGLPOLYGONMODEPROC) (GLenum face, GLenum mode);
|
||||
typedef void (APIENTRYP PFNGLSCISSORPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param);
|
||||
typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
|
||||
typedef void (APIENTRYP PFNGLCLEARPROC) (GLbitfield mask);
|
||||
typedef void (APIENTRYP PFNGLCLEARCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
||||
typedef void (APIENTRYP PFNGLDISABLEPROC) (GLenum cap);
|
||||
typedef void (APIENTRYP PFNGLENABLEPROC) (GLenum cap);
|
||||
typedef void (APIENTRYP PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param);
|
||||
typedef void (APIENTRYP PFNGLREADPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);
|
||||
typedef GLenum (APIENTRYP PFNGLGETERRORPROC) (void);
|
||||
typedef void (APIENTRYP PFNGLGETINTEGERVPROC) (GLenum pname, GLint *data);
|
||||
typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGPROC) (GLenum name);
|
||||
typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC) (GLenum cap);
|
||||
typedef void (APIENTRYP PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glPolygonMode (GLenum face, GLenum mode);
|
||||
GLAPI void APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
GLAPI void APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
|
||||
GLAPI void APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
|
||||
GLAPI void APIENTRY glClear (GLbitfield mask);
|
||||
GLAPI void APIENTRY glClearColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
||||
GLAPI void APIENTRY glDisable (GLenum cap);
|
||||
GLAPI void APIENTRY glEnable (GLenum cap);
|
||||
GLAPI void APIENTRY glPixelStorei (GLenum pname, GLint param);
|
||||
GLAPI void APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);
|
||||
GLAPI GLenum APIENTRY glGetError (void);
|
||||
GLAPI void APIENTRY glGetIntegerv (GLenum pname, GLint *data);
|
||||
GLAPI const GLubyte *APIENTRY glGetString (GLenum name);
|
||||
GLAPI GLboolean APIENTRY glIsEnabled (GLenum cap);
|
||||
GLAPI void APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
#endif
|
||||
#endif /* GL_VERSION_1_0 */
|
||||
#ifndef GL_VERSION_1_1
|
||||
typedef khronos_float_t GLclampf;
|
||||
typedef double GLclampd;
|
||||
#define GL_TEXTURE_BINDING_2D 0x8069
|
||||
typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices);
|
||||
typedef void (APIENTRYP PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture);
|
||||
typedef void (APIENTRYP PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint *textures);
|
||||
typedef void (APIENTRYP PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void *indices);
|
||||
GLAPI void APIENTRY glBindTexture (GLenum target, GLuint texture);
|
||||
GLAPI void APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures);
|
||||
GLAPI void APIENTRY glGenTextures (GLsizei n, GLuint *textures);
|
||||
#endif
|
||||
#endif /* GL_VERSION_1_1 */
|
||||
#ifndef GL_VERSION_1_3
|
||||
#define GL_TEXTURE0 0x84C0
|
||||
#define GL_ACTIVE_TEXTURE 0x84E0
|
||||
typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glActiveTexture (GLenum texture);
|
||||
#endif
|
||||
#endif /* GL_VERSION_1_3 */
|
||||
#ifndef GL_VERSION_1_4
|
||||
#define GL_BLEND_DST_RGB 0x80C8
|
||||
#define GL_BLEND_SRC_RGB 0x80C9
|
||||
#define GL_BLEND_DST_ALPHA 0x80CA
|
||||
#define GL_BLEND_SRC_ALPHA 0x80CB
|
||||
#define GL_FUNC_ADD 0x8006
|
||||
typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
|
||||
typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
|
||||
GLAPI void APIENTRY glBlendEquation (GLenum mode);
|
||||
#endif
|
||||
#endif /* GL_VERSION_1_4 */
|
||||
#ifndef GL_VERSION_1_5
|
||||
typedef khronos_ssize_t GLsizeiptr;
|
||||
typedef khronos_intptr_t GLintptr;
|
||||
#define GL_ARRAY_BUFFER 0x8892
|
||||
#define GL_ELEMENT_ARRAY_BUFFER 0x8893
|
||||
#define GL_ARRAY_BUFFER_BINDING 0x8894
|
||||
#define GL_STREAM_DRAW 0x88E0
|
||||
typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
|
||||
typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
|
||||
typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
|
||||
typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer);
|
||||
GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers);
|
||||
GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers);
|
||||
GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
|
||||
#endif
|
||||
#endif /* GL_VERSION_1_5 */
|
||||
#ifndef GL_VERSION_2_0
|
||||
typedef char GLchar;
|
||||
typedef khronos_int16_t GLshort;
|
||||
typedef khronos_int8_t GLbyte;
|
||||
typedef khronos_uint16_t GLushort;
|
||||
#define GL_BLEND_EQUATION_RGB 0x8009
|
||||
#define GL_BLEND_EQUATION_ALPHA 0x883D
|
||||
#define GL_FRAGMENT_SHADER 0x8B30
|
||||
#define GL_VERTEX_SHADER 0x8B31
|
||||
#define GL_COMPILE_STATUS 0x8B81
|
||||
#define GL_LINK_STATUS 0x8B82
|
||||
#define GL_INFO_LOG_LENGTH 0x8B84
|
||||
#define GL_CURRENT_PROGRAM 0x8B8D
|
||||
#define GL_UPPER_LEFT 0x8CA2
|
||||
typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha);
|
||||
typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
|
||||
typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader);
|
||||
typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void);
|
||||
typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type);
|
||||
typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program);
|
||||
typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader);
|
||||
typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader);
|
||||
typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
|
||||
typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name);
|
||||
typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);
|
||||
typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
|
||||
typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
|
||||
typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
|
||||
typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name);
|
||||
typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program);
|
||||
typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
|
||||
typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program);
|
||||
typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0);
|
||||
typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha);
|
||||
GLAPI void APIENTRY glAttachShader (GLuint program, GLuint shader);
|
||||
GLAPI void APIENTRY glCompileShader (GLuint shader);
|
||||
GLAPI GLuint APIENTRY glCreateProgram (void);
|
||||
GLAPI GLuint APIENTRY glCreateShader (GLenum type);
|
||||
GLAPI void APIENTRY glDeleteProgram (GLuint program);
|
||||
GLAPI void APIENTRY glDeleteShader (GLuint shader);
|
||||
GLAPI void APIENTRY glDetachShader (GLuint program, GLuint shader);
|
||||
GLAPI void APIENTRY glEnableVertexAttribArray (GLuint index);
|
||||
GLAPI GLint APIENTRY glGetAttribLocation (GLuint program, const GLchar *name);
|
||||
GLAPI void APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params);
|
||||
GLAPI void APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
|
||||
GLAPI void APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params);
|
||||
GLAPI void APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
|
||||
GLAPI GLint APIENTRY glGetUniformLocation (GLuint program, const GLchar *name);
|
||||
GLAPI void APIENTRY glLinkProgram (GLuint program);
|
||||
GLAPI void APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
|
||||
GLAPI void APIENTRY glUseProgram (GLuint program);
|
||||
GLAPI void APIENTRY glUniform1i (GLint location, GLint v0);
|
||||
GLAPI void APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
|
||||
GLAPI void APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
|
||||
#endif
|
||||
#endif /* GL_VERSION_2_0 */
|
||||
#ifndef GL_VERSION_3_0
|
||||
typedef khronos_uint16_t GLhalf;
|
||||
#define GL_MAJOR_VERSION 0x821B
|
||||
#define GL_MINOR_VERSION 0x821C
|
||||
#define GL_NUM_EXTENSIONS 0x821D
|
||||
#define GL_FRAMEBUFFER_SRGB 0x8DB9
|
||||
#define GL_VERTEX_ARRAY_BINDING 0x85B5
|
||||
typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data);
|
||||
typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data);
|
||||
typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index);
|
||||
typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array);
|
||||
typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays);
|
||||
typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI const GLubyte *APIENTRY glGetStringi (GLenum name, GLuint index);
|
||||
GLAPI void APIENTRY glBindVertexArray (GLuint array);
|
||||
GLAPI void APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint *arrays);
|
||||
GLAPI void APIENTRY glGenVertexArrays (GLsizei n, GLuint *arrays);
|
||||
#endif
|
||||
#endif /* GL_VERSION_3_0 */
|
||||
#ifndef GL_VERSION_3_1
|
||||
#define GL_VERSION_3_1 1
|
||||
#define GL_PRIMITIVE_RESTART 0x8F9D
|
||||
#endif /* GL_VERSION_3_1 */
|
||||
#ifndef GL_VERSION_3_2
|
||||
#define GL_VERSION_3_2 1
|
||||
typedef struct __GLsync *GLsync;
|
||||
typedef khronos_uint64_t GLuint64;
|
||||
typedef khronos_int64_t GLint64;
|
||||
typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
|
||||
typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
|
||||
#endif
|
||||
#endif /* GL_VERSION_3_2 */
|
||||
#ifndef GL_VERSION_3_3
|
||||
#define GL_VERSION_3_3 1
|
||||
#define GL_SAMPLER_BINDING 0x8919
|
||||
typedef void (APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glBindSampler (GLuint unit, GLuint sampler);
|
||||
#endif
|
||||
#endif /* GL_VERSION_3_3 */
|
||||
#ifndef GL_VERSION_4_1
|
||||
typedef void (APIENTRYP PFNGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data);
|
||||
typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data);
|
||||
#endif /* GL_VERSION_4_1 */
|
||||
#ifndef GL_VERSION_4_3
|
||||
typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
|
||||
#endif /* GL_VERSION_4_3 */
|
||||
#ifndef GL_VERSION_4_5
|
||||
#define GL_CLIP_ORIGIN 0x935C
|
||||
typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint *param);
|
||||
typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI64_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint64 *param);
|
||||
#endif /* GL_VERSION_4_5 */
|
||||
#ifndef GL_ARB_bindless_texture
|
||||
typedef khronos_uint64_t GLuint64EXT;
|
||||
#endif /* GL_ARB_bindless_texture */
|
||||
#ifndef GL_ARB_cl_event
|
||||
struct _cl_context;
|
||||
struct _cl_event;
|
||||
#endif /* GL_ARB_cl_event */
|
||||
#ifndef GL_ARB_clip_control
|
||||
#define GL_ARB_clip_control 1
|
||||
#endif /* GL_ARB_clip_control */
|
||||
#ifndef GL_ARB_debug_output
|
||||
typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
|
||||
#endif /* GL_ARB_debug_output */
|
||||
#ifndef GL_EXT_EGL_image_storage
|
||||
typedef void *GLeglImageOES;
|
||||
#endif /* GL_EXT_EGL_image_storage */
|
||||
#ifndef GL_EXT_direct_state_access
|
||||
typedef void (APIENTRYP PFNGLGETFLOATI_VEXTPROC) (GLenum pname, GLuint index, GLfloat *params);
|
||||
typedef void (APIENTRYP PFNGLGETDOUBLEI_VEXTPROC) (GLenum pname, GLuint index, GLdouble *params);
|
||||
typedef void (APIENTRYP PFNGLGETPOINTERI_VEXTPROC) (GLenum pname, GLuint index, void **params);
|
||||
typedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint *param);
|
||||
typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, void **param);
|
||||
#endif /* GL_EXT_direct_state_access */
|
||||
#ifndef GL_NV_draw_vulkan_image
|
||||
typedef void (APIENTRY *GLVULKANPROCNV)(void);
|
||||
#endif /* GL_NV_draw_vulkan_image */
|
||||
#ifndef GL_NV_gpu_shader5
|
||||
typedef khronos_int64_t GLint64EXT;
|
||||
#endif /* GL_NV_gpu_shader5 */
|
||||
#ifndef GL_NV_vertex_buffer_unified_memory
|
||||
typedef void (APIENTRYP PFNGLGETINTEGERUI64I_VNVPROC) (GLenum value, GLuint index, GLuint64EXT *result);
|
||||
#endif /* GL_NV_vertex_buffer_unified_memory */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef GL3W_API
|
||||
#define GL3W_API
|
||||
#endif
|
||||
|
||||
#ifndef __gl_h_
|
||||
#define __gl_h_
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define GL3W_OK 0
|
||||
#define GL3W_ERROR_INIT -1
|
||||
#define GL3W_ERROR_LIBRARY_OPEN -2
|
||||
#define GL3W_ERROR_OPENGL_VERSION -3
|
||||
|
||||
typedef void (*GL3WglProc)(void);
|
||||
typedef GL3WglProc (*GL3WGetProcAddressProc)(const char *proc);
|
||||
|
||||
/* gl3w api */
|
||||
GL3W_API int imgl3wInit(void);
|
||||
GL3W_API int imgl3wInit2(GL3WGetProcAddressProc proc);
|
||||
GL3W_API int imgl3wIsSupported(int major, int minor);
|
||||
GL3W_API GL3WglProc imgl3wGetProcAddress(const char *proc);
|
||||
|
||||
/* gl3w internal state */
|
||||
union GL3WProcs {
|
||||
GL3WglProc ptr[53];
|
||||
struct {
|
||||
PFNGLACTIVETEXTUREPROC ActiveTexture;
|
||||
PFNGLATTACHSHADERPROC AttachShader;
|
||||
PFNGLBINDBUFFERPROC BindBuffer;
|
||||
PFNGLBINDSAMPLERPROC BindSampler;
|
||||
PFNGLBINDTEXTUREPROC BindTexture;
|
||||
PFNGLBINDVERTEXARRAYPROC BindVertexArray;
|
||||
PFNGLBLENDEQUATIONPROC BlendEquation;
|
||||
PFNGLBLENDEQUATIONSEPARATEPROC BlendEquationSeparate;
|
||||
PFNGLBLENDFUNCSEPARATEPROC BlendFuncSeparate;
|
||||
PFNGLBUFFERDATAPROC BufferData;
|
||||
PFNGLCLEARPROC Clear;
|
||||
PFNGLCLEARCOLORPROC ClearColor;
|
||||
PFNGLCOMPILESHADERPROC CompileShader;
|
||||
PFNGLCREATEPROGRAMPROC CreateProgram;
|
||||
PFNGLCREATESHADERPROC CreateShader;
|
||||
PFNGLDELETEBUFFERSPROC DeleteBuffers;
|
||||
PFNGLDELETEPROGRAMPROC DeleteProgram;
|
||||
PFNGLDELETESHADERPROC DeleteShader;
|
||||
PFNGLDELETETEXTURESPROC DeleteTextures;
|
||||
PFNGLDELETEVERTEXARRAYSPROC DeleteVertexArrays;
|
||||
PFNGLDETACHSHADERPROC DetachShader;
|
||||
PFNGLDISABLEPROC Disable;
|
||||
PFNGLDRAWELEMENTSPROC DrawElements;
|
||||
PFNGLDRAWELEMENTSBASEVERTEXPROC DrawElementsBaseVertex;
|
||||
PFNGLENABLEPROC Enable;
|
||||
PFNGLENABLEVERTEXATTRIBARRAYPROC EnableVertexAttribArray;
|
||||
PFNGLGENBUFFERSPROC GenBuffers;
|
||||
PFNGLGENTEXTURESPROC GenTextures;
|
||||
PFNGLGENVERTEXARRAYSPROC GenVertexArrays;
|
||||
PFNGLGETATTRIBLOCATIONPROC GetAttribLocation;
|
||||
PFNGLGETERRORPROC GetError;
|
||||
PFNGLGETINTEGERVPROC GetIntegerv;
|
||||
PFNGLGETPROGRAMINFOLOGPROC GetProgramInfoLog;
|
||||
PFNGLGETPROGRAMIVPROC GetProgramiv;
|
||||
PFNGLGETSHADERINFOLOGPROC GetShaderInfoLog;
|
||||
PFNGLGETSHADERIVPROC GetShaderiv;
|
||||
PFNGLGETSTRINGPROC GetString;
|
||||
PFNGLGETSTRINGIPROC GetStringi;
|
||||
PFNGLGETUNIFORMLOCATIONPROC GetUniformLocation;
|
||||
PFNGLISENABLEDPROC IsEnabled;
|
||||
PFNGLLINKPROGRAMPROC LinkProgram;
|
||||
PFNGLPIXELSTOREIPROC PixelStorei;
|
||||
PFNGLPOLYGONMODEPROC PolygonMode;
|
||||
PFNGLREADPIXELSPROC ReadPixels;
|
||||
PFNGLSCISSORPROC Scissor;
|
||||
PFNGLSHADERSOURCEPROC ShaderSource;
|
||||
PFNGLTEXIMAGE2DPROC TexImage2D;
|
||||
PFNGLTEXPARAMETERIPROC TexParameteri;
|
||||
PFNGLUNIFORM1IPROC Uniform1i;
|
||||
PFNGLUNIFORMMATRIX4FVPROC UniformMatrix4fv;
|
||||
PFNGLUSEPROGRAMPROC UseProgram;
|
||||
PFNGLVERTEXATTRIBPOINTERPROC VertexAttribPointer;
|
||||
PFNGLVIEWPORTPROC Viewport;
|
||||
} gl;
|
||||
};
|
||||
|
||||
GL3W_API extern union GL3WProcs imgl3wProcs;
|
||||
|
||||
/* OpenGL functions */
|
||||
#define glActiveTexture imgl3wProcs.gl.ActiveTexture
|
||||
#define glAttachShader imgl3wProcs.gl.AttachShader
|
||||
#define glBindBuffer imgl3wProcs.gl.BindBuffer
|
||||
#define glBindSampler imgl3wProcs.gl.BindSampler
|
||||
#define glBindTexture imgl3wProcs.gl.BindTexture
|
||||
#define glBindVertexArray imgl3wProcs.gl.BindVertexArray
|
||||
#define glBlendEquation imgl3wProcs.gl.BlendEquation
|
||||
#define glBlendEquationSeparate imgl3wProcs.gl.BlendEquationSeparate
|
||||
#define glBlendFuncSeparate imgl3wProcs.gl.BlendFuncSeparate
|
||||
#define glBufferData imgl3wProcs.gl.BufferData
|
||||
#define glClear imgl3wProcs.gl.Clear
|
||||
#define glClearColor imgl3wProcs.gl.ClearColor
|
||||
#define glCompileShader imgl3wProcs.gl.CompileShader
|
||||
#define glCreateProgram imgl3wProcs.gl.CreateProgram
|
||||
#define glCreateShader imgl3wProcs.gl.CreateShader
|
||||
#define glDeleteBuffers imgl3wProcs.gl.DeleteBuffers
|
||||
#define glDeleteProgram imgl3wProcs.gl.DeleteProgram
|
||||
#define glDeleteShader imgl3wProcs.gl.DeleteShader
|
||||
#define glDeleteTextures imgl3wProcs.gl.DeleteTextures
|
||||
#define glDeleteVertexArrays imgl3wProcs.gl.DeleteVertexArrays
|
||||
#define glDetachShader imgl3wProcs.gl.DetachShader
|
||||
#define glDisable imgl3wProcs.gl.Disable
|
||||
#define glDrawElements imgl3wProcs.gl.DrawElements
|
||||
#define glDrawElementsBaseVertex imgl3wProcs.gl.DrawElementsBaseVertex
|
||||
#define glEnable imgl3wProcs.gl.Enable
|
||||
#define glEnableVertexAttribArray imgl3wProcs.gl.EnableVertexAttribArray
|
||||
#define glGenBuffers imgl3wProcs.gl.GenBuffers
|
||||
#define glGenTextures imgl3wProcs.gl.GenTextures
|
||||
#define glGenVertexArrays imgl3wProcs.gl.GenVertexArrays
|
||||
#define glGetAttribLocation imgl3wProcs.gl.GetAttribLocation
|
||||
#define glGetError imgl3wProcs.gl.GetError
|
||||
#define glGetIntegerv imgl3wProcs.gl.GetIntegerv
|
||||
#define glGetProgramInfoLog imgl3wProcs.gl.GetProgramInfoLog
|
||||
#define glGetProgramiv imgl3wProcs.gl.GetProgramiv
|
||||
#define glGetShaderInfoLog imgl3wProcs.gl.GetShaderInfoLog
|
||||
#define glGetShaderiv imgl3wProcs.gl.GetShaderiv
|
||||
#define glGetString imgl3wProcs.gl.GetString
|
||||
#define glGetStringi imgl3wProcs.gl.GetStringi
|
||||
#define glGetUniformLocation imgl3wProcs.gl.GetUniformLocation
|
||||
#define glIsEnabled imgl3wProcs.gl.IsEnabled
|
||||
#define glLinkProgram imgl3wProcs.gl.LinkProgram
|
||||
#define glPixelStorei imgl3wProcs.gl.PixelStorei
|
||||
#define glPolygonMode imgl3wProcs.gl.PolygonMode
|
||||
#define glReadPixels imgl3wProcs.gl.ReadPixels
|
||||
#define glScissor imgl3wProcs.gl.Scissor
|
||||
#define glShaderSource imgl3wProcs.gl.ShaderSource
|
||||
#define glTexImage2D imgl3wProcs.gl.TexImage2D
|
||||
#define glTexParameteri imgl3wProcs.gl.TexParameteri
|
||||
#define glUniform1i imgl3wProcs.gl.Uniform1i
|
||||
#define glUniformMatrix4fv imgl3wProcs.gl.UniformMatrix4fv
|
||||
#define glUseProgram imgl3wProcs.gl.UseProgram
|
||||
#define glVertexAttribPointer imgl3wProcs.gl.VertexAttribPointer
|
||||
#define glViewport imgl3wProcs.gl.Viewport
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef IMGL3W_IMPL
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
#if defined(_WIN32)
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#endif
|
||||
#include <windows.h>
|
||||
|
||||
static HMODULE libgl;
|
||||
typedef PROC(__stdcall* GL3WglGetProcAddr)(LPCSTR);
|
||||
static GL3WglGetProcAddr wgl_get_proc_address;
|
||||
|
||||
static int open_libgl(void)
|
||||
{
|
||||
libgl = LoadLibraryA("opengl32.dll");
|
||||
if (!libgl)
|
||||
return GL3W_ERROR_LIBRARY_OPEN;
|
||||
wgl_get_proc_address = (GL3WglGetProcAddr)GetProcAddress(libgl, "wglGetProcAddress");
|
||||
return GL3W_OK;
|
||||
}
|
||||
|
||||
static void close_libgl(void) { FreeLibrary(libgl); }
|
||||
static GL3WglProc get_proc(const char *proc)
|
||||
{
|
||||
GL3WglProc res;
|
||||
res = (GL3WglProc)wgl_get_proc_address(proc);
|
||||
if (!res)
|
||||
res = (GL3WglProc)GetProcAddress(libgl, proc);
|
||||
return res;
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
#include <dlfcn.h>
|
||||
|
||||
static void *libgl;
|
||||
static int open_libgl(void)
|
||||
{
|
||||
libgl = dlopen("/System/Library/Frameworks/OpenGL.framework/OpenGL", RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!libgl)
|
||||
return GL3W_ERROR_LIBRARY_OPEN;
|
||||
return GL3W_OK;
|
||||
}
|
||||
|
||||
static void close_libgl(void) { dlclose(libgl); }
|
||||
|
||||
static GL3WglProc get_proc(const char *proc)
|
||||
{
|
||||
GL3WglProc res;
|
||||
*(void **)(&res) = dlsym(libgl, proc);
|
||||
return res;
|
||||
}
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
|
||||
static void *libgl;
|
||||
static GL3WglProc (*glx_get_proc_address)(const GLubyte *);
|
||||
|
||||
static int open_libgl(void)
|
||||
{
|
||||
libgl = dlopen("libGL.so.1", RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!libgl)
|
||||
return GL3W_ERROR_LIBRARY_OPEN;
|
||||
*(void **)(&glx_get_proc_address) = dlsym(libgl, "glXGetProcAddressARB");
|
||||
return GL3W_OK;
|
||||
}
|
||||
|
||||
static void close_libgl(void) { dlclose(libgl); }
|
||||
|
||||
static GL3WglProc get_proc(const char *proc)
|
||||
{
|
||||
GL3WglProc res;
|
||||
res = glx_get_proc_address((const GLubyte *)proc);
|
||||
if (!res)
|
||||
*(void **)(&res) = dlsym(libgl, proc);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct { int major, minor; } version;
|
||||
|
||||
static int parse_version(void)
|
||||
{
|
||||
if (!glGetIntegerv)
|
||||
return GL3W_ERROR_INIT;
|
||||
glGetIntegerv(GL_MAJOR_VERSION, &version.major);
|
||||
glGetIntegerv(GL_MINOR_VERSION, &version.minor);
|
||||
if (version.major < 3)
|
||||
return GL3W_ERROR_OPENGL_VERSION;
|
||||
return GL3W_OK;
|
||||
}
|
||||
|
||||
static void load_procs(GL3WGetProcAddressProc proc);
|
||||
|
||||
int imgl3wInit(void)
|
||||
{
|
||||
int res = open_libgl();
|
||||
if (res)
|
||||
return res;
|
||||
atexit(close_libgl);
|
||||
return imgl3wInit2(get_proc);
|
||||
}
|
||||
|
||||
int imgl3wInit2(GL3WGetProcAddressProc proc)
|
||||
{
|
||||
load_procs(proc);
|
||||
return parse_version();
|
||||
}
|
||||
|
||||
int imgl3wIsSupported(int major, int minor)
|
||||
{
|
||||
if (major < 3)
|
||||
return 0;
|
||||
if (version.major == major)
|
||||
return version.minor >= minor;
|
||||
return version.major >= major;
|
||||
}
|
||||
|
||||
GL3WglProc imgl3wGetProcAddress(const char *proc) { return get_proc(proc); }
|
||||
|
||||
static const char *proc_names[] = {
|
||||
"glActiveTexture",
|
||||
"glAttachShader",
|
||||
"glBindBuffer",
|
||||
"glBindSampler",
|
||||
"glBindTexture",
|
||||
"glBindVertexArray",
|
||||
"glBlendEquation",
|
||||
"glBlendEquationSeparate",
|
||||
"glBlendFuncSeparate",
|
||||
"glBufferData",
|
||||
"glClear",
|
||||
"glClearColor",
|
||||
"glCompileShader",
|
||||
"glCreateProgram",
|
||||
"glCreateShader",
|
||||
"glDeleteBuffers",
|
||||
"glDeleteProgram",
|
||||
"glDeleteShader",
|
||||
"glDeleteTextures",
|
||||
"glDeleteVertexArrays",
|
||||
"glDetachShader",
|
||||
"glDisable",
|
||||
"glDrawElements",
|
||||
"glDrawElementsBaseVertex",
|
||||
"glEnable",
|
||||
"glEnableVertexAttribArray",
|
||||
"glGenBuffers",
|
||||
"glGenTextures",
|
||||
"glGenVertexArrays",
|
||||
"glGetAttribLocation",
|
||||
"glGetError",
|
||||
"glGetIntegerv",
|
||||
"glGetProgramInfoLog",
|
||||
"glGetProgramiv",
|
||||
"glGetShaderInfoLog",
|
||||
"glGetShaderiv",
|
||||
"glGetString",
|
||||
"glGetStringi",
|
||||
"glGetUniformLocation",
|
||||
"glIsEnabled",
|
||||
"glLinkProgram",
|
||||
"glPixelStorei",
|
||||
"glPolygonMode",
|
||||
"glReadPixels",
|
||||
"glScissor",
|
||||
"glShaderSource",
|
||||
"glTexImage2D",
|
||||
"glTexParameteri",
|
||||
"glUniform1i",
|
||||
"glUniformMatrix4fv",
|
||||
"glUseProgram",
|
||||
"glVertexAttribPointer",
|
||||
"glViewport",
|
||||
};
|
||||
|
||||
GL3W_API union GL3WProcs imgl3wProcs;
|
||||
|
||||
static void load_procs(GL3WGetProcAddressProc proc)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < ARRAY_SIZE(proc_names); i++)
|
||||
imgl3wProcs.ptr[i] = proc(proc_names[i]);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
25
samples/external/Imgui/imgui-docking/backends/imgui_impl_osx.h
vendored
Normal file
25
samples/external/Imgui/imgui-docking/backends/imgui_impl_osx.h
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
// dear imgui: Platform Backend for OSX / Cocoa
|
||||
// This needs to be used along with a Renderer (e.g. OpenGL2, OpenGL3, Vulkan, Metal..)
|
||||
// [ALPHA] Early backend, not well tested. If you want a portable application, prefer using the GLFW or SDL platform Backends on Mac.
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// [X] Platform: OSX clipboard is supported within core Dear ImGui (no specific code in this backend).
|
||||
// Issues:
|
||||
// [ ] Platform: Keys are all generally very broken. Best using [event keycode] and not [event characters]..
|
||||
// [ ] Platform: Multi-viewport / platform windows.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
@class NSEvent;
|
||||
@class NSView;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplOSX_Init();
|
||||
IMGUI_IMPL_API void ImGui_ImplOSX_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplOSX_NewFrame(NSView* _Nullable view);
|
||||
IMGUI_IMPL_API bool ImGui_ImplOSX_HandleEvent(NSEvent* _Nonnull event, NSView* _Nullable view);
|
||||
388
samples/external/Imgui/imgui-docking/backends/imgui_impl_osx.mm
vendored
Normal file
388
samples/external/Imgui/imgui-docking/backends/imgui_impl_osx.mm
vendored
Normal file
@@ -0,0 +1,388 @@
|
||||
// dear imgui: Platform Backend for OSX / Cocoa
|
||||
// This needs to be used along with a Renderer (e.g. OpenGL2, OpenGL3, Vulkan, Metal..)
|
||||
// [ALPHA] Early backend, not well tested. If you want a portable application, prefer using the GLFW or SDL platform Backends on Mac.
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// [X] Platform: OSX clipboard is supported within core Dear ImGui (no specific code in this backend).
|
||||
// Issues:
|
||||
// [ ] Platform: Keys are all generally very broken. Best using [event keycode] and not [event characters]..
|
||||
// [ ] Platform: Multi-viewport / platform windows.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_osx.h"
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#include <mach/mach_time.h>
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2021-09-21: Use mach_absolute_time as CFAbsoluteTimeGetCurrent can jump backwards.
|
||||
// 2021-08-17: Calling io.AddFocusEvent() on NSApplicationDidBecomeActiveNotification/NSApplicationDidResignActiveNotification events.
|
||||
// 2021-06-23: Inputs: Added a fix for shortcuts using CTRL key instead of CMD key.
|
||||
// 2021-04-19: Inputs: Added a fix for keys remaining stuck in pressed state when CMD-tabbing into different application.
|
||||
// 2021-01-27: Inputs: Added a fix for mouse position not being reported when mouse buttons other than left one are down.
|
||||
// 2020-10-28: Inputs: Added a fix for handling keypad-enter key.
|
||||
// 2020-05-25: Inputs: Added a fix for missing trackpad clicks when done with "soft tap".
|
||||
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
|
||||
// 2019-10-11: Inputs: Fix using Backspace key.
|
||||
// 2019-07-21: Re-added clipboard handlers as they are not enabled by default in core imgui.cpp (reverted 2019-05-18 change).
|
||||
// 2019-05-28: Inputs: Added mouse cursor shape and visibility support.
|
||||
// 2019-05-18: Misc: Removed clipboard handlers as they are now supported by core imgui.cpp.
|
||||
// 2019-05-11: Inputs: Don't filter character values before calling AddInputCharacter() apart from 0xF700..0xFFFF range.
|
||||
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
|
||||
// 2018-07-07: Initial version.
|
||||
|
||||
@class ImFocusObserver;
|
||||
|
||||
// Data
|
||||
static double g_HostClockPeriod = 0.0;
|
||||
static double g_Time = 0.0;
|
||||
static NSCursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = {};
|
||||
static bool g_MouseCursorHidden = false;
|
||||
static bool g_MouseJustPressed[ImGuiMouseButton_COUNT] = {};
|
||||
static bool g_MouseDown[ImGuiMouseButton_COUNT] = {};
|
||||
static ImFocusObserver* g_FocusObserver = NULL;
|
||||
|
||||
// Undocumented methods for creating cursors.
|
||||
@interface NSCursor()
|
||||
+ (id)_windowResizeNorthWestSouthEastCursor;
|
||||
+ (id)_windowResizeNorthEastSouthWestCursor;
|
||||
+ (id)_windowResizeNorthSouthCursor;
|
||||
+ (id)_windowResizeEastWestCursor;
|
||||
@end
|
||||
|
||||
static void InitHostClockPeriod()
|
||||
{
|
||||
struct mach_timebase_info info;
|
||||
mach_timebase_info(&info);
|
||||
g_HostClockPeriod = 1e-9 * ((double)info.denom / (double)info.numer); // Period is the reciprocal of frequency.
|
||||
}
|
||||
|
||||
static double GetMachAbsoluteTimeInSeconds()
|
||||
{
|
||||
return (double)mach_absolute_time() * g_HostClockPeriod;
|
||||
}
|
||||
|
||||
static void resetKeys()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
memset(io.KeysDown, 0, sizeof(io.KeysDown));
|
||||
io.KeyCtrl = io.KeyShift = io.KeyAlt = io.KeySuper = false;
|
||||
}
|
||||
|
||||
@interface ImFocusObserver : NSObject
|
||||
|
||||
- (void)onApplicationBecomeActive:(NSNotification*)aNotification;
|
||||
- (void)onApplicationBecomeInactive:(NSNotification*)aNotification;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ImFocusObserver
|
||||
|
||||
- (void)onApplicationBecomeActive:(NSNotification*)aNotification
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.AddFocusEvent(true);
|
||||
}
|
||||
|
||||
- (void)onApplicationBecomeInactive:(NSNotification*)aNotification
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.AddFocusEvent(false);
|
||||
|
||||
// Unfocused applications do not receive input events, therefore we must manually
|
||||
// release any pressed keys when application loses focus, otherwise they would remain
|
||||
// stuck in a pressed state. https://github.com/ocornut/imgui/issues/3832
|
||||
resetKeys();
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// Functions
|
||||
bool ImGui_ImplOSX_Init()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
// Setup backend capabilities flags
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||
//io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||
//io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
|
||||
//io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can set io.MouseHoveredViewport correctly (optional, not easy)
|
||||
io.BackendPlatformName = "imgui_impl_osx";
|
||||
|
||||
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeyDown[] array.
|
||||
const int offset_for_function_keys = 256 - 0xF700;
|
||||
io.KeyMap[ImGuiKey_Tab] = '\t';
|
||||
io.KeyMap[ImGuiKey_LeftArrow] = NSLeftArrowFunctionKey + offset_for_function_keys;
|
||||
io.KeyMap[ImGuiKey_RightArrow] = NSRightArrowFunctionKey + offset_for_function_keys;
|
||||
io.KeyMap[ImGuiKey_UpArrow] = NSUpArrowFunctionKey + offset_for_function_keys;
|
||||
io.KeyMap[ImGuiKey_DownArrow] = NSDownArrowFunctionKey + offset_for_function_keys;
|
||||
io.KeyMap[ImGuiKey_PageUp] = NSPageUpFunctionKey + offset_for_function_keys;
|
||||
io.KeyMap[ImGuiKey_PageDown] = NSPageDownFunctionKey + offset_for_function_keys;
|
||||
io.KeyMap[ImGuiKey_Home] = NSHomeFunctionKey + offset_for_function_keys;
|
||||
io.KeyMap[ImGuiKey_End] = NSEndFunctionKey + offset_for_function_keys;
|
||||
io.KeyMap[ImGuiKey_Insert] = NSInsertFunctionKey + offset_for_function_keys;
|
||||
io.KeyMap[ImGuiKey_Delete] = NSDeleteFunctionKey + offset_for_function_keys;
|
||||
io.KeyMap[ImGuiKey_Backspace] = 127;
|
||||
io.KeyMap[ImGuiKey_Space] = 32;
|
||||
io.KeyMap[ImGuiKey_Enter] = 13;
|
||||
io.KeyMap[ImGuiKey_Escape] = 27;
|
||||
io.KeyMap[ImGuiKey_KeyPadEnter] = 3;
|
||||
io.KeyMap[ImGuiKey_A] = 'A';
|
||||
io.KeyMap[ImGuiKey_C] = 'C';
|
||||
io.KeyMap[ImGuiKey_V] = 'V';
|
||||
io.KeyMap[ImGuiKey_X] = 'X';
|
||||
io.KeyMap[ImGuiKey_Y] = 'Y';
|
||||
io.KeyMap[ImGuiKey_Z] = 'Z';
|
||||
|
||||
// Load cursors. Some of them are undocumented.
|
||||
g_MouseCursorHidden = false;
|
||||
g_MouseCursors[ImGuiMouseCursor_Arrow] = [NSCursor arrowCursor];
|
||||
g_MouseCursors[ImGuiMouseCursor_TextInput] = [NSCursor IBeamCursor];
|
||||
g_MouseCursors[ImGuiMouseCursor_ResizeAll] = [NSCursor closedHandCursor];
|
||||
g_MouseCursors[ImGuiMouseCursor_Hand] = [NSCursor pointingHandCursor];
|
||||
g_MouseCursors[ImGuiMouseCursor_NotAllowed] = [NSCursor operationNotAllowedCursor];
|
||||
g_MouseCursors[ImGuiMouseCursor_ResizeNS] = [NSCursor respondsToSelector:@selector(_windowResizeNorthSouthCursor)] ? [NSCursor _windowResizeNorthSouthCursor] : [NSCursor resizeUpDownCursor];
|
||||
g_MouseCursors[ImGuiMouseCursor_ResizeEW] = [NSCursor respondsToSelector:@selector(_windowResizeEastWestCursor)] ? [NSCursor _windowResizeEastWestCursor] : [NSCursor resizeLeftRightCursor];
|
||||
g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = [NSCursor respondsToSelector:@selector(_windowResizeNorthEastSouthWestCursor)] ? [NSCursor _windowResizeNorthEastSouthWestCursor] : [NSCursor closedHandCursor];
|
||||
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = [NSCursor respondsToSelector:@selector(_windowResizeNorthWestSouthEastCursor)] ? [NSCursor _windowResizeNorthWestSouthEastCursor] : [NSCursor closedHandCursor];
|
||||
|
||||
// Note that imgui.cpp also include default OSX clipboard handlers which can be enabled
|
||||
// by adding '#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS' in imconfig.h and adding '-framework ApplicationServices' to your linker command-line.
|
||||
// Since we are already in ObjC land here, it is easy for us to add a clipboard handler using the NSPasteboard api.
|
||||
io.SetClipboardTextFn = [](void*, const char* str) -> void
|
||||
{
|
||||
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
|
||||
[pasteboard declareTypes:[NSArray arrayWithObject:NSPasteboardTypeString] owner:nil];
|
||||
[pasteboard setString:[NSString stringWithUTF8String:str] forType:NSPasteboardTypeString];
|
||||
};
|
||||
|
||||
io.GetClipboardTextFn = [](void*) -> const char*
|
||||
{
|
||||
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
|
||||
NSString* available = [pasteboard availableTypeFromArray: [NSArray arrayWithObject:NSPasteboardTypeString]];
|
||||
if (![available isEqualToString:NSPasteboardTypeString])
|
||||
return NULL;
|
||||
|
||||
NSString* string = [pasteboard stringForType:NSPasteboardTypeString];
|
||||
if (string == nil)
|
||||
return NULL;
|
||||
|
||||
const char* string_c = (const char*)[string UTF8String];
|
||||
size_t string_len = strlen(string_c);
|
||||
static ImVector<char> s_clipboard;
|
||||
s_clipboard.resize((int)string_len + 1);
|
||||
strcpy(s_clipboard.Data, string_c);
|
||||
return s_clipboard.Data;
|
||||
};
|
||||
|
||||
g_FocusObserver = [[ImFocusObserver alloc] init];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:g_FocusObserver
|
||||
selector:@selector(onApplicationBecomeActive:)
|
||||
name:NSApplicationDidBecomeActiveNotification
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:g_FocusObserver
|
||||
selector:@selector(onApplicationBecomeInactive:)
|
||||
name:NSApplicationDidResignActiveNotification
|
||||
object:nil];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplOSX_Shutdown()
|
||||
{
|
||||
g_FocusObserver = NULL;
|
||||
}
|
||||
|
||||
static void ImGui_ImplOSX_UpdateMouseCursorAndButtons()
|
||||
{
|
||||
// Update buttons
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
|
||||
{
|
||||
// If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
|
||||
io.MouseDown[i] = g_MouseJustPressed[i] || g_MouseDown[i];
|
||||
g_MouseJustPressed[i] = false;
|
||||
}
|
||||
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
|
||||
return;
|
||||
|
||||
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
||||
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None)
|
||||
{
|
||||
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
||||
if (!g_MouseCursorHidden)
|
||||
{
|
||||
g_MouseCursorHidden = true;
|
||||
[NSCursor hide];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Show OS mouse cursor
|
||||
[g_MouseCursors[g_MouseCursors[imgui_cursor] ? imgui_cursor : ImGuiMouseCursor_Arrow] set];
|
||||
if (g_MouseCursorHidden)
|
||||
{
|
||||
g_MouseCursorHidden = false;
|
||||
[NSCursor unhide];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImGui_ImplOSX_NewFrame(NSView* view)
|
||||
{
|
||||
// Setup display size
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (view)
|
||||
{
|
||||
const float dpi = (float)[view.window backingScaleFactor];
|
||||
io.DisplaySize = ImVec2((float)view.bounds.size.width, (float)view.bounds.size.height);
|
||||
io.DisplayFramebufferScale = ImVec2(dpi, dpi);
|
||||
}
|
||||
|
||||
// Setup time step
|
||||
if (g_Time == 0.0)
|
||||
{
|
||||
InitHostClockPeriod();
|
||||
g_Time = GetMachAbsoluteTimeInSeconds();
|
||||
}
|
||||
double current_time = GetMachAbsoluteTimeInSeconds();
|
||||
io.DeltaTime = (float)(current_time - g_Time);
|
||||
g_Time = current_time;
|
||||
|
||||
ImGui_ImplOSX_UpdateMouseCursorAndButtons();
|
||||
}
|
||||
|
||||
static int mapCharacterToKey(int c)
|
||||
{
|
||||
if (c >= 'a' && c <= 'z')
|
||||
return c - 'a' + 'A';
|
||||
if (c == 25) // SHIFT+TAB -> TAB
|
||||
return 9;
|
||||
if (c >= 0 && c < 256)
|
||||
return c;
|
||||
if (c >= 0xF700 && c < 0xF700 + 256)
|
||||
return c - 0xF700 + 256;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
if (event.type == NSEventTypeLeftMouseDown || event.type == NSEventTypeRightMouseDown || event.type == NSEventTypeOtherMouseDown)
|
||||
{
|
||||
int button = (int)[event buttonNumber];
|
||||
if (button >= 0 && button < IM_ARRAYSIZE(g_MouseDown))
|
||||
g_MouseDown[button] = g_MouseJustPressed[button] = true;
|
||||
return io.WantCaptureMouse;
|
||||
}
|
||||
|
||||
if (event.type == NSEventTypeLeftMouseUp || event.type == NSEventTypeRightMouseUp || event.type == NSEventTypeOtherMouseUp)
|
||||
{
|
||||
int button = (int)[event buttonNumber];
|
||||
if (button >= 0 && button < IM_ARRAYSIZE(g_MouseDown))
|
||||
g_MouseDown[button] = false;
|
||||
return io.WantCaptureMouse;
|
||||
}
|
||||
|
||||
if (event.type == NSEventTypeMouseMoved || event.type == NSEventTypeLeftMouseDragged || event.type == NSEventTypeRightMouseDragged || event.type == NSEventTypeOtherMouseDragged)
|
||||
{
|
||||
NSPoint mousePoint = event.locationInWindow;
|
||||
mousePoint = [view convertPoint:mousePoint fromView:nil];
|
||||
mousePoint = NSMakePoint(mousePoint.x, view.bounds.size.height - mousePoint.y);
|
||||
io.MousePos = ImVec2((float)mousePoint.x, (float)mousePoint.y);
|
||||
}
|
||||
|
||||
if (event.type == NSEventTypeScrollWheel)
|
||||
{
|
||||
double wheel_dx = 0.0;
|
||||
double wheel_dy = 0.0;
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6)
|
||||
{
|
||||
wheel_dx = [event scrollingDeltaX];
|
||||
wheel_dy = [event scrollingDeltaY];
|
||||
if ([event hasPreciseScrollingDeltas])
|
||||
{
|
||||
wheel_dx *= 0.1;
|
||||
wheel_dy *= 0.1;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif // MAC_OS_X_VERSION_MAX_ALLOWED
|
||||
{
|
||||
wheel_dx = [event deltaX];
|
||||
wheel_dy = [event deltaY];
|
||||
}
|
||||
|
||||
if (fabs(wheel_dx) > 0.0)
|
||||
io.MouseWheelH += (float)wheel_dx * 0.1f;
|
||||
if (fabs(wheel_dy) > 0.0)
|
||||
io.MouseWheel += (float)wheel_dy * 0.1f;
|
||||
return io.WantCaptureMouse;
|
||||
}
|
||||
|
||||
// FIXME: All the key handling is wrong and broken. Refer to GLFW's cocoa_init.mm and cocoa_window.mm.
|
||||
if (event.type == NSEventTypeKeyDown)
|
||||
{
|
||||
NSString* str = [event characters];
|
||||
NSUInteger len = [str length];
|
||||
for (NSUInteger i = 0; i < len; i++)
|
||||
{
|
||||
int c = [str characterAtIndex:i];
|
||||
if (!io.KeySuper && !(c >= 0xF700 && c <= 0xFFFF) && c != 127)
|
||||
io.AddInputCharacter((unsigned int)c);
|
||||
|
||||
// We must reset in case we're pressing a sequence of special keys while keeping the command pressed
|
||||
int key = mapCharacterToKey(c);
|
||||
if (key != -1 && key < 256 && !io.KeySuper)
|
||||
resetKeys();
|
||||
if (key != -1)
|
||||
io.KeysDown[key] = true;
|
||||
}
|
||||
return io.WantCaptureKeyboard;
|
||||
}
|
||||
|
||||
if (event.type == NSEventTypeKeyUp)
|
||||
{
|
||||
NSString* str = [event characters];
|
||||
NSUInteger len = [str length];
|
||||
for (NSUInteger i = 0; i < len; i++)
|
||||
{
|
||||
int c = [str characterAtIndex:i];
|
||||
int key = mapCharacterToKey(c);
|
||||
if (key != -1)
|
||||
io.KeysDown[key] = false;
|
||||
}
|
||||
return io.WantCaptureKeyboard;
|
||||
}
|
||||
|
||||
if (event.type == NSEventTypeFlagsChanged)
|
||||
{
|
||||
unsigned int flags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
|
||||
|
||||
bool oldKeyCtrl = io.KeyCtrl;
|
||||
bool oldKeyShift = io.KeyShift;
|
||||
bool oldKeyAlt = io.KeyAlt;
|
||||
bool oldKeySuper = io.KeySuper;
|
||||
io.KeyCtrl = flags & NSEventModifierFlagControl;
|
||||
io.KeyShift = flags & NSEventModifierFlagShift;
|
||||
io.KeyAlt = flags & NSEventModifierFlagOption;
|
||||
io.KeySuper = flags & NSEventModifierFlagCommand;
|
||||
|
||||
// We must reset them as we will not receive any keyUp event if they where pressed with a modifier
|
||||
if ((oldKeyShift && !io.KeyShift) || (oldKeyCtrl && !io.KeyCtrl) || (oldKeyAlt && !io.KeyAlt) || (oldKeySuper && !io.KeySuper))
|
||||
resetKeys();
|
||||
return io.WantCaptureKeyboard;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
780
samples/external/Imgui/imgui-docking/backends/imgui_impl_sdl.cpp
vendored
Normal file
780
samples/external/Imgui/imgui-docking/backends/imgui_impl_sdl.cpp
vendored
Normal file
@@ -0,0 +1,780 @@
|
||||
// dear imgui: Platform Backend for SDL2
|
||||
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
|
||||
// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
|
||||
// (Prefer SDL 2.0.5+ for full feature support.)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// [X] Platform: Clipboard support.
|
||||
// [X] Platform: Keyboard arrays indexed using SDL_SCANCODE_* codes, e.g. ImGui::IsKeyPressed(SDL_SCANCODE_SPACE).
|
||||
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
// Missing features:
|
||||
// [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME.
|
||||
// [ ] Platform: Multi-viewport + Minimized windows seems to break mouse wheel events (at least under Windows).
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
|
||||
// 2021-08-17: Calling io.AddFocusEvent() on SDL_WINDOWEVENT_FOCUS_GAINED/SDL_WINDOWEVENT_FOCUS_LOST.
|
||||
// 2021-07-29: Inputs: MousePos is correctly reported when the host platform window is hovered but not focused (using SDL_GetMouseFocus() + SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, requires SDL 2.0.5+)
|
||||
// 2021-06:29: *BREAKING CHANGE* Removed 'SDL_Window* window' parameter to ImGui_ImplSDL2_NewFrame() which was unnecessary.
|
||||
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||
// 2021-03-22: Rework global mouse pos availability check listing supported platforms explicitly, effectively fixing mouse access on Raspberry Pi. (#2837, #3950)
|
||||
// 2020-05-25: Misc: Report a zero display-size when window is minimized, to be consistent with other backends.
|
||||
// 2020-02-20: Inputs: Fixed mapping for ImGuiKey_KeyPadEnter (using SDL_SCANCODE_KP_ENTER instead of SDL_SCANCODE_RETURN2).
|
||||
// 2019-12-17: Inputs: On Wayland, use SDL_GetMouseState (because there is no global mouse state).
|
||||
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
|
||||
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
|
||||
// 2019-04-23: Inputs: Added support for SDL_GameController (if ImGuiConfigFlags_NavEnableGamepad is set by user application).
|
||||
// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
|
||||
// 2018-12-21: Inputs: Workaround for Android/iOS which don't seem to handle focus related calls.
|
||||
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
|
||||
// 2018-11-14: Changed the signature of ImGui_ImplSDL2_ProcessEvent() to take a 'const SDL_Event*'.
|
||||
// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
|
||||
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
|
||||
// 2018-06-08: Misc: Extracted imgui_impl_sdl.cpp/.h away from the old combined SDL2+OpenGL/Vulkan examples.
|
||||
// 2018-06-08: Misc: ImGui_ImplSDL2_InitForOpenGL() now takes a SDL_GLContext parameter.
|
||||
// 2018-05-09: Misc: Fixed clipboard paste memory leak (we didn't call SDL_FreeMemory on the data returned by SDL_GetClipboardText).
|
||||
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
|
||||
// 2018-02-16: Inputs: Added support for mouse cursors, honoring ImGui::GetMouseCursor() value.
|
||||
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
|
||||
// 2018-02-05: Misc: Using SDL_GetPerformanceCounter() instead of SDL_GetTicks() to be able to handle very high framerate (1000+ FPS).
|
||||
// 2018-02-05: Inputs: Keyboard mapping is using scancodes everywhere instead of a confusing mixture of keycodes and scancodes.
|
||||
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
|
||||
// 2018-01-19: Inputs: When available (SDL 2.0.4+) using SDL_CaptureMouse() to retrieve coordinates outside of client area when dragging. Otherwise (SDL 2.0.3 and before) testing for SDL_WINDOW_INPUT_FOCUS instead of SDL_WINDOW_MOUSE_FOCUS.
|
||||
// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
|
||||
// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
|
||||
// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_sdl.h"
|
||||
|
||||
// SDL
|
||||
// (the multi-viewports feature requires SDL features supported from SDL 2.0.4+. SDL 2.0.5+ is highly recommended)
|
||||
#include <SDL.h>
|
||||
#include <SDL_syswm.h>
|
||||
#if defined(__APPLE__)
|
||||
#include <TargetConditionals.h>
|
||||
#endif
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2,0,4) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS)
|
||||
#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 1
|
||||
#else
|
||||
#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 0
|
||||
#endif
|
||||
#define SDL_HAS_MOUSE_FOCUS_CLICKTHROUGH SDL_VERSION_ATLEAST(2,0,5)
|
||||
#define SDL_HAS_WINDOW_ALPHA SDL_VERSION_ATLEAST(2,0,5)
|
||||
#define SDL_HAS_ALWAYS_ON_TOP SDL_VERSION_ATLEAST(2,0,5)
|
||||
#define SDL_HAS_USABLE_DISPLAY_BOUNDS SDL_VERSION_ATLEAST(2,0,5)
|
||||
#define SDL_HAS_PER_MONITOR_DPI SDL_VERSION_ATLEAST(2,0,4)
|
||||
#define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6)
|
||||
#if !SDL_HAS_VULKAN
|
||||
static const Uint32 SDL_WINDOW_VULKAN = 0x10000000;
|
||||
#endif
|
||||
|
||||
// SDL Data
|
||||
struct ImGui_ImplSDL2_Data
|
||||
{
|
||||
SDL_Window* Window;
|
||||
Uint64 Time;
|
||||
bool MousePressed[3];
|
||||
SDL_Cursor* MouseCursors[ImGuiMouseCursor_COUNT];
|
||||
char* ClipboardTextData;
|
||||
bool MouseCanUseGlobalState;
|
||||
bool UseVulkan;
|
||||
|
||||
ImGui_ImplSDL2_Data() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
|
||||
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||
// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
|
||||
// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
|
||||
static ImGui_ImplSDL2_Data* ImGui_ImplSDL2_GetBackendData()
|
||||
{
|
||||
return ImGui::GetCurrentContext() ? (ImGui_ImplSDL2_Data*)ImGui::GetIO().BackendPlatformUserData : NULL;
|
||||
}
|
||||
|
||||
// Forward Declarations
|
||||
static void ImGui_ImplSDL2_UpdateMonitors();
|
||||
static void ImGui_ImplSDL2_InitPlatformInterface(SDL_Window* window, void* sdl_gl_context);
|
||||
static void ImGui_ImplSDL2_ShutdownPlatformInterface();
|
||||
|
||||
// Functions
|
||||
static const char* ImGui_ImplSDL2_GetClipboardText(void*)
|
||||
{
|
||||
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||
if (bd->ClipboardTextData)
|
||||
SDL_free(bd->ClipboardTextData);
|
||||
bd->ClipboardTextData = SDL_GetClipboardText();
|
||||
return bd->ClipboardTextData;
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_SetClipboardText(void*, const char* text)
|
||||
{
|
||||
SDL_SetClipboardText(text);
|
||||
}
|
||||
|
||||
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
|
||||
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
|
||||
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
|
||||
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
|
||||
// If you have multiple SDL events and some of them are not meant to be used by dear imgui, you may need to filter events based on their windowID field.
|
||||
bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case SDL_MOUSEWHEEL:
|
||||
{
|
||||
if (event->wheel.x > 0) io.MouseWheelH += 1;
|
||||
if (event->wheel.x < 0) io.MouseWheelH -= 1;
|
||||
if (event->wheel.y > 0) io.MouseWheel += 1;
|
||||
if (event->wheel.y < 0) io.MouseWheel -= 1;
|
||||
return true;
|
||||
}
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
{
|
||||
if (event->button.button == SDL_BUTTON_LEFT) { bd->MousePressed[0] = true; }
|
||||
if (event->button.button == SDL_BUTTON_RIGHT) { bd->MousePressed[1] = true; }
|
||||
if (event->button.button == SDL_BUTTON_MIDDLE) { bd->MousePressed[2] = true; }
|
||||
return true;
|
||||
}
|
||||
case SDL_TEXTINPUT:
|
||||
{
|
||||
io.AddInputCharactersUTF8(event->text.text);
|
||||
return true;
|
||||
}
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
{
|
||||
int key = event->key.keysym.scancode;
|
||||
IM_ASSERT(key >= 0 && key < IM_ARRAYSIZE(io.KeysDown));
|
||||
io.KeysDown[key] = (event->type == SDL_KEYDOWN);
|
||||
io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0);
|
||||
io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0);
|
||||
io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0);
|
||||
#ifdef _WIN32
|
||||
io.KeySuper = false;
|
||||
#else
|
||||
io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
// Multi-viewport support
|
||||
case SDL_WINDOWEVENT:
|
||||
Uint8 window_event = event->window.event;
|
||||
if (window_event == SDL_WINDOWEVENT_CLOSE || window_event == SDL_WINDOWEVENT_MOVED || window_event == SDL_WINDOWEVENT_RESIZED || window_event == SDL_WINDOWEVENT_FOCUS_GAINED || window_event == SDL_WINDOWEVENT_FOCUS_LOST)
|
||||
if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)SDL_GetWindowFromID(event->window.windowID)))
|
||||
{
|
||||
if (window_event == SDL_WINDOWEVENT_CLOSE)
|
||||
viewport->PlatformRequestClose = true;
|
||||
if (window_event == SDL_WINDOWEVENT_MOVED)
|
||||
viewport->PlatformRequestMove = true;
|
||||
if (window_event == SDL_WINDOWEVENT_RESIZED)
|
||||
viewport->PlatformRequestResize = true;
|
||||
if (window_event == SDL_WINDOWEVENT_FOCUS_GAINED)
|
||||
io.AddFocusEvent(true);
|
||||
else if (window_event == SDL_WINDOWEVENT_FOCUS_LOST)
|
||||
io.AddFocusEvent(false);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ImGui_ImplSDL2_Init(SDL_Window* window, void* sdl_gl_context)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IM_ASSERT(io.BackendPlatformUserData == NULL && "Already initialized a platform backend!");
|
||||
|
||||
// Check and store if we are on a SDL backend that supports global mouse position
|
||||
// ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list)
|
||||
bool mouse_can_use_global_state = false;
|
||||
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
|
||||
const char* sdl_backend = SDL_GetCurrentVideoDriver();
|
||||
const char* global_mouse_whitelist[] = { "windows", "cocoa", "x11", "DIVE", "VMAN" };
|
||||
for (int n = 0; n < IM_ARRAYSIZE(global_mouse_whitelist); n++)
|
||||
if (strncmp(sdl_backend, global_mouse_whitelist[n], strlen(global_mouse_whitelist[n])) == 0)
|
||||
mouse_can_use_global_state = true;
|
||||
#endif
|
||||
|
||||
// Setup backend capabilities flags
|
||||
ImGui_ImplSDL2_Data* bd = IM_NEW(ImGui_ImplSDL2_Data)();
|
||||
io.BackendPlatformUserData = (void*)bd;
|
||||
io.BackendPlatformName = "imgui_impl_sdl";
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||
if (mouse_can_use_global_state)
|
||||
io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
|
||||
|
||||
bd->Window = window;
|
||||
bd->MouseCanUseGlobalState = mouse_can_use_global_state;
|
||||
|
||||
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
|
||||
io.KeyMap[ImGuiKey_Tab] = SDL_SCANCODE_TAB;
|
||||
io.KeyMap[ImGuiKey_LeftArrow] = SDL_SCANCODE_LEFT;
|
||||
io.KeyMap[ImGuiKey_RightArrow] = SDL_SCANCODE_RIGHT;
|
||||
io.KeyMap[ImGuiKey_UpArrow] = SDL_SCANCODE_UP;
|
||||
io.KeyMap[ImGuiKey_DownArrow] = SDL_SCANCODE_DOWN;
|
||||
io.KeyMap[ImGuiKey_PageUp] = SDL_SCANCODE_PAGEUP;
|
||||
io.KeyMap[ImGuiKey_PageDown] = SDL_SCANCODE_PAGEDOWN;
|
||||
io.KeyMap[ImGuiKey_Home] = SDL_SCANCODE_HOME;
|
||||
io.KeyMap[ImGuiKey_End] = SDL_SCANCODE_END;
|
||||
io.KeyMap[ImGuiKey_Insert] = SDL_SCANCODE_INSERT;
|
||||
io.KeyMap[ImGuiKey_Delete] = SDL_SCANCODE_DELETE;
|
||||
io.KeyMap[ImGuiKey_Backspace] = SDL_SCANCODE_BACKSPACE;
|
||||
io.KeyMap[ImGuiKey_Space] = SDL_SCANCODE_SPACE;
|
||||
io.KeyMap[ImGuiKey_Enter] = SDL_SCANCODE_RETURN;
|
||||
io.KeyMap[ImGuiKey_Escape] = SDL_SCANCODE_ESCAPE;
|
||||
io.KeyMap[ImGuiKey_KeyPadEnter] = SDL_SCANCODE_KP_ENTER;
|
||||
io.KeyMap[ImGuiKey_A] = SDL_SCANCODE_A;
|
||||
io.KeyMap[ImGuiKey_C] = SDL_SCANCODE_C;
|
||||
io.KeyMap[ImGuiKey_V] = SDL_SCANCODE_V;
|
||||
io.KeyMap[ImGuiKey_X] = SDL_SCANCODE_X;
|
||||
io.KeyMap[ImGuiKey_Y] = SDL_SCANCODE_Y;
|
||||
io.KeyMap[ImGuiKey_Z] = SDL_SCANCODE_Z;
|
||||
|
||||
io.SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText;
|
||||
io.GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText;
|
||||
io.ClipboardUserData = NULL;
|
||||
|
||||
// Load mouse cursors
|
||||
bd->MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
|
||||
bd->MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
|
||||
bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL);
|
||||
bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS);
|
||||
bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE);
|
||||
bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW);
|
||||
bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE);
|
||||
bd->MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
|
||||
bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO);
|
||||
|
||||
// Our mouse update function expect PlatformHandle to be filled for the main viewport
|
||||
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
||||
main_viewport->PlatformHandle = (void*)window;
|
||||
#ifdef _WIN32
|
||||
SDL_SysWMinfo info;
|
||||
SDL_VERSION(&info.version);
|
||||
if (SDL_GetWindowWMInfo(window, &info))
|
||||
main_viewport->PlatformHandleRaw = info.info.win.window;
|
||||
#endif
|
||||
|
||||
// Set SDL hint to receive mouse click events on window focus, otherwise SDL doesn't emit the event.
|
||||
// Without this, when clicking to gain focus, our widgets wouldn't activate even though they showed as hovered.
|
||||
// (This is unfortunately a global SDL setting, so enabling it might have a side-effect on your application.
|
||||
// It is unlikely to make a difference, but if your app absolutely needs to ignore the initial on-focus click:
|
||||
// you can ignore SDL_MOUSEBUTTONDOWN events coming right after a SDL_WINDOWEVENT_FOCUS_GAINED)
|
||||
#if SDL_HAS_MOUSE_FOCUS_CLICKTHROUGH
|
||||
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
|
||||
#endif
|
||||
|
||||
// Update monitors
|
||||
ImGui_ImplSDL2_UpdateMonitors();
|
||||
|
||||
// We need SDL_CaptureMouse(), SDL_GetGlobalMouseState() from SDL 2.0.4+ to support multiple viewports.
|
||||
// We left the call to ImGui_ImplSDL2_InitPlatformInterface() outside of #ifdef to avoid unused-function warnings.
|
||||
if ((io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) && (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports))
|
||||
ImGui_ImplSDL2_InitPlatformInterface(window, sdl_gl_context);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context)
|
||||
{
|
||||
return ImGui_ImplSDL2_Init(window, sdl_gl_context);
|
||||
}
|
||||
|
||||
bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window)
|
||||
{
|
||||
#if !SDL_HAS_VULKAN
|
||||
IM_ASSERT(0 && "Unsupported");
|
||||
#endif
|
||||
if (!ImGui_ImplSDL2_Init(window, NULL))
|
||||
return false;
|
||||
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||
bd->UseVulkan = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window)
|
||||
{
|
||||
#if !defined(_WIN32)
|
||||
IM_ASSERT(0 && "Unsupported");
|
||||
#endif
|
||||
return ImGui_ImplSDL2_Init(window, NULL);
|
||||
}
|
||||
|
||||
bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window)
|
||||
{
|
||||
return ImGui_ImplSDL2_Init(window, NULL);
|
||||
}
|
||||
|
||||
bool ImGui_ImplSDL2_InitForSDLRenderer(SDL_Window* window)
|
||||
{
|
||||
return ImGui_ImplSDL2_Init(window, NULL);
|
||||
}
|
||||
|
||||
void ImGui_ImplSDL2_Shutdown()
|
||||
{
|
||||
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||
IM_ASSERT(bd != NULL && "No platform backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui_ImplSDL2_ShutdownPlatformInterface();
|
||||
|
||||
if (bd->ClipboardTextData)
|
||||
SDL_free(bd->ClipboardTextData);
|
||||
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
|
||||
SDL_FreeCursor(bd->MouseCursors[cursor_n]);
|
||||
|
||||
io.BackendPlatformName = NULL;
|
||||
io.BackendPlatformUserData = NULL;
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
// This code is incredibly messy because some of the functions we need for full viewport support are not available in SDL < 2.0.4.
|
||||
static void ImGui_ImplSDL2_UpdateMousePosAndButtons()
|
||||
{
|
||||
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImVec2 mouse_pos_prev = io.MousePos;
|
||||
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
||||
io.MouseHoveredViewport = 0;
|
||||
|
||||
// Update mouse buttons
|
||||
int mouse_x_local, mouse_y_local;
|
||||
Uint32 mouse_buttons = SDL_GetMouseState(&mouse_x_local, &mouse_y_local);
|
||||
io.MouseDown[0] = bd->MousePressed[0] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
|
||||
io.MouseDown[1] = bd->MousePressed[1] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
|
||||
io.MouseDown[2] = bd->MousePressed[2] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0;
|
||||
bd->MousePressed[0] = bd->MousePressed[1] = bd->MousePressed[2] = false;
|
||||
|
||||
// Obtain focused and hovered window. We forward mouse input when focused or when hovered (and no other window is capturing)
|
||||
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
|
||||
SDL_Window* focused_window = SDL_GetKeyboardFocus();
|
||||
SDL_Window* hovered_window = SDL_HAS_MOUSE_FOCUS_CLICKTHROUGH ? SDL_GetMouseFocus() : NULL; // This is better but is only reliably useful with SDL 2.0.5+ and SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH.
|
||||
SDL_Window* mouse_window = NULL;
|
||||
if (hovered_window && (bd->Window == hovered_window || ImGui::FindViewportByPlatformHandle((void*)hovered_window)))
|
||||
mouse_window = hovered_window;
|
||||
else if (focused_window && (bd->Window == focused_window || ImGui::FindViewportByPlatformHandle((void*)focused_window)))
|
||||
mouse_window = focused_window;
|
||||
|
||||
// SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger other operations outside
|
||||
SDL_CaptureMouse(ImGui::IsAnyMouseDown() ? SDL_TRUE : SDL_FALSE);
|
||||
#else
|
||||
// SDL 2.0.3 and non-windowed systems: single-viewport only
|
||||
SDL_Window* mouse_window = (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_INPUT_FOCUS) ? bd->Window : NULL;
|
||||
#endif
|
||||
|
||||
if (mouse_window == NULL)
|
||||
return;
|
||||
|
||||
// Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
|
||||
if (io.WantSetMousePos)
|
||||
{
|
||||
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
SDL_WarpMouseGlobal((int)mouse_pos_prev.x, (int)mouse_pos_prev.y);
|
||||
else
|
||||
#endif
|
||||
SDL_WarpMouseInWindow(bd->Window, (int)mouse_pos_prev.x, (int)mouse_pos_prev.y);
|
||||
}
|
||||
|
||||
// Set Dear ImGui mouse position from OS position + get buttons. (this is the common behavior)
|
||||
if (bd->MouseCanUseGlobalState)
|
||||
{
|
||||
int mouse_x_global, mouse_y_global;
|
||||
SDL_GetGlobalMouseState(&mouse_x_global, &mouse_y_global);
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
{
|
||||
// Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
|
||||
io.MousePos = ImVec2((float)mouse_x_global, (float)mouse_y_global);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Single-viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window)
|
||||
// Unlike local position obtained earlier this will be valid when straying out of bounds.
|
||||
int window_x, window_y;
|
||||
SDL_GetWindowPosition(mouse_window, &window_x, &window_y);
|
||||
io.MousePos = ImVec2((float)(mouse_x_global - window_x), (float)(mouse_y_global - window_y));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
io.MousePos = ImVec2((float)mouse_x_local, (float)mouse_y_local);
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_UpdateMouseCursor()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
|
||||
return;
|
||||
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||
|
||||
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
||||
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None)
|
||||
{
|
||||
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
||||
SDL_ShowCursor(SDL_FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Show OS mouse cursor
|
||||
SDL_SetCursor(bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]);
|
||||
SDL_ShowCursor(SDL_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_UpdateGamepads()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
memset(io.NavInputs, 0, sizeof(io.NavInputs));
|
||||
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
|
||||
return;
|
||||
|
||||
// Get gamepad
|
||||
SDL_GameController* game_controller = SDL_GameControllerOpen(0);
|
||||
if (!game_controller)
|
||||
{
|
||||
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
|
||||
return;
|
||||
}
|
||||
|
||||
// Update gamepad inputs
|
||||
#define MAP_BUTTON(NAV_NO, BUTTON_NO) { io.NavInputs[NAV_NO] = (SDL_GameControllerGetButton(game_controller, BUTTON_NO) != 0) ? 1.0f : 0.0f; }
|
||||
#define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float vn = (float)(SDL_GameControllerGetAxis(game_controller, AXIS_NO) - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; }
|
||||
const int thumb_dead_zone = 8000; // SDL_gamecontroller.h suggests using this value.
|
||||
MAP_BUTTON(ImGuiNavInput_Activate, SDL_CONTROLLER_BUTTON_A); // Cross / A
|
||||
MAP_BUTTON(ImGuiNavInput_Cancel, SDL_CONTROLLER_BUTTON_B); // Circle / B
|
||||
MAP_BUTTON(ImGuiNavInput_Menu, SDL_CONTROLLER_BUTTON_X); // Square / X
|
||||
MAP_BUTTON(ImGuiNavInput_Input, SDL_CONTROLLER_BUTTON_Y); // Triangle / Y
|
||||
MAP_BUTTON(ImGuiNavInput_DpadLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT); // D-Pad Left
|
||||
MAP_BUTTON(ImGuiNavInput_DpadRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT); // D-Pad Right
|
||||
MAP_BUTTON(ImGuiNavInput_DpadUp, SDL_CONTROLLER_BUTTON_DPAD_UP); // D-Pad Up
|
||||
MAP_BUTTON(ImGuiNavInput_DpadDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN); // D-Pad Down
|
||||
MAP_BUTTON(ImGuiNavInput_FocusPrev, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); // L1 / LB
|
||||
MAP_BUTTON(ImGuiNavInput_FocusNext, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); // R1 / RB
|
||||
MAP_BUTTON(ImGuiNavInput_TweakSlow, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); // L1 / LB
|
||||
MAP_BUTTON(ImGuiNavInput_TweakFast, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); // R1 / RB
|
||||
MAP_ANALOG(ImGuiNavInput_LStickLeft, SDL_CONTROLLER_AXIS_LEFTX, -thumb_dead_zone, -32768);
|
||||
MAP_ANALOG(ImGuiNavInput_LStickRight, SDL_CONTROLLER_AXIS_LEFTX, +thumb_dead_zone, +32767);
|
||||
MAP_ANALOG(ImGuiNavInput_LStickUp, SDL_CONTROLLER_AXIS_LEFTY, -thumb_dead_zone, -32767);
|
||||
MAP_ANALOG(ImGuiNavInput_LStickDown, SDL_CONTROLLER_AXIS_LEFTY, +thumb_dead_zone, +32767);
|
||||
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
|
||||
#undef MAP_BUTTON
|
||||
#undef MAP_ANALOG
|
||||
}
|
||||
|
||||
// FIXME-PLATFORM: SDL doesn't have an event to notify the application of display/monitor changes
|
||||
static void ImGui_ImplSDL2_UpdateMonitors()
|
||||
{
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Monitors.resize(0);
|
||||
int display_count = SDL_GetNumVideoDisplays();
|
||||
for (int n = 0; n < display_count; n++)
|
||||
{
|
||||
// Warning: the validity of monitor DPI information on Windows depends on the application DPI awareness settings, which generally needs to be set in the manifest or at runtime.
|
||||
ImGuiPlatformMonitor monitor;
|
||||
SDL_Rect r;
|
||||
SDL_GetDisplayBounds(n, &r);
|
||||
monitor.MainPos = monitor.WorkPos = ImVec2((float)r.x, (float)r.y);
|
||||
monitor.MainSize = monitor.WorkSize = ImVec2((float)r.w, (float)r.h);
|
||||
#if SDL_HAS_USABLE_DISPLAY_BOUNDS
|
||||
SDL_GetDisplayUsableBounds(n, &r);
|
||||
monitor.WorkPos = ImVec2((float)r.x, (float)r.y);
|
||||
monitor.WorkSize = ImVec2((float)r.w, (float)r.h);
|
||||
#endif
|
||||
#if SDL_HAS_PER_MONITOR_DPI
|
||||
float dpi = 0.0f;
|
||||
if (!SDL_GetDisplayDPI(n, &dpi, NULL, NULL))
|
||||
monitor.DpiScale = dpi / 96.0f;
|
||||
#endif
|
||||
platform_io.Monitors.push_back(monitor);
|
||||
}
|
||||
}
|
||||
|
||||
void ImGui_ImplSDL2_NewFrame()
|
||||
{
|
||||
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplSDL2_Init()?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
// Setup display size (every frame to accommodate for window resizing)
|
||||
int w, h;
|
||||
int display_w, display_h;
|
||||
SDL_GetWindowSize(bd->Window, &w, &h);
|
||||
if (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_MINIMIZED)
|
||||
w = h = 0;
|
||||
SDL_GL_GetDrawableSize(bd->Window, &display_w, &display_h);
|
||||
io.DisplaySize = ImVec2((float)w, (float)h);
|
||||
if (w > 0 && h > 0)
|
||||
io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);
|
||||
|
||||
// Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution)
|
||||
static Uint64 frequency = SDL_GetPerformanceFrequency();
|
||||
Uint64 current_time = SDL_GetPerformanceCounter();
|
||||
io.DeltaTime = bd->Time > 0 ? (float)((double)(current_time - bd->Time) / frequency) : (float)(1.0f / 60.0f);
|
||||
bd->Time = current_time;
|
||||
|
||||
ImGui_ImplSDL2_UpdateMousePosAndButtons();
|
||||
ImGui_ImplSDL2_UpdateMouseCursor();
|
||||
|
||||
// Update game controllers (if enabled and available)
|
||||
ImGui_ImplSDL2_UpdateGamepads();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
|
||||
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
|
||||
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Helper structure we store in the void* RenderUserData field of each ImGuiViewport to easily retrieve our backend data.
|
||||
struct ImGui_ImplSDL2_ViewportData
|
||||
{
|
||||
SDL_Window* Window;
|
||||
Uint32 WindowID;
|
||||
bool WindowOwned;
|
||||
SDL_GLContext GLContext;
|
||||
|
||||
ImGui_ImplSDL2_ViewportData() { Window = NULL; WindowID = 0; WindowOwned = false; GLContext = NULL; }
|
||||
~ImGui_ImplSDL2_ViewportData() { IM_ASSERT(Window == NULL && GLContext == NULL); }
|
||||
};
|
||||
|
||||
static void ImGui_ImplSDL2_CreateWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||
ImGui_ImplSDL2_ViewportData* vd = IM_NEW(ImGui_ImplSDL2_ViewportData)();
|
||||
viewport->PlatformUserData = vd;
|
||||
|
||||
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
||||
ImGui_ImplSDL2_ViewportData* main_viewport_data = (ImGui_ImplSDL2_ViewportData*)main_viewport->PlatformUserData;
|
||||
|
||||
// Share GL resources with main context
|
||||
bool use_opengl = (main_viewport_data->GLContext != NULL);
|
||||
SDL_GLContext backup_context = NULL;
|
||||
if (use_opengl)
|
||||
{
|
||||
backup_context = SDL_GL_GetCurrentContext();
|
||||
SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
|
||||
SDL_GL_MakeCurrent(main_viewport_data->Window, main_viewport_data->GLContext);
|
||||
}
|
||||
|
||||
Uint32 sdl_flags = 0;
|
||||
sdl_flags |= use_opengl ? SDL_WINDOW_OPENGL : (bd->UseVulkan ? SDL_WINDOW_VULKAN : 0);
|
||||
sdl_flags |= SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_ALLOW_HIGHDPI;
|
||||
sdl_flags |= SDL_WINDOW_HIDDEN;
|
||||
sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? SDL_WINDOW_BORDERLESS : 0;
|
||||
sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? 0 : SDL_WINDOW_RESIZABLE;
|
||||
#if !defined(_WIN32)
|
||||
// See SDL hack in ImGui_ImplSDL2_ShowWindow().
|
||||
sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon) ? SDL_WINDOW_SKIP_TASKBAR : 0;
|
||||
#endif
|
||||
#if SDL_HAS_ALWAYS_ON_TOP
|
||||
sdl_flags |= (viewport->Flags & ImGuiViewportFlags_TopMost) ? SDL_WINDOW_ALWAYS_ON_TOP : 0;
|
||||
#endif
|
||||
vd->Window = SDL_CreateWindow("No Title Yet", (int)viewport->Pos.x, (int)viewport->Pos.y, (int)viewport->Size.x, (int)viewport->Size.y, sdl_flags);
|
||||
vd->WindowOwned = true;
|
||||
if (use_opengl)
|
||||
{
|
||||
vd->GLContext = SDL_GL_CreateContext(vd->Window);
|
||||
SDL_GL_SetSwapInterval(0);
|
||||
}
|
||||
if (use_opengl && backup_context)
|
||||
SDL_GL_MakeCurrent(vd->Window, backup_context);
|
||||
|
||||
viewport->PlatformHandle = (void*)vd->Window;
|
||||
#if defined(_WIN32)
|
||||
SDL_SysWMinfo info;
|
||||
SDL_VERSION(&info.version);
|
||||
if (SDL_GetWindowWMInfo(vd->Window, &info))
|
||||
viewport->PlatformHandleRaw = info.info.win.window;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_DestroyWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
if (ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData)
|
||||
{
|
||||
if (vd->GLContext && vd->WindowOwned)
|
||||
SDL_GL_DeleteContext(vd->GLContext);
|
||||
if (vd->Window && vd->WindowOwned)
|
||||
SDL_DestroyWindow(vd->Window);
|
||||
vd->GLContext = NULL;
|
||||
vd->Window = NULL;
|
||||
IM_DELETE(vd);
|
||||
}
|
||||
viewport->PlatformUserData = viewport->PlatformHandle = NULL;
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_ShowWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
#if defined(_WIN32)
|
||||
HWND hwnd = (HWND)viewport->PlatformHandleRaw;
|
||||
|
||||
// SDL hack: Hide icon from task bar
|
||||
// Note: SDL 2.0.6+ has a SDL_WINDOW_SKIP_TASKBAR flag which is supported under Windows but the way it create the window breaks our seamless transition.
|
||||
if (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon)
|
||||
{
|
||||
LONG ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
|
||||
ex_style &= ~WS_EX_APPWINDOW;
|
||||
ex_style |= WS_EX_TOOLWINDOW;
|
||||
::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style);
|
||||
}
|
||||
|
||||
// SDL hack: SDL always activate/focus windows :/
|
||||
if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing)
|
||||
{
|
||||
::ShowWindow(hwnd, SW_SHOWNA);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
SDL_ShowWindow(vd->Window);
|
||||
}
|
||||
|
||||
static ImVec2 ImGui_ImplSDL2_GetWindowPos(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
int x = 0, y = 0;
|
||||
SDL_GetWindowPosition(vd->Window, &x, &y);
|
||||
return ImVec2((float)x, (float)y);
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos)
|
||||
{
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
SDL_SetWindowPosition(vd->Window, (int)pos.x, (int)pos.y);
|
||||
}
|
||||
|
||||
static ImVec2 ImGui_ImplSDL2_GetWindowSize(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
int w = 0, h = 0;
|
||||
SDL_GetWindowSize(vd->Window, &w, &h);
|
||||
return ImVec2((float)w, (float)h);
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
|
||||
{
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
SDL_SetWindowSize(vd->Window, (int)size.x, (int)size.y);
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_SetWindowTitle(ImGuiViewport* viewport, const char* title)
|
||||
{
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
SDL_SetWindowTitle(vd->Window, title);
|
||||
}
|
||||
|
||||
#if SDL_HAS_WINDOW_ALPHA
|
||||
static void ImGui_ImplSDL2_SetWindowAlpha(ImGuiViewport* viewport, float alpha)
|
||||
{
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
SDL_SetWindowOpacity(vd->Window, alpha);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ImGui_ImplSDL2_SetWindowFocus(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
SDL_RaiseWindow(vd->Window);
|
||||
}
|
||||
|
||||
static bool ImGui_ImplSDL2_GetWindowFocus(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
return (SDL_GetWindowFlags(vd->Window) & SDL_WINDOW_INPUT_FOCUS) != 0;
|
||||
}
|
||||
|
||||
static bool ImGui_ImplSDL2_GetWindowMinimized(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
return (SDL_GetWindowFlags(vd->Window) & SDL_WINDOW_MINIMIZED) != 0;
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_RenderWindow(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
if (vd->GLContext)
|
||||
SDL_GL_MakeCurrent(vd->Window, vd->GLContext);
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_SwapBuffers(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
if (vd->GLContext)
|
||||
{
|
||||
SDL_GL_MakeCurrent(vd->Window, vd->GLContext);
|
||||
SDL_GL_SwapWindow(vd->Window);
|
||||
}
|
||||
}
|
||||
|
||||
// Vulkan support (the Vulkan renderer needs to call a platform-side support function to create the surface)
|
||||
// SDL is graceful enough to _not_ need <vulkan/vulkan.h> so we can safely include this.
|
||||
#if SDL_HAS_VULKAN
|
||||
#include <SDL_vulkan.h>
|
||||
static int ImGui_ImplSDL2_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_instance, const void* vk_allocator, ImU64* out_vk_surface)
|
||||
{
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
(void)vk_allocator;
|
||||
SDL_bool ret = SDL_Vulkan_CreateSurface(vd->Window, (VkInstance)vk_instance, (VkSurfaceKHR*)out_vk_surface);
|
||||
return ret ? 0 : 1; // ret ? VK_SUCCESS : VK_NOT_READY
|
||||
}
|
||||
#endif // SDL_HAS_VULKAN
|
||||
|
||||
static void ImGui_ImplSDL2_InitPlatformInterface(SDL_Window* window, void* sdl_gl_context)
|
||||
{
|
||||
// Register platform interface (will be coupled with a renderer interface)
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Platform_CreateWindow = ImGui_ImplSDL2_CreateWindow;
|
||||
platform_io.Platform_DestroyWindow = ImGui_ImplSDL2_DestroyWindow;
|
||||
platform_io.Platform_ShowWindow = ImGui_ImplSDL2_ShowWindow;
|
||||
platform_io.Platform_SetWindowPos = ImGui_ImplSDL2_SetWindowPos;
|
||||
platform_io.Platform_GetWindowPos = ImGui_ImplSDL2_GetWindowPos;
|
||||
platform_io.Platform_SetWindowSize = ImGui_ImplSDL2_SetWindowSize;
|
||||
platform_io.Platform_GetWindowSize = ImGui_ImplSDL2_GetWindowSize;
|
||||
platform_io.Platform_SetWindowFocus = ImGui_ImplSDL2_SetWindowFocus;
|
||||
platform_io.Platform_GetWindowFocus = ImGui_ImplSDL2_GetWindowFocus;
|
||||
platform_io.Platform_GetWindowMinimized = ImGui_ImplSDL2_GetWindowMinimized;
|
||||
platform_io.Platform_SetWindowTitle = ImGui_ImplSDL2_SetWindowTitle;
|
||||
platform_io.Platform_RenderWindow = ImGui_ImplSDL2_RenderWindow;
|
||||
platform_io.Platform_SwapBuffers = ImGui_ImplSDL2_SwapBuffers;
|
||||
#if SDL_HAS_WINDOW_ALPHA
|
||||
platform_io.Platform_SetWindowAlpha = ImGui_ImplSDL2_SetWindowAlpha;
|
||||
#endif
|
||||
#if SDL_HAS_VULKAN
|
||||
platform_io.Platform_CreateVkSurface = ImGui_ImplSDL2_CreateVkSurface;
|
||||
#endif
|
||||
|
||||
// Register main window handle (which is owned by the main application, not by us)
|
||||
// This is mostly for simplicity and consistency, so that our code (e.g. mouse handling etc.) can use same logic for main and secondary viewports.
|
||||
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
||||
ImGui_ImplSDL2_ViewportData* vd = IM_NEW(ImGui_ImplSDL2_ViewportData)();
|
||||
vd->Window = window;
|
||||
vd->WindowID = SDL_GetWindowID(window);
|
||||
vd->WindowOwned = false;
|
||||
vd->GLContext = sdl_gl_context;
|
||||
main_viewport->PlatformUserData = vd;
|
||||
main_viewport->PlatformHandle = vd->Window;
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_ShutdownPlatformInterface()
|
||||
{
|
||||
ImGui::DestroyPlatformWindows();
|
||||
}
|
||||
37
samples/external/Imgui/imgui-docking/backends/imgui_impl_sdl.h
vendored
Normal file
37
samples/external/Imgui/imgui-docking/backends/imgui_impl_sdl.h
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
// dear imgui: Platform Backend for SDL2
|
||||
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
|
||||
// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// [X] Platform: Clipboard support.
|
||||
// [X] Platform: Keyboard arrays indexed using SDL_SCANCODE_* codes, e.g. ImGui::IsKeyPressed(SDL_SCANCODE_SPACE).
|
||||
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
// Missing features:
|
||||
// [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME.
|
||||
// [ ] Platform: Multi-viewport + Minimized windows seems to break mouse wheel events (at least under Windows).
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
struct SDL_Window;
|
||||
typedef union SDL_Event SDL_Event;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window);
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForSDLRenderer(SDL_Window* window);
|
||||
IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame();
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event);
|
||||
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
static inline void ImGui_ImplSDL2_NewFrame(SDL_Window*) { ImGui_ImplSDL2_NewFrame(); } // 1.84: removed unnecessary parameter
|
||||
#endif
|
||||
239
samples/external/Imgui/imgui-docking/backends/imgui_impl_sdlrenderer.cpp
vendored
Normal file
239
samples/external/Imgui/imgui-docking/backends/imgui_impl_sdlrenderer.cpp
vendored
Normal file
@@ -0,0 +1,239 @@
|
||||
// dear imgui: Renderer Backend for SDL_Renderer
|
||||
// (Requires: SDL 2.0.17+)
|
||||
|
||||
// Important to understand: SDL_Renderer is an _optional_ component of SDL. We do not recommend you use SDL_Renderer
|
||||
// because it provide a rather limited API to the end-user. We provide this backend for the sake of completeness.
|
||||
// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX.
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// Missing features:
|
||||
// [ ] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
// [ ] Renderer: Multi-viewport support (multiple windows).
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// CHANGELOG
|
||||
// 2021-10-06: Backup and restore modified ClipRect/Viewport.
|
||||
// 2021-09-21: Initial version.
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_sdlrenderer.h"
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
|
||||
#include <stddef.h> // intptr_t
|
||||
#else
|
||||
#include <stdint.h> // intptr_t
|
||||
#endif
|
||||
|
||||
// SDL
|
||||
#include <SDL.h>
|
||||
#if !SDL_VERSION_ATLEAST(2,0,17)
|
||||
#error This backend requires SDL 2.0.17+ because of SDL_RenderGeometry() function
|
||||
#endif
|
||||
|
||||
// SDL_Renderer data
|
||||
struct ImGui_ImplSDLRenderer_Data
|
||||
{
|
||||
SDL_Renderer* SDLRenderer;
|
||||
SDL_Texture* FontTexture;
|
||||
ImGui_ImplSDLRenderer_Data() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||
static ImGui_ImplSDLRenderer_Data* ImGui_ImplSDLRenderer_GetBackendData()
|
||||
{
|
||||
return ImGui::GetCurrentContext() ? (ImGui_ImplSDLRenderer_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
|
||||
}
|
||||
|
||||
// Functions
|
||||
bool ImGui_ImplSDLRenderer_Init(SDL_Renderer* renderer)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
|
||||
IM_ASSERT(renderer != NULL && "SDL_Renderer not initialized!");
|
||||
|
||||
// Setup backend capabilities flags
|
||||
ImGui_ImplSDLRenderer_Data* bd = IM_NEW(ImGui_ImplSDLRenderer_Data)();
|
||||
io.BackendRendererUserData = (void*)bd;
|
||||
io.BackendRendererName = "imgui_impl_sdlrenderer";
|
||||
|
||||
bd->SDLRenderer = renderer;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplSDLRenderer_Shutdown()
|
||||
{
|
||||
ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData();
|
||||
IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui_ImplSDLRenderer_DestroyDeviceObjects();
|
||||
|
||||
io.BackendRendererName = NULL;
|
||||
io.BackendRendererUserData = NULL;
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDLRenderer_SetupRenderState()
|
||||
{
|
||||
ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData();
|
||||
|
||||
// Clear out any viewports and cliprect set by the user
|
||||
// FIXME: Technically speaking there are lots of other things we could backup/setup/restore during our render process.
|
||||
SDL_RenderSetViewport(bd->SDLRenderer, NULL);
|
||||
SDL_RenderSetClipRect(bd->SDLRenderer, NULL);
|
||||
}
|
||||
|
||||
void ImGui_ImplSDLRenderer_NewFrame()
|
||||
{
|
||||
ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData();
|
||||
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplSDLRenderer_Init()?");
|
||||
|
||||
if (!bd->FontTexture)
|
||||
ImGui_ImplSDLRenderer_CreateDeviceObjects();
|
||||
}
|
||||
|
||||
void ImGui_ImplSDLRenderer_RenderDrawData(ImDrawData* draw_data)
|
||||
{
|
||||
ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData();
|
||||
|
||||
// If there's a scale factor set by the user, use that instead
|
||||
// If the user has specified a scale factor to SDL_Renderer already via SDL_RenderSetScale(), SDL will scale whatever we pass
|
||||
// to SDL_RenderGeometryRaw() by that scale factor. In that case we don't want to be also scaling it ourselves here.
|
||||
float rsx = 1.0f;
|
||||
float rsy = 1.0f;
|
||||
SDL_RenderGetScale(bd->SDLRenderer, &rsx, &rsy);
|
||||
ImVec2 render_scale;
|
||||
render_scale.x = (rsx == 1.0f) ? draw_data->FramebufferScale.x : 1.0f;
|
||||
render_scale.y = (rsy == 1.0f) ? draw_data->FramebufferScale.y : 1.0f;
|
||||
|
||||
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||
int fb_width = (int)(draw_data->DisplaySize.x * render_scale.x);
|
||||
int fb_height = (int)(draw_data->DisplaySize.y * render_scale.y);
|
||||
if (fb_width == 0 || fb_height == 0)
|
||||
return;
|
||||
|
||||
// Backup SDL_Renderer state that will be modified to restore it afterwards
|
||||
struct BackupSDLRendererState
|
||||
{
|
||||
SDL_Rect Viewport;
|
||||
bool ClipEnabled;
|
||||
SDL_Rect ClipRect;
|
||||
};
|
||||
BackupSDLRendererState old = {};
|
||||
old.ClipEnabled = SDL_RenderIsClipEnabled(bd->SDLRenderer);
|
||||
SDL_RenderGetViewport(bd->SDLRenderer, &old.Viewport);
|
||||
SDL_RenderGetClipRect(bd->SDLRenderer, &old.ClipRect);
|
||||
|
||||
// Will project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
|
||||
ImVec2 clip_scale = render_scale;
|
||||
|
||||
// Render command lists
|
||||
ImGui_ImplSDLRenderer_SetupRenderState();
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data;
|
||||
const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;
|
||||
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||
if (pcmd->UserCallback)
|
||||
{
|
||||
// User callback, registered via ImDrawList::AddCallback()
|
||||
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||
ImGui_ImplSDLRenderer_SetupRenderState();
|
||||
else
|
||||
pcmd->UserCallback(cmd_list, pcmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
|
||||
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
|
||||
if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
|
||||
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
|
||||
if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }
|
||||
if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }
|
||||
if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
|
||||
continue;
|
||||
|
||||
SDL_Rect r = { (int)(clip_min.x), (int)(clip_min.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y) };
|
||||
SDL_RenderSetClipRect(bd->SDLRenderer, &r);
|
||||
|
||||
const float* xy = (const float*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, pos));
|
||||
const float* uv = (const float*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, uv));
|
||||
const int* color = (const int*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, col));
|
||||
|
||||
// Bind texture, Draw
|
||||
SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID();
|
||||
SDL_RenderGeometryRaw(bd->SDLRenderer, tex,
|
||||
xy, (int)sizeof(ImDrawVert),
|
||||
color, (int)sizeof(ImDrawVert),
|
||||
uv, (int)sizeof(ImDrawVert),
|
||||
cmd_list->VtxBuffer.Size,
|
||||
idx_buffer + pcmd->IdxOffset, pcmd->ElemCount, sizeof(ImDrawIdx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Restore modified SDL_Renderer state
|
||||
SDL_RenderSetViewport(bd->SDLRenderer, &old.Viewport);
|
||||
SDL_RenderSetClipRect(bd->SDLRenderer, old.ClipEnabled ? &old.ClipRect : NULL);
|
||||
}
|
||||
|
||||
// Called by Init/NewFrame/Shutdown
|
||||
bool ImGui_ImplSDLRenderer_CreateFontsTexture()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData();
|
||||
|
||||
// Build texture atlas
|
||||
unsigned char* pixels;
|
||||
int width, height;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
|
||||
|
||||
// Upload texture to graphics system
|
||||
bd->FontTexture = SDL_CreateTexture(bd->SDLRenderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, width, height);
|
||||
if (bd->FontTexture == NULL)
|
||||
{
|
||||
SDL_Log("error creating texture");
|
||||
return false;
|
||||
}
|
||||
SDL_UpdateTexture(bd->FontTexture, NULL, pixels, 4 * width);
|
||||
SDL_SetTextureBlendMode(bd->FontTexture, SDL_BLENDMODE_BLEND);
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplSDLRenderer_DestroyFontsTexture()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData();
|
||||
if (bd->FontTexture)
|
||||
{
|
||||
io.Fonts->SetTexID(0);
|
||||
SDL_DestroyTexture(bd->FontTexture);
|
||||
bd->FontTexture = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool ImGui_ImplSDLRenderer_CreateDeviceObjects()
|
||||
{
|
||||
return ImGui_ImplSDLRenderer_CreateFontsTexture();
|
||||
}
|
||||
|
||||
void ImGui_ImplSDLRenderer_DestroyDeviceObjects()
|
||||
{
|
||||
ImGui_ImplSDLRenderer_DestroyFontsTexture();
|
||||
}
|
||||
28
samples/external/Imgui/imgui-docking/backends/imgui_impl_sdlrenderer.h
vendored
Normal file
28
samples/external/Imgui/imgui-docking/backends/imgui_impl_sdlrenderer.h
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
// dear imgui: Renderer Backend for SDL_Renderer
|
||||
// (Requires: SDL 2.0.17+)
|
||||
|
||||
// Important to understand: SDL_Renderer is an _optional_ component of SDL. We do not recommend you use SDL_Renderer
|
||||
// because it provide a rather limited API to the end-user. We provide this backend for the sake of completeness.
|
||||
// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX.
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// Missing features:
|
||||
// [ ] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
// [ ] Renderer: Multi-viewport support (multiple windows).
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
struct SDL_Renderer;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer_Init(SDL_Renderer* renderer);
|
||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer_NewFrame();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer_RenderDrawData(ImDrawData* draw_data);
|
||||
|
||||
// Called by Init/NewFrame/Shutdown
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer_CreateFontsTexture();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer_DestroyFontsTexture();
|
||||
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer_CreateDeviceObjects();
|
||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer_DestroyDeviceObjects();
|
||||
1715
samples/external/Imgui/imgui-docking/backends/imgui_impl_vulkan.cpp
vendored
Normal file
1715
samples/external/Imgui/imgui-docking/backends/imgui_impl_vulkan.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
150
samples/external/Imgui/imgui-docking/backends/imgui_impl_vulkan.h
vendored
Normal file
150
samples/external/Imgui/imgui-docking/backends/imgui_impl_vulkan.h
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
// dear imgui: Renderer Backend for Vulkan
|
||||
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
// Missing features:
|
||||
// [ ] Platform: Multi-viewport / platform windows.
|
||||
// [ ] Renderer: User texture binding. Changes of ImTextureID aren't supported by this backend! See https://github.com/ocornut/imgui/pull/914
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
|
||||
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
|
||||
|
||||
// Important note to the reader who wish to integrate imgui_impl_vulkan.cpp/.h in their own engine/app.
|
||||
// - Common ImGui_ImplVulkan_XXX functions and structures are used to interface with imgui_impl_vulkan.cpp/.h.
|
||||
// You will use those if you want to use this rendering backend in your engine/app.
|
||||
// - Helper ImGui_ImplVulkanH_XXX functions and structures are only used by this example (main.cpp) and by
|
||||
// the backend itself (imgui_impl_vulkan.cpp), but should PROBABLY NOT be used by your own engine/app code.
|
||||
// Read comments in imgui_impl_vulkan.h.
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
// [Configuration] in order to use a custom Vulkan function loader:
|
||||
// (1) You'll need to disable default Vulkan function prototypes.
|
||||
// We provide a '#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES' convenience configuration flag.
|
||||
// In order to make sure this is visible from the imgui_impl_vulkan.cpp compilation unit:
|
||||
// - Add '#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES' in your imconfig.h file
|
||||
// - Or as a compilation flag in your build system
|
||||
// - Or uncomment here (not recommended because you'd be modifying imgui sources!)
|
||||
// - Do not simply add it in a .cpp file!
|
||||
// (2) Call ImGui_ImplVulkan_LoadFunctions() before ImGui_ImplVulkan_Init() with your custom function.
|
||||
// If you have no idea what this is, leave it alone!
|
||||
//#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES
|
||||
|
||||
// Vulkan includes
|
||||
#if defined(IMGUI_IMPL_VULKAN_NO_PROTOTYPES) && !defined(VK_NO_PROTOTYPES)
|
||||
#define VK_NO_PROTOTYPES
|
||||
#endif
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
// Initialization data, for ImGui_ImplVulkan_Init()
|
||||
// [Please zero-clear before use!]
|
||||
struct ImGui_ImplVulkan_InitInfo
|
||||
{
|
||||
VkInstance Instance;
|
||||
VkPhysicalDevice PhysicalDevice;
|
||||
VkDevice Device;
|
||||
uint32_t QueueFamily;
|
||||
VkQueue Queue;
|
||||
VkPipelineCache PipelineCache;
|
||||
VkDescriptorPool DescriptorPool;
|
||||
uint32_t Subpass;
|
||||
uint32_t MinImageCount; // >= 2
|
||||
uint32_t ImageCount; // >= MinImageCount
|
||||
VkSampleCountFlagBits MSAASamples; // >= VK_SAMPLE_COUNT_1_BIT
|
||||
const VkAllocationCallbacks* Allocator;
|
||||
void (*CheckVkResultFn)(VkResult err);
|
||||
};
|
||||
|
||||
// Called by user code
|
||||
IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass);
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame();
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline = VK_NULL_HANDLE);
|
||||
IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer);
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontUploadObjects();
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated)
|
||||
|
||||
// Optional: load Vulkan functions with a custom function loader
|
||||
// This is only useful with IMGUI_IMPL_VULKAN_NO_PROTOTYPES / VK_NO_PROTOTYPES
|
||||
IMGUI_IMPL_API bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data = NULL);
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Internal / Miscellaneous Vulkan Helpers
|
||||
// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own engine/app.)
|
||||
//-------------------------------------------------------------------------
|
||||
// You probably do NOT need to use or care about those functions.
|
||||
// Those functions only exist because:
|
||||
// 1) they facilitate the readability and maintenance of the multiple main.cpp examples files.
|
||||
// 2) the multi-viewport / platform window implementation needs them internally.
|
||||
// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,
|
||||
// but it is too much code to duplicate everywhere so we exceptionally expose them.
|
||||
//
|
||||
// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
|
||||
// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.
|
||||
// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
struct ImGui_ImplVulkanH_Frame;
|
||||
struct ImGui_ImplVulkanH_Window;
|
||||
|
||||
// Helpers
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateOrResizeWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wnd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wnd, const VkAllocationCallbacks* allocator);
|
||||
IMGUI_IMPL_API VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space);
|
||||
IMGUI_IMPL_API VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count);
|
||||
IMGUI_IMPL_API int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode);
|
||||
|
||||
// Helper structure to hold the data needed by one rendering frame
|
||||
// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
|
||||
// [Please zero-clear before use!]
|
||||
struct ImGui_ImplVulkanH_Frame
|
||||
{
|
||||
VkCommandPool CommandPool;
|
||||
VkCommandBuffer CommandBuffer;
|
||||
VkFence Fence;
|
||||
VkImage Backbuffer;
|
||||
VkImageView BackbufferView;
|
||||
VkFramebuffer Framebuffer;
|
||||
};
|
||||
|
||||
struct ImGui_ImplVulkanH_FrameSemaphores
|
||||
{
|
||||
VkSemaphore ImageAcquiredSemaphore;
|
||||
VkSemaphore RenderCompleteSemaphore;
|
||||
};
|
||||
|
||||
// Helper structure to hold the data needed by one rendering context into one OS window
|
||||
// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
|
||||
struct ImGui_ImplVulkanH_Window
|
||||
{
|
||||
int Width;
|
||||
int Height;
|
||||
VkSwapchainKHR Swapchain;
|
||||
VkSurfaceKHR Surface;
|
||||
VkSurfaceFormatKHR SurfaceFormat;
|
||||
VkPresentModeKHR PresentMode;
|
||||
VkRenderPass RenderPass;
|
||||
VkPipeline Pipeline; // The window pipeline may uses a different VkRenderPass than the one passed in ImGui_ImplVulkan_InitInfo
|
||||
bool ClearEnable;
|
||||
VkClearValue ClearValue;
|
||||
uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount)
|
||||
uint32_t ImageCount; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count)
|
||||
uint32_t SemaphoreIndex; // Current set of swapchain wait semaphores we're using (needs to be distinct from per frame data)
|
||||
ImGui_ImplVulkanH_Frame* Frames;
|
||||
ImGui_ImplVulkanH_FrameSemaphores* FrameSemaphores;
|
||||
|
||||
ImGui_ImplVulkanH_Window()
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
PresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR;
|
||||
ClearEnable = true;
|
||||
}
|
||||
};
|
||||
|
||||
717
samples/external/Imgui/imgui-docking/backends/imgui_impl_wgpu.cpp
vendored
Normal file
717
samples/external/Imgui/imgui-docking/backends/imgui_impl_wgpu.cpp
vendored
Normal file
@@ -0,0 +1,717 @@
|
||||
// dear imgui: Renderer for WebGPU
|
||||
// This needs to be used along with a Platform Binding (e.g. GLFW)
|
||||
// (Please note that WebGPU is currently experimental, will not run on non-beta browsers, and may break.)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2021-08-24: Fix for latest specs.
|
||||
// 2021-05-24: Add support for draw_data->FramebufferScale.
|
||||
// 2021-05-19: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||
// 2021-05-16: Update to latest WebGPU specs (compatible with Emscripten 2.0.20 and Chrome Canary 92).
|
||||
// 2021-02-18: Change blending equation to preserve alpha in output buffer.
|
||||
// 2021-01-28: Initial version.
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_wgpu.h"
|
||||
#include <limits.h>
|
||||
#include <webgpu/webgpu.h>
|
||||
|
||||
#define HAS_EMSCRIPTEN_VERSION(major, minor, tiny) (__EMSCRIPTEN_major__ > (major) || (__EMSCRIPTEN_major__ == (major) && __EMSCRIPTEN_minor__ > (minor)) || (__EMSCRIPTEN_major__ == (major) && __EMSCRIPTEN_minor__ == (minor) && __EMSCRIPTEN_tiny__ >= (tiny)))
|
||||
|
||||
#if defined(__EMSCRIPTEN__) && !HAS_EMSCRIPTEN_VERSION(2, 0, 20)
|
||||
#error "Requires at least emscripten 2.0.20"
|
||||
#endif
|
||||
|
||||
// Dear ImGui prototypes from imgui_internal.h
|
||||
extern ImGuiID ImHashData(const void* data_p, size_t data_size, ImU32 seed = 0);
|
||||
|
||||
// WebGPU data
|
||||
static WGPUDevice g_wgpuDevice = NULL;
|
||||
static WGPUQueue g_defaultQueue = NULL;
|
||||
static WGPUTextureFormat g_renderTargetFormat = WGPUTextureFormat_Undefined;
|
||||
static WGPURenderPipeline g_pipelineState = NULL;
|
||||
|
||||
struct RenderResources
|
||||
{
|
||||
WGPUTexture FontTexture; // Font texture
|
||||
WGPUTextureView FontTextureView; // Texture view for font texture
|
||||
WGPUSampler Sampler; // Sampler for the font texture
|
||||
WGPUBuffer Uniforms; // Shader uniforms
|
||||
WGPUBindGroup CommonBindGroup; // Resources bind-group to bind the common resources to pipeline
|
||||
ImGuiStorage ImageBindGroups; // Resources bind-group to bind the font/image resources to pipeline (this is a key->value map)
|
||||
WGPUBindGroup ImageBindGroup; // Default font-resource of Dear ImGui
|
||||
WGPUBindGroupLayout ImageBindGroupLayout; // Cache layout used for the image bind group. Avoids allocating unnecessary JS objects when working with WebASM
|
||||
};
|
||||
static RenderResources g_resources;
|
||||
|
||||
struct FrameResources
|
||||
{
|
||||
WGPUBuffer IndexBuffer;
|
||||
WGPUBuffer VertexBuffer;
|
||||
ImDrawIdx* IndexBufferHost;
|
||||
ImDrawVert* VertexBufferHost;
|
||||
int IndexBufferSize;
|
||||
int VertexBufferSize;
|
||||
};
|
||||
static FrameResources* g_pFrameResources = NULL;
|
||||
static unsigned int g_numFramesInFlight = 0;
|
||||
static unsigned int g_frameIndex = UINT_MAX;
|
||||
|
||||
struct Uniforms
|
||||
{
|
||||
float MVP[4][4];
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SHADERS
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// glsl_shader.vert, compiled with:
|
||||
// # glslangValidator -V -x -o glsl_shader.vert.u32 glsl_shader.vert
|
||||
/*
|
||||
#version 450 core
|
||||
layout(location = 0) in vec2 aPos;
|
||||
layout(location = 1) in vec2 aUV;
|
||||
layout(location = 2) in vec4 aColor;
|
||||
layout(set=0, binding = 0) uniform transform { mat4 mvp; };
|
||||
|
||||
out gl_PerVertex { vec4 gl_Position; };
|
||||
layout(location = 0) out struct { vec4 Color; vec2 UV; } Out;
|
||||
|
||||
void main()
|
||||
{
|
||||
Out.Color = aColor;
|
||||
Out.UV = aUV;
|
||||
gl_Position = mvp * vec4(aPos, 0, 1);
|
||||
}
|
||||
*/
|
||||
static uint32_t __glsl_shader_vert_spv[] =
|
||||
{
|
||||
0x07230203,0x00010000,0x00080007,0x0000002c,0x00000000,0x00020011,0x00000001,0x0006000b,
|
||||
0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
|
||||
0x000a000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000b,0x0000000f,0x00000015,
|
||||
0x0000001b,0x00000023,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d,
|
||||
0x00000000,0x00030005,0x00000009,0x00000000,0x00050006,0x00000009,0x00000000,0x6f6c6f43,
|
||||
0x00000072,0x00040006,0x00000009,0x00000001,0x00005655,0x00030005,0x0000000b,0x0074754f,
|
||||
0x00040005,0x0000000f,0x6c6f4361,0x0000726f,0x00030005,0x00000015,0x00565561,0x00060005,
|
||||
0x00000019,0x505f6c67,0x65567265,0x78657472,0x00000000,0x00060006,0x00000019,0x00000000,
|
||||
0x505f6c67,0x7469736f,0x006e6f69,0x00030005,0x0000001b,0x00000000,0x00050005,0x0000001d,
|
||||
0x6e617274,0x726f6673,0x0000006d,0x00040006,0x0000001d,0x00000000,0x0070766d,0x00030005,
|
||||
0x0000001f,0x00000000,0x00040005,0x00000023,0x736f5061,0x00000000,0x00040047,0x0000000b,
|
||||
0x0000001e,0x00000000,0x00040047,0x0000000f,0x0000001e,0x00000002,0x00040047,0x00000015,
|
||||
0x0000001e,0x00000001,0x00050048,0x00000019,0x00000000,0x0000000b,0x00000000,0x00030047,
|
||||
0x00000019,0x00000002,0x00040048,0x0000001d,0x00000000,0x00000005,0x00050048,0x0000001d,
|
||||
0x00000000,0x00000023,0x00000000,0x00050048,0x0000001d,0x00000000,0x00000007,0x00000010,
|
||||
0x00030047,0x0000001d,0x00000002,0x00040047,0x0000001f,0x00000022,0x00000000,0x00040047,
|
||||
0x0000001f,0x00000021,0x00000000,0x00040047,0x00000023,0x0000001e,0x00000000,0x00020013,
|
||||
0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,0x00000020,0x00040017,
|
||||
0x00000007,0x00000006,0x00000004,0x00040017,0x00000008,0x00000006,0x00000002,0x0004001e,
|
||||
0x00000009,0x00000007,0x00000008,0x00040020,0x0000000a,0x00000003,0x00000009,0x0004003b,
|
||||
0x0000000a,0x0000000b,0x00000003,0x00040015,0x0000000c,0x00000020,0x00000001,0x0004002b,
|
||||
0x0000000c,0x0000000d,0x00000000,0x00040020,0x0000000e,0x00000001,0x00000007,0x0004003b,
|
||||
0x0000000e,0x0000000f,0x00000001,0x00040020,0x00000011,0x00000003,0x00000007,0x0004002b,
|
||||
0x0000000c,0x00000013,0x00000001,0x00040020,0x00000014,0x00000001,0x00000008,0x0004003b,
|
||||
0x00000014,0x00000015,0x00000001,0x00040020,0x00000017,0x00000003,0x00000008,0x0003001e,
|
||||
0x00000019,0x00000007,0x00040020,0x0000001a,0x00000003,0x00000019,0x0004003b,0x0000001a,
|
||||
0x0000001b,0x00000003,0x00040018,0x0000001c,0x00000007,0x00000004,0x0003001e,0x0000001d,
|
||||
0x0000001c,0x00040020,0x0000001e,0x00000002,0x0000001d,0x0004003b,0x0000001e,0x0000001f,
|
||||
0x00000002,0x00040020,0x00000020,0x00000002,0x0000001c,0x0004003b,0x00000014,0x00000023,
|
||||
0x00000001,0x0004002b,0x00000006,0x00000025,0x00000000,0x0004002b,0x00000006,0x00000026,
|
||||
0x3f800000,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,
|
||||
0x0004003d,0x00000007,0x00000010,0x0000000f,0x00050041,0x00000011,0x00000012,0x0000000b,
|
||||
0x0000000d,0x0003003e,0x00000012,0x00000010,0x0004003d,0x00000008,0x00000016,0x00000015,
|
||||
0x00050041,0x00000017,0x00000018,0x0000000b,0x00000013,0x0003003e,0x00000018,0x00000016,
|
||||
0x00050041,0x00000020,0x00000021,0x0000001f,0x0000000d,0x0004003d,0x0000001c,0x00000022,
|
||||
0x00000021,0x0004003d,0x00000008,0x00000024,0x00000023,0x00050051,0x00000006,0x00000027,
|
||||
0x00000024,0x00000000,0x00050051,0x00000006,0x00000028,0x00000024,0x00000001,0x00070050,
|
||||
0x00000007,0x00000029,0x00000027,0x00000028,0x00000025,0x00000026,0x00050091,0x00000007,
|
||||
0x0000002a,0x00000022,0x00000029,0x00050041,0x00000011,0x0000002b,0x0000001b,0x0000000d,
|
||||
0x0003003e,0x0000002b,0x0000002a,0x000100fd,0x00010038
|
||||
};
|
||||
|
||||
// glsl_shader.frag, compiled with:
|
||||
// # glslangValidator -V -x -o glsl_shader.frag.u32 glsl_shader.frag
|
||||
/*
|
||||
#version 450 core
|
||||
layout(location = 0) out vec4 fColor;
|
||||
layout(set=0, binding=1) uniform sampler s;
|
||||
layout(set=1, binding=0) uniform texture2D t;
|
||||
layout(location = 0) in struct { vec4 Color; vec2 UV; } In;
|
||||
void main()
|
||||
{
|
||||
fColor = In.Color * texture(sampler2D(t, s), In.UV.st);
|
||||
}
|
||||
*/
|
||||
static uint32_t __glsl_shader_frag_spv[] =
|
||||
{
|
||||
0x07230203,0x00010000,0x00080007,0x00000023,0x00000000,0x00020011,0x00000001,0x0006000b,
|
||||
0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
|
||||
0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000009,0x0000000d,0x00030010,
|
||||
0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d,
|
||||
0x00000000,0x00040005,0x00000009,0x6c6f4366,0x0000726f,0x00030005,0x0000000b,0x00000000,
|
||||
0x00050006,0x0000000b,0x00000000,0x6f6c6f43,0x00000072,0x00040006,0x0000000b,0x00000001,
|
||||
0x00005655,0x00030005,0x0000000d,0x00006e49,0x00030005,0x00000015,0x00000074,0x00030005,
|
||||
0x00000019,0x00000073,0x00040047,0x00000009,0x0000001e,0x00000000,0x00040047,0x0000000d,
|
||||
0x0000001e,0x00000000,0x00040047,0x00000015,0x00000022,0x00000001,0x00040047,0x00000015,
|
||||
0x00000021,0x00000000,0x00040047,0x00000019,0x00000022,0x00000000,0x00040047,0x00000019,
|
||||
0x00000021,0x00000001,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,
|
||||
0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x00040020,0x00000008,
|
||||
0x00000003,0x00000007,0x0004003b,0x00000008,0x00000009,0x00000003,0x00040017,0x0000000a,
|
||||
0x00000006,0x00000002,0x0004001e,0x0000000b,0x00000007,0x0000000a,0x00040020,0x0000000c,
|
||||
0x00000001,0x0000000b,0x0004003b,0x0000000c,0x0000000d,0x00000001,0x00040015,0x0000000e,
|
||||
0x00000020,0x00000001,0x0004002b,0x0000000e,0x0000000f,0x00000000,0x00040020,0x00000010,
|
||||
0x00000001,0x00000007,0x00090019,0x00000013,0x00000006,0x00000001,0x00000000,0x00000000,
|
||||
0x00000000,0x00000001,0x00000000,0x00040020,0x00000014,0x00000000,0x00000013,0x0004003b,
|
||||
0x00000014,0x00000015,0x00000000,0x0002001a,0x00000017,0x00040020,0x00000018,0x00000000,
|
||||
0x00000017,0x0004003b,0x00000018,0x00000019,0x00000000,0x0003001b,0x0000001b,0x00000013,
|
||||
0x0004002b,0x0000000e,0x0000001d,0x00000001,0x00040020,0x0000001e,0x00000001,0x0000000a,
|
||||
0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x00050041,
|
||||
0x00000010,0x00000011,0x0000000d,0x0000000f,0x0004003d,0x00000007,0x00000012,0x00000011,
|
||||
0x0004003d,0x00000013,0x00000016,0x00000015,0x0004003d,0x00000017,0x0000001a,0x00000019,
|
||||
0x00050056,0x0000001b,0x0000001c,0x00000016,0x0000001a,0x00050041,0x0000001e,0x0000001f,
|
||||
0x0000000d,0x0000001d,0x0004003d,0x0000000a,0x00000020,0x0000001f,0x00050057,0x00000007,
|
||||
0x00000021,0x0000001c,0x00000020,0x00050085,0x00000007,0x00000022,0x00000012,0x00000021,
|
||||
0x0003003e,0x00000009,0x00000022,0x000100fd,0x00010038
|
||||
};
|
||||
|
||||
static void SafeRelease(ImDrawIdx*& res)
|
||||
{
|
||||
if (res)
|
||||
delete[] res;
|
||||
res = NULL;
|
||||
}
|
||||
static void SafeRelease(ImDrawVert*& res)
|
||||
{
|
||||
if (res)
|
||||
delete[] res;
|
||||
res = NULL;
|
||||
}
|
||||
static void SafeRelease(WGPUBindGroupLayout& res)
|
||||
{
|
||||
if (res)
|
||||
wgpuBindGroupLayoutRelease(res);
|
||||
res = NULL;
|
||||
}
|
||||
static void SafeRelease(WGPUBindGroup& res)
|
||||
{
|
||||
if (res)
|
||||
wgpuBindGroupRelease(res);
|
||||
res = NULL;
|
||||
}
|
||||
static void SafeRelease(WGPUBuffer& res)
|
||||
{
|
||||
if (res)
|
||||
wgpuBufferRelease(res);
|
||||
res = NULL;
|
||||
}
|
||||
static void SafeRelease(WGPURenderPipeline& res)
|
||||
{
|
||||
if (res)
|
||||
wgpuRenderPipelineRelease(res);
|
||||
res = NULL;
|
||||
}
|
||||
static void SafeRelease(WGPUSampler& res)
|
||||
{
|
||||
if (res)
|
||||
wgpuSamplerRelease(res);
|
||||
res = NULL;
|
||||
}
|
||||
static void SafeRelease(WGPUShaderModule& res)
|
||||
{
|
||||
if (res)
|
||||
wgpuShaderModuleRelease(res);
|
||||
res = NULL;
|
||||
}
|
||||
static void SafeRelease(WGPUTextureView& res)
|
||||
{
|
||||
if (res)
|
||||
wgpuTextureViewRelease(res);
|
||||
res = NULL;
|
||||
}
|
||||
static void SafeRelease(WGPUTexture& res)
|
||||
{
|
||||
if (res)
|
||||
wgpuTextureRelease(res);
|
||||
res = NULL;
|
||||
}
|
||||
|
||||
static void SafeRelease(RenderResources& res)
|
||||
{
|
||||
SafeRelease(res.FontTexture);
|
||||
SafeRelease(res.FontTextureView);
|
||||
SafeRelease(res.Sampler);
|
||||
SafeRelease(res.Uniforms);
|
||||
SafeRelease(res.CommonBindGroup);
|
||||
SafeRelease(res.ImageBindGroup);
|
||||
SafeRelease(res.ImageBindGroupLayout);
|
||||
};
|
||||
|
||||
static void SafeRelease(FrameResources& res)
|
||||
{
|
||||
SafeRelease(res.IndexBuffer);
|
||||
SafeRelease(res.VertexBuffer);
|
||||
SafeRelease(res.IndexBufferHost);
|
||||
SafeRelease(res.VertexBufferHost);
|
||||
}
|
||||
|
||||
static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModule(uint32_t* binary_data, uint32_t binary_data_size)
|
||||
{
|
||||
WGPUShaderModuleSPIRVDescriptor spirv_desc = {};
|
||||
spirv_desc.chain.sType = WGPUSType_ShaderModuleSPIRVDescriptor;
|
||||
spirv_desc.codeSize = binary_data_size;
|
||||
spirv_desc.code = binary_data;
|
||||
|
||||
WGPUShaderModuleDescriptor desc = {};
|
||||
desc.nextInChain = reinterpret_cast<WGPUChainedStruct*>(&spirv_desc);
|
||||
|
||||
WGPUProgrammableStageDescriptor stage_desc = {};
|
||||
stage_desc.module = wgpuDeviceCreateShaderModule(g_wgpuDevice, &desc);
|
||||
stage_desc.entryPoint = "main";
|
||||
return stage_desc;
|
||||
}
|
||||
|
||||
static WGPUBindGroup ImGui_ImplWGPU_CreateImageBindGroup(WGPUBindGroupLayout layout, WGPUTextureView texture)
|
||||
{
|
||||
WGPUBindGroupEntry image_bg_entries[] = { { nullptr, 0, 0, 0, 0, 0, texture } };
|
||||
|
||||
WGPUBindGroupDescriptor image_bg_descriptor = {};
|
||||
image_bg_descriptor.layout = layout;
|
||||
image_bg_descriptor.entryCount = sizeof(image_bg_entries) / sizeof(WGPUBindGroupEntry);
|
||||
image_bg_descriptor.entries = image_bg_entries;
|
||||
return wgpuDeviceCreateBindGroup(g_wgpuDevice, &image_bg_descriptor);
|
||||
}
|
||||
|
||||
static void ImGui_ImplWGPU_SetupRenderState(ImDrawData* draw_data, WGPURenderPassEncoder ctx, FrameResources* fr)
|
||||
{
|
||||
// Setup orthographic projection matrix into our constant buffer
|
||||
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right).
|
||||
{
|
||||
float L = draw_data->DisplayPos.x;
|
||||
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||
float T = draw_data->DisplayPos.y;
|
||||
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
|
||||
float mvp[4][4] =
|
||||
{
|
||||
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
|
||||
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
|
||||
{ 0.0f, 0.0f, 0.5f, 0.0f },
|
||||
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
|
||||
};
|
||||
wgpuQueueWriteBuffer(g_defaultQueue, g_resources.Uniforms, 0, mvp, sizeof(mvp));
|
||||
}
|
||||
|
||||
// Setup viewport
|
||||
wgpuRenderPassEncoderSetViewport(ctx, 0, 0, draw_data->FramebufferScale.x * draw_data->DisplaySize.x, draw_data->FramebufferScale.y * draw_data->DisplaySize.y, 0, 1);
|
||||
|
||||
// Bind shader and vertex buffers
|
||||
wgpuRenderPassEncoderSetVertexBuffer(ctx, 0, fr->VertexBuffer, 0, 0);
|
||||
wgpuRenderPassEncoderSetIndexBuffer(ctx, fr->IndexBuffer, sizeof(ImDrawIdx) == 2 ? WGPUIndexFormat_Uint16 : WGPUIndexFormat_Uint32, 0, 0);
|
||||
wgpuRenderPassEncoderSetPipeline(ctx, g_pipelineState);
|
||||
wgpuRenderPassEncoderSetBindGroup(ctx, 0, g_resources.CommonBindGroup, 0, NULL);
|
||||
|
||||
// Setup blend factor
|
||||
WGPUColor blend_color = { 0.f, 0.f, 0.f, 0.f };
|
||||
wgpuRenderPassEncoderSetBlendConstant(ctx, &blend_color);
|
||||
}
|
||||
|
||||
// Render function
|
||||
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
|
||||
void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder pass_encoder)
|
||||
{
|
||||
// Avoid rendering when minimized
|
||||
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
||||
return;
|
||||
|
||||
// FIXME: Assuming that this only gets called once per frame!
|
||||
// If not, we can't just re-allocate the IB or VB, we'll have to do a proper allocator.
|
||||
g_frameIndex = g_frameIndex + 1;
|
||||
FrameResources* fr = &g_pFrameResources[g_frameIndex % g_numFramesInFlight];
|
||||
|
||||
// Create and grow vertex/index buffers if needed
|
||||
if (fr->VertexBuffer == NULL || fr->VertexBufferSize < draw_data->TotalVtxCount)
|
||||
{
|
||||
if (fr->VertexBuffer)
|
||||
{
|
||||
wgpuBufferDestroy(fr->VertexBuffer);
|
||||
wgpuBufferRelease(fr->VertexBuffer);
|
||||
}
|
||||
SafeRelease(fr->VertexBufferHost);
|
||||
fr->VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
||||
|
||||
WGPUBufferDescriptor vb_desc =
|
||||
{
|
||||
NULL,
|
||||
"Dear ImGui Vertex buffer",
|
||||
WGPUBufferUsage_CopyDst | WGPUBufferUsage_Vertex,
|
||||
fr->VertexBufferSize * sizeof(ImDrawVert),
|
||||
false
|
||||
};
|
||||
fr->VertexBuffer = wgpuDeviceCreateBuffer(g_wgpuDevice, &vb_desc);
|
||||
if (!fr->VertexBuffer)
|
||||
return;
|
||||
|
||||
fr->VertexBufferHost = new ImDrawVert[fr->VertexBufferSize];
|
||||
}
|
||||
if (fr->IndexBuffer == NULL || fr->IndexBufferSize < draw_data->TotalIdxCount)
|
||||
{
|
||||
if (fr->IndexBuffer)
|
||||
{
|
||||
wgpuBufferDestroy(fr->IndexBuffer);
|
||||
wgpuBufferRelease(fr->IndexBuffer);
|
||||
}
|
||||
SafeRelease(fr->IndexBufferHost);
|
||||
fr->IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
||||
|
||||
WGPUBufferDescriptor ib_desc =
|
||||
{
|
||||
NULL,
|
||||
"Dear ImGui Index buffer",
|
||||
WGPUBufferUsage_CopyDst | WGPUBufferUsage_Index,
|
||||
fr->IndexBufferSize * sizeof(ImDrawIdx),
|
||||
false
|
||||
};
|
||||
fr->IndexBuffer = wgpuDeviceCreateBuffer(g_wgpuDevice, &ib_desc);
|
||||
if (!fr->IndexBuffer)
|
||||
return;
|
||||
|
||||
fr->IndexBufferHost = new ImDrawIdx[fr->IndexBufferSize];
|
||||
}
|
||||
|
||||
// Upload vertex/index data into a single contiguous GPU buffer
|
||||
ImDrawVert* vtx_dst = (ImDrawVert*)fr->VertexBufferHost;
|
||||
ImDrawIdx* idx_dst = (ImDrawIdx*)fr->IndexBufferHost;
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
|
||||
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
|
||||
vtx_dst += cmd_list->VtxBuffer.Size;
|
||||
idx_dst += cmd_list->IdxBuffer.Size;
|
||||
}
|
||||
int64_t vb_write_size = ((char*)vtx_dst - (char*)fr->VertexBufferHost + 3) & ~3;
|
||||
int64_t ib_write_size = ((char*)idx_dst - (char*)fr->IndexBufferHost + 3) & ~3;
|
||||
wgpuQueueWriteBuffer(g_defaultQueue, fr->VertexBuffer, 0, fr->VertexBufferHost, vb_write_size);
|
||||
wgpuQueueWriteBuffer(g_defaultQueue, fr->IndexBuffer, 0, fr->IndexBufferHost, ib_write_size);
|
||||
|
||||
// Setup desired render state
|
||||
ImGui_ImplWGPU_SetupRenderState(draw_data, pass_encoder, fr);
|
||||
|
||||
// Render command lists
|
||||
// (Because we merged all buffers into a single one, we maintain our own offset into them)
|
||||
int global_vtx_offset = 0;
|
||||
int global_idx_offset = 0;
|
||||
ImVec2 clip_scale = draw_data->FramebufferScale;
|
||||
ImVec2 clip_off = draw_data->DisplayPos;
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||
if (pcmd->UserCallback != NULL)
|
||||
{
|
||||
// User callback, registered via ImDrawList::AddCallback()
|
||||
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||
ImGui_ImplWGPU_SetupRenderState(draw_data, pass_encoder, fr);
|
||||
else
|
||||
pcmd->UserCallback(cmd_list, pcmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Bind custom texture
|
||||
ImTextureID tex_id = pcmd->GetTexID();
|
||||
ImGuiID tex_id_hash = ImHashData(&tex_id, sizeof(tex_id));
|
||||
auto bind_group = g_resources.ImageBindGroups.GetVoidPtr(tex_id_hash);
|
||||
if (bind_group)
|
||||
{
|
||||
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 1, (WGPUBindGroup)bind_group, 0, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
WGPUBindGroup image_bind_group = ImGui_ImplWGPU_CreateImageBindGroup(g_resources.ImageBindGroupLayout, (WGPUTextureView)tex_id);
|
||||
g_resources.ImageBindGroups.SetVoidPtr(tex_id_hash, image_bind_group);
|
||||
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 1, image_bind_group, 0, NULL);
|
||||
}
|
||||
|
||||
// Project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
|
||||
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
|
||||
if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
|
||||
continue;
|
||||
|
||||
// Apply scissor/clipping rectangle, Draw
|
||||
wgpuRenderPassEncoderSetScissorRect(pass_encoder, (uint32_t)clip_min.x, (uint32_t)clip_min.y, (uint32_t)(clip_max.x - clip_min.x), (uint32_t)(clip_max.y - clip_min.y));
|
||||
wgpuRenderPassEncoderDrawIndexed(pass_encoder, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
|
||||
}
|
||||
}
|
||||
global_idx_offset += cmd_list->IdxBuffer.Size;
|
||||
global_vtx_offset += cmd_list->VtxBuffer.Size;
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplWGPU_CreateFontsTexture()
|
||||
{
|
||||
// Build texture atlas
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
unsigned char* pixels;
|
||||
int width, height, size_pp;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &size_pp);
|
||||
|
||||
// Upload texture to graphics system
|
||||
{
|
||||
WGPUTextureDescriptor tex_desc = {};
|
||||
tex_desc.label = "Dear ImGui Font Texture";
|
||||
tex_desc.dimension = WGPUTextureDimension_2D;
|
||||
tex_desc.size.width = width;
|
||||
tex_desc.size.height = height;
|
||||
tex_desc.size.depthOrArrayLayers = 1;
|
||||
tex_desc.sampleCount = 1;
|
||||
tex_desc.format = WGPUTextureFormat_RGBA8Unorm;
|
||||
tex_desc.mipLevelCount = 1;
|
||||
tex_desc.usage = WGPUTextureUsage_CopyDst | WGPUTextureUsage_TextureBinding;
|
||||
g_resources.FontTexture = wgpuDeviceCreateTexture(g_wgpuDevice, &tex_desc);
|
||||
|
||||
WGPUTextureViewDescriptor tex_view_desc = {};
|
||||
tex_view_desc.format = WGPUTextureFormat_RGBA8Unorm;
|
||||
tex_view_desc.dimension = WGPUTextureViewDimension_2D;
|
||||
tex_view_desc.baseMipLevel = 0;
|
||||
tex_view_desc.mipLevelCount = 1;
|
||||
tex_view_desc.baseArrayLayer = 0;
|
||||
tex_view_desc.arrayLayerCount = 1;
|
||||
tex_view_desc.aspect = WGPUTextureAspect_All;
|
||||
g_resources.FontTextureView = wgpuTextureCreateView(g_resources.FontTexture, &tex_view_desc);
|
||||
}
|
||||
|
||||
// Upload texture data
|
||||
{
|
||||
WGPUImageCopyTexture dst_view = {};
|
||||
dst_view.texture = g_resources.FontTexture;
|
||||
dst_view.mipLevel = 0;
|
||||
dst_view.origin = { 0, 0, 0 };
|
||||
dst_view.aspect = WGPUTextureAspect_All;
|
||||
WGPUTextureDataLayout layout = {};
|
||||
layout.offset = 0;
|
||||
layout.bytesPerRow = width * size_pp;
|
||||
layout.rowsPerImage = height;
|
||||
WGPUExtent3D size = { (uint32_t)width, (uint32_t)height, 1 };
|
||||
wgpuQueueWriteTexture(g_defaultQueue, &dst_view, pixels, (uint32_t)(width * size_pp * height), &layout, &size);
|
||||
}
|
||||
|
||||
// Create the associated sampler
|
||||
{
|
||||
WGPUSamplerDescriptor sampler_desc = {};
|
||||
sampler_desc.minFilter = WGPUFilterMode_Linear;
|
||||
sampler_desc.magFilter = WGPUFilterMode_Linear;
|
||||
sampler_desc.mipmapFilter = WGPUFilterMode_Linear;
|
||||
sampler_desc.addressModeU = WGPUAddressMode_Repeat;
|
||||
sampler_desc.addressModeV = WGPUAddressMode_Repeat;
|
||||
sampler_desc.addressModeW = WGPUAddressMode_Repeat;
|
||||
sampler_desc.maxAnisotropy = 1;
|
||||
g_resources.Sampler = wgpuDeviceCreateSampler(g_wgpuDevice, &sampler_desc);
|
||||
}
|
||||
|
||||
// Store our identifier
|
||||
static_assert(sizeof(ImTextureID) >= sizeof(g_resources.FontTexture), "Can't pack descriptor handle into TexID, 32-bit not supported yet.");
|
||||
io.Fonts->SetTexID((ImTextureID)g_resources.FontTextureView);
|
||||
}
|
||||
|
||||
static void ImGui_ImplWGPU_CreateUniformBuffer()
|
||||
{
|
||||
WGPUBufferDescriptor ub_desc =
|
||||
{
|
||||
NULL,
|
||||
"Dear ImGui Uniform buffer",
|
||||
WGPUBufferUsage_CopyDst | WGPUBufferUsage_Uniform,
|
||||
sizeof(Uniforms),
|
||||
false
|
||||
};
|
||||
g_resources.Uniforms = wgpuDeviceCreateBuffer(g_wgpuDevice, &ub_desc);
|
||||
}
|
||||
|
||||
bool ImGui_ImplWGPU_CreateDeviceObjects()
|
||||
{
|
||||
if (!g_wgpuDevice)
|
||||
return false;
|
||||
if (g_pipelineState)
|
||||
ImGui_ImplWGPU_InvalidateDeviceObjects();
|
||||
|
||||
// Create render pipeline
|
||||
WGPURenderPipelineDescriptor graphics_pipeline_desc = {};
|
||||
graphics_pipeline_desc.primitive.topology = WGPUPrimitiveTopology_TriangleList;
|
||||
graphics_pipeline_desc.primitive.stripIndexFormat = WGPUIndexFormat_Undefined;
|
||||
graphics_pipeline_desc.primitive.frontFace = WGPUFrontFace_CW;
|
||||
graphics_pipeline_desc.primitive.cullMode = WGPUCullMode_None;
|
||||
graphics_pipeline_desc.multisample.count = 1;
|
||||
graphics_pipeline_desc.multisample.mask = UINT_MAX;
|
||||
graphics_pipeline_desc.multisample.alphaToCoverageEnabled = false;
|
||||
graphics_pipeline_desc.layout = nullptr; // Use automatic layout generation
|
||||
|
||||
// Create the vertex shader
|
||||
WGPUProgrammableStageDescriptor vertex_shader_desc = ImGui_ImplWGPU_CreateShaderModule(__glsl_shader_vert_spv, sizeof(__glsl_shader_vert_spv) / sizeof(uint32_t));
|
||||
graphics_pipeline_desc.vertex.module = vertex_shader_desc.module;
|
||||
graphics_pipeline_desc.vertex.entryPoint = vertex_shader_desc.entryPoint;
|
||||
|
||||
// Vertex input configuration
|
||||
WGPUVertexAttribute attribute_desc[] =
|
||||
{
|
||||
{ WGPUVertexFormat_Float32x2, (uint64_t)IM_OFFSETOF(ImDrawVert, pos), 0 },
|
||||
{ WGPUVertexFormat_Float32x2, (uint64_t)IM_OFFSETOF(ImDrawVert, uv), 1 },
|
||||
{ WGPUVertexFormat_Unorm8x4, (uint64_t)IM_OFFSETOF(ImDrawVert, col), 2 },
|
||||
};
|
||||
|
||||
WGPUVertexBufferLayout buffer_layouts[1];
|
||||
buffer_layouts[0].arrayStride = sizeof(ImDrawVert);
|
||||
buffer_layouts[0].stepMode = WGPUVertexStepMode_Vertex;
|
||||
buffer_layouts[0].attributeCount = 3;
|
||||
buffer_layouts[0].attributes = attribute_desc;
|
||||
|
||||
graphics_pipeline_desc.vertex.bufferCount = 1;
|
||||
graphics_pipeline_desc.vertex.buffers = buffer_layouts;
|
||||
|
||||
// Create the pixel shader
|
||||
WGPUProgrammableStageDescriptor pixel_shader_desc = ImGui_ImplWGPU_CreateShaderModule(__glsl_shader_frag_spv, sizeof(__glsl_shader_frag_spv) / sizeof(uint32_t));
|
||||
|
||||
// Create the blending setup
|
||||
WGPUBlendState blend_state = {};
|
||||
blend_state.alpha.operation = WGPUBlendOperation_Add;
|
||||
blend_state.alpha.srcFactor = WGPUBlendFactor_One;
|
||||
blend_state.alpha.dstFactor = WGPUBlendFactor_OneMinusSrcAlpha;
|
||||
blend_state.color.operation = WGPUBlendOperation_Add;
|
||||
blend_state.color.srcFactor = WGPUBlendFactor_SrcAlpha;
|
||||
blend_state.color.dstFactor = WGPUBlendFactor_OneMinusSrcAlpha;
|
||||
|
||||
WGPUColorTargetState color_state = {};
|
||||
color_state.format = g_renderTargetFormat;
|
||||
color_state.blend = &blend_state;
|
||||
color_state.writeMask = WGPUColorWriteMask_All;
|
||||
|
||||
WGPUFragmentState fragment_state = {};
|
||||
fragment_state.module = pixel_shader_desc.module;
|
||||
fragment_state.entryPoint = pixel_shader_desc.entryPoint;
|
||||
fragment_state.targetCount = 1;
|
||||
fragment_state.targets = &color_state;
|
||||
|
||||
graphics_pipeline_desc.fragment = &fragment_state;
|
||||
|
||||
// Create depth-stencil State
|
||||
WGPUDepthStencilState depth_stencil_state = {};
|
||||
depth_stencil_state.depthBias = 0;
|
||||
depth_stencil_state.depthBiasClamp = 0;
|
||||
depth_stencil_state.depthBiasSlopeScale = 0;
|
||||
|
||||
// Configure disabled depth-stencil state
|
||||
graphics_pipeline_desc.depthStencil = nullptr;
|
||||
|
||||
g_pipelineState = wgpuDeviceCreateRenderPipeline(g_wgpuDevice, &graphics_pipeline_desc);
|
||||
|
||||
ImGui_ImplWGPU_CreateFontsTexture();
|
||||
ImGui_ImplWGPU_CreateUniformBuffer();
|
||||
|
||||
// Create resource bind group
|
||||
WGPUBindGroupLayout bg_layouts[2];
|
||||
bg_layouts[0] = wgpuRenderPipelineGetBindGroupLayout(g_pipelineState, 0);
|
||||
bg_layouts[1] = wgpuRenderPipelineGetBindGroupLayout(g_pipelineState, 1);
|
||||
|
||||
WGPUBindGroupEntry common_bg_entries[] =
|
||||
{
|
||||
{ nullptr, 0, g_resources.Uniforms, 0, sizeof(Uniforms), 0, 0 },
|
||||
{ nullptr, 1, 0, 0, 0, g_resources.Sampler, 0 },
|
||||
};
|
||||
|
||||
WGPUBindGroupDescriptor common_bg_descriptor = {};
|
||||
common_bg_descriptor.layout = bg_layouts[0];
|
||||
common_bg_descriptor.entryCount = sizeof(common_bg_entries) / sizeof(WGPUBindGroupEntry);
|
||||
common_bg_descriptor.entries = common_bg_entries;
|
||||
g_resources.CommonBindGroup = wgpuDeviceCreateBindGroup(g_wgpuDevice, &common_bg_descriptor);
|
||||
|
||||
WGPUBindGroup image_bind_group = ImGui_ImplWGPU_CreateImageBindGroup(bg_layouts[1], g_resources.FontTextureView);
|
||||
g_resources.ImageBindGroup = image_bind_group;
|
||||
g_resources.ImageBindGroupLayout = bg_layouts[1];
|
||||
g_resources.ImageBindGroups.SetVoidPtr(ImHashData(&g_resources.FontTextureView, sizeof(ImTextureID)), image_bind_group);
|
||||
|
||||
SafeRelease(vertex_shader_desc.module);
|
||||
SafeRelease(pixel_shader_desc.module);
|
||||
SafeRelease(bg_layouts[0]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplWGPU_InvalidateDeviceObjects()
|
||||
{
|
||||
if (!g_wgpuDevice)
|
||||
return;
|
||||
|
||||
SafeRelease(g_pipelineState);
|
||||
SafeRelease(g_resources);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.Fonts->SetTexID(NULL); // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
||||
|
||||
for (unsigned int i = 0; i < g_numFramesInFlight; i++)
|
||||
SafeRelease(g_pFrameResources[i]);
|
||||
}
|
||||
|
||||
bool ImGui_ImplWGPU_Init(WGPUDevice device, int num_frames_in_flight, WGPUTextureFormat rt_format)
|
||||
{
|
||||
// Setup backend capabilities flags
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.BackendRendererName = "imgui_impl_webgpu";
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
|
||||
g_wgpuDevice = device;
|
||||
g_defaultQueue = wgpuDeviceGetQueue(g_wgpuDevice);
|
||||
g_renderTargetFormat = rt_format;
|
||||
g_pFrameResources = new FrameResources[num_frames_in_flight];
|
||||
g_numFramesInFlight = num_frames_in_flight;
|
||||
g_frameIndex = UINT_MAX;
|
||||
|
||||
g_resources.FontTexture = NULL;
|
||||
g_resources.FontTextureView = NULL;
|
||||
g_resources.Sampler = NULL;
|
||||
g_resources.Uniforms = NULL;
|
||||
g_resources.CommonBindGroup = NULL;
|
||||
g_resources.ImageBindGroups.Data.reserve(100);
|
||||
g_resources.ImageBindGroup = NULL;
|
||||
g_resources.ImageBindGroupLayout = NULL;
|
||||
|
||||
// Create buffers with a default size (they will later be grown as needed)
|
||||
for (int i = 0; i < num_frames_in_flight; i++)
|
||||
{
|
||||
FrameResources* fr = &g_pFrameResources[i];
|
||||
fr->IndexBuffer = NULL;
|
||||
fr->VertexBuffer = NULL;
|
||||
fr->IndexBufferHost = NULL;
|
||||
fr->VertexBufferHost = NULL;
|
||||
fr->IndexBufferSize = 10000;
|
||||
fr->VertexBufferSize = 5000;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplWGPU_Shutdown()
|
||||
{
|
||||
ImGui_ImplWGPU_InvalidateDeviceObjects();
|
||||
delete[] g_pFrameResources;
|
||||
g_pFrameResources = NULL;
|
||||
wgpuQueueRelease(g_defaultQueue);
|
||||
g_wgpuDevice = NULL;
|
||||
g_numFramesInFlight = 0;
|
||||
g_frameIndex = UINT_MAX;
|
||||
}
|
||||
|
||||
void ImGui_ImplWGPU_NewFrame()
|
||||
{
|
||||
if (!g_pipelineState)
|
||||
ImGui_ImplWGPU_CreateDeviceObjects();
|
||||
}
|
||||
25
samples/external/Imgui/imgui-docking/backends/imgui_impl_wgpu.h
vendored
Normal file
25
samples/external/Imgui/imgui-docking/backends/imgui_impl_wgpu.h
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
// dear imgui: Renderer for WebGPU
|
||||
// This needs to be used along with a Platform Binding (e.g. GLFW)
|
||||
// (Please note that WebGPU is currently experimental, will not run on non-beta browsers, and may break.)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
#include <webgpu/webgpu.h>
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplWGPU_Init(WGPUDevice device, int num_frames_in_flight, WGPUTextureFormat rt_format);
|
||||
IMGUI_IMPL_API void ImGui_ImplWGPU_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplWGPU_NewFrame();
|
||||
IMGUI_IMPL_API void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder pass_encoder);
|
||||
|
||||
// Use if you want to reset your rendering device without losing Dear ImGui state.
|
||||
IMGUI_IMPL_API void ImGui_ImplWGPU_InvalidateDeviceObjects();
|
||||
IMGUI_IMPL_API bool ImGui_ImplWGPU_CreateDeviceObjects();
|
||||
1052
samples/external/Imgui/imgui-docking/backends/imgui_impl_win32.cpp
vendored
Normal file
1052
samples/external/Imgui/imgui-docking/backends/imgui_impl_win32.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
43
samples/external/Imgui/imgui-docking/backends/imgui_impl_win32.h
vendored
Normal file
43
samples/external/Imgui/imgui-docking/backends/imgui_impl_win32.h
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
// dear imgui: Platform Backend for Windows (standard windows API for 32 and 64 bits applications)
|
||||
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui)
|
||||
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE).
|
||||
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd);
|
||||
IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame();
|
||||
|
||||
// Win32 message handler your application need to call.
|
||||
// - Intentionally commented out in a '#if 0' block to avoid dragging dependencies on <windows.h> from this helper.
|
||||
// - You should COPY the line below into your .cpp code to forward declare the function and then you can call it.
|
||||
#if 0
|
||||
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
#endif
|
||||
|
||||
// DPI-related helpers (optional)
|
||||
// - Use to enable DPI awareness without having to create an application manifest.
|
||||
// - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps.
|
||||
// - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc.
|
||||
// but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime,
|
||||
// neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies.
|
||||
IMGUI_IMPL_API void ImGui_ImplWin32_EnableDpiAwareness();
|
||||
IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd); // HWND hwnd
|
||||
IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor); // HMONITOR monitor
|
||||
|
||||
// Transparency related helpers (optional) [experimental]
|
||||
// - Use to enable alpha compositing transparency with the desktop.
|
||||
// - Use together with e.g. clearing your framebuffer with zero-alpha.
|
||||
IMGUI_IMPL_API void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd); // HWND hwnd
|
||||
6
samples/external/Imgui/imgui-docking/backends/vulkan/generate_spv.sh
vendored
Normal file
6
samples/external/Imgui/imgui-docking/backends/vulkan/generate_spv.sh
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
## -V: create SPIR-V binary
|
||||
## -x: save binary output as text-based 32-bit hexadecimal numbers
|
||||
## -o: output file
|
||||
glslangValidator -V -x -o glsl_shader.frag.u32 glsl_shader.frag
|
||||
glslangValidator -V -x -o glsl_shader.vert.u32 glsl_shader.vert
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user