Start Windows compatibility
screen_capture_lite turned out to be pretty broken and so I brought back my old X11 implementation for the Window node, for Unices only. Hopefully SCL actually works on Windows because lemme tell you, I do not want to go knee-deep in that. Additionally, SAIL was replaced with stb_image because I couldn't get SAIL to build under MinGW.
This commit is contained in:
parent
d77ae15b46
commit
3993163d6d
39
Makefile
39
Makefile
@ -1,6 +1,26 @@
|
|||||||
|
|
||||||
CXXFLAGS := -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200809L -Wno-narrowing -march=native -flto -Wall -fvisibility=hidden -fPIC -msse4 -I./ -I/usr/local/include/sail -L/usr/local/lib `pkg-config --cflags pango opus libv4l2` '-Wl,-rpath,$$ORIGIN' -Wno-multichar
|
CXXFLAGS := -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200809L -Wno-narrowing -march=native -flto -Wall -fvisibility=hidden -fPIC -msse4 -I./ '-Wl,-rpath,$$ORIGIN' -Wno-multichar
|
||||||
LDFLAGS := -lwebm -lpng -lvpx -lsail -lsail-manip `pkg-config --libs pango opus libv4l2` -lportaudio -lXtst -lrtmp -lfdk-aac -leebie -lscreen_capture_lite_shared
|
LDFLAGS := -lwebm -lpng -lvpx -lportaudio -lrtmp -lfdk-aac -leebie -lscreen_capture_lite_shared
|
||||||
|
|
||||||
|
ifneq ($(MINGW),0)
|
||||||
|
CXXFLAGS := `pkg-config --cflags pango opus libv4l2` -I/usr/local/bin -I/usr/local/include/sail $(CXXFLAGS)
|
||||||
|
LDFLAGS := $(LDFLAGS) -lXtst `pkg-config --libs pango opus libv4l2` -lstdc++
|
||||||
|
WXCFLAGS := `wx-config --cflags base,adv,core,aui`
|
||||||
|
WXLDFLAGS := `wx-config --libs base,adv,core,aui`
|
||||||
|
RELAY_C := relay_x11.c
|
||||||
|
WINDOW_C := window_x11.cpp
|
||||||
|
LIBCUTIHI := libcutihi.so
|
||||||
|
else
|
||||||
|
CXXFLAGS := `x86_64-w64-mingw32-pkg-config --cflags pangoft2 freetype2 opus` $(CXXFLAGS)
|
||||||
|
LDFLAGS := $(LDFLAGS) -pthread -lwinmm -lwebm -lole32 -lsetupapi -lws2_32 -lopus -lssp `x86_64-w64-mingw32-pkg-config --libs pangoft2` -lstdc++
|
||||||
|
WXCFLAGS := `wx-config --host=x86_64-w64-mingw32 --prefix=/usr/x86_64-w64-mingw32/ --cflags base,adv,core,aui`
|
||||||
|
WXLDFLAGS := `wx-config --host=x86_64-w64-mingw32 --prefix=/usr/x86_64-w64-mingw32/ --libs base,adv,core,aui`
|
||||||
|
RELAY_C := relay_win.c
|
||||||
|
WINDOW_C := window_scl.cpp
|
||||||
|
CC = x86_64-w64-mingw32-gcc
|
||||||
|
CXX = x86_64-w64-mingw32-g++
|
||||||
|
LIBCUTIHI := libcutihi.dll
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq ($(RELEASE),0)
|
ifneq ($(RELEASE),0)
|
||||||
CXXFLAGS := $(CXXFLAGS) -O0 -gdwarf-2 -DMTR_ENABLED
|
CXXFLAGS := $(CXXFLAGS) -O0 -gdwarf-2 -DMTR_ENABLED
|
||||||
@ -8,24 +28,29 @@ else
|
|||||||
CXXFLAGS := $(CXXFLAGS) -O3 -fopenmp -DMTR_ENABLED
|
CXXFLAGS := $(CXXFLAGS) -O3 -fopenmp -DMTR_ENABLED
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq ($(SANITIZE),0)
|
||||||
|
else
|
||||||
|
CXXFLAGS := -fsanitize=address $(CXXFLAGS)
|
||||||
|
endif
|
||||||
|
|
||||||
all:
|
all:
|
||||||
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o node.o hi/node.c $(LDFLAGS)
|
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o node.o hi/node.c $(LDFLAGS)
|
||||||
$(CXX) $(CXXFLAGS) -std=c++17 -shared -c -o window.o hi/window.cpp $(LDFLAGS)
|
$(CXX) $(CXXFLAGS) -std=c++17 -shared -c -o window.o hi/$(WINDOW_C) $(LDFLAGS)
|
||||||
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o microphone.o hi/microphone.c $(LDFLAGS)
|
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o microphone.o hi/microphone.c $(LDFLAGS)
|
||||||
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o mode.o hi/mode.c $(LDFLAGS)
|
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o mode.o hi/mode.c $(LDFLAGS)
|
||||||
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o img.o hi/img.c $(LDFLAGS)
|
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o img.o hi/img.c $(LDFLAGS)
|
||||||
$(CXX) $(CXXFLAGS) -std=c++17 -shared -c -o webmdec.o hi/webmdec.cpp $(LDFLAGS)
|
$(CXX) $(CXXFLAGS) -std=c++17 -shared -c -o webmdec.o hi/webmdec.cpp $(LDFLAGS)
|
||||||
$(CXX) $(CXXFLAGS) -std=c++17 -shared -c -o webmenc.o hi/webmenc.cpp $(LDFLAGS)
|
# $(CXX) $(CXXFLAGS) -std=c++17 -shared -c -o webmenc.o hi/webmenc.cpp $(LDFLAGS)
|
||||||
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o vpxenc.o hi/vpxenc.c $(LDFLAGS)
|
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o vpxenc.o hi/vpxenc.c $(LDFLAGS)
|
||||||
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o opus.o hi/opus.c $(LDFLAGS)
|
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o opus.o hi/opus.c $(LDFLAGS)
|
||||||
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o webcam.o hi/webcam.c $(LDFLAGS)
|
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o webcam.o hi/webcam.c $(LDFLAGS)
|
||||||
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o scale.o hi/relay.c $(LDFLAGS)
|
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o scale.o hi/$(RELAY_C) $(LDFLAGS)
|
||||||
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o minitrace.o hi/minitrace.c $(LDFLAGS)
|
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o minitrace.o hi/minitrace.c $(LDFLAGS)
|
||||||
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o h264enc.o hi/h264enc.c $(LDFLAGS)
|
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o h264enc.o hi/h264enc.c $(LDFLAGS)
|
||||||
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o rtmp.o hi/rtmp.c $(LDFLAGS)
|
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o rtmp.o hi/rtmp.c $(LDFLAGS)
|
||||||
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o aaclc.o hi/aaclc.c $(LDFLAGS)
|
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o aaclc.o hi/aaclc.c $(LDFLAGS)
|
||||||
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o mkv.o hi/mkv.c $(LDFLAGS)
|
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o mkv.o hi/mkv.c $(LDFLAGS)
|
||||||
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o serialize.o hi/serialize.c $(LDFLAGS)
|
$(CC) $(CXXFLAGS) -std=c99 -shared -c -o serialize.o hi/serialize.c $(LDFLAGS)
|
||||||
$(CC) $(CXXFLAGS) -shared -o libcutihi.so -shared node.o webmdec.o webmenc.o window.o microphone.o mode.o img.o opus.o webcam.o scale.o minitrace.o h264enc.o rtmp.o aaclc.o vpxenc.o mkv.o serialize.o $(LDFLAGS)
|
$(CC) $(CXXFLAGS) -shared -o $(LIBCUTIHI) node.o webmdec.o window.o microphone.o mode.o img.o opus.o webcam.o scale.o minitrace.o h264enc.o rtmp.o aaclc.o vpxenc.o mkv.o serialize.o $(LDFLAGS)
|
||||||
|
|
||||||
$(CXX) $(CXXFLAGS) -std=c++11 `wx-config --cflags base,adv,core,aui` -o cuticle ui/main.cpp ui/frame.cpp ui/textctrl.cpp ui/timeline.cpp -L./ -lcutihi $(LDFLAGS) `wx-config --libs base,adv,core,aui`
|
$(CXX) $(CXXFLAGS) $(WXCFLAGS) -std=c++11 -o cuticle ui/main.cpp ui/frame.cpp ui/textctrl.cpp ui/timeline.cpp -L./ -lcutihi $(LDFLAGS) $(WXLDFLAGS)
|
||||||
|
2
hi/img.c
2
hi/img.c
@ -12,7 +12,7 @@ CUTIVIS CHiImage* CHi_Image_New(uint8_t bpc, uint8_t channels, uint16_t stride,
|
|||||||
img->width = width;
|
img->width = width;
|
||||||
img->height = height;
|
img->height = height;
|
||||||
if(data) img->data16 = data;
|
if(data) img->data16 = data;
|
||||||
else img->data16 = _mm_malloc(bpc * stride * height, 16);
|
else img->data16 = _mm_malloc(bpc * stride * height + 16, 16);
|
||||||
img->owned = !data;
|
img->owned = !data;
|
||||||
|
|
||||||
assert(stride % 16 == 0);
|
assert(stride % 16 == 0);
|
||||||
|
@ -219,7 +219,7 @@ _PS_CONST(cephes_log_q2, 0.693359375);
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
inline __m128 my_movehl_ps(__m128 a, const __m128 b) {
|
inline __m128 my_movehl_ps(__m128 a, const __m128 b) {
|
||||||
asm (
|
__asm__ (
|
||||||
"movhlps %2,%0\n\t"
|
"movhlps %2,%0\n\t"
|
||||||
: "=x" (a)
|
: "=x" (a)
|
||||||
: "0" (a), "x"(b)
|
: "0" (a), "x"(b)
|
||||||
@ -229,7 +229,7 @@ inline __m128 my_movehl_ps(__m128 a, const __m128 b) {
|
|||||||
#define _mm_movehl_ps my_movehl_ps
|
#define _mm_movehl_ps my_movehl_ps
|
||||||
|
|
||||||
inline __m128 my_cmplt_ps(__m128 a, const __m128 b) {
|
inline __m128 my_cmplt_ps(__m128 a, const __m128 b) {
|
||||||
asm (
|
__asm__ (
|
||||||
"cmpltps %2,%0\n\t"
|
"cmpltps %2,%0\n\t"
|
||||||
: "=x" (a)
|
: "=x" (a)
|
||||||
: "0" (a), "x"(b)
|
: "0" (a), "x"(b)
|
||||||
@ -237,7 +237,7 @@ inline __m128 my_cmplt_ps(__m128 a, const __m128 b) {
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
inline __m128 my_cmpgt_ps(__m128 a, const __m128 b) {
|
inline __m128 my_cmpgt_ps(__m128 a, const __m128 b) {
|
||||||
asm (
|
__asm__ (
|
||||||
"cmpnleps %2,%0\n\t"
|
"cmpnleps %2,%0\n\t"
|
||||||
: "=x" (a)
|
: "=x" (a)
|
||||||
: "0" (a), "x"(b)
|
: "0" (a), "x"(b)
|
||||||
@ -245,7 +245,7 @@ inline __m128 my_cmpgt_ps(__m128 a, const __m128 b) {
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
inline __m128 my_cmpeq_ps(__m128 a, const __m128 b) {
|
inline __m128 my_cmpeq_ps(__m128 a, const __m128 b) {
|
||||||
asm (
|
__asm__ (
|
||||||
"cmpeqps %2,%0\n\t"
|
"cmpeqps %2,%0\n\t"
|
||||||
: "=x" (a)
|
: "=x" (a)
|
||||||
: "0" (a), "x"(b)
|
: "0" (a), "x"(b)
|
||||||
|
9
hi/mkv.c
9
hi/mkv.c
@ -24,8 +24,15 @@
|
|||||||
|
|
||||||
#include<stdio.h>
|
#include<stdio.h>
|
||||||
|
|
||||||
#include<arpa/inet.h>
|
#ifdef _WIN32
|
||||||
|
#include<windows.h>
|
||||||
|
#include<ntsecapi.h>
|
||||||
|
static int getrandom(void *buf, size_t buflen, unsigned int flags) {
|
||||||
|
return RtlGenRandom(buf, buflen) ? buflen : -1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
#include<sys/random.h>
|
#include<sys/random.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define NALLENSZ 4
|
#define NALLENSZ 4
|
||||||
|
|
||||||
|
31
hi/node.c
31
hi/node.c
@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
#include<stdlib.h>
|
#include<stdlib.h>
|
||||||
#include"img.h"
|
#include"img.h"
|
||||||
#include<sail/sail.h>
|
|
||||||
#include<sail-manip/sail-manip.h>
|
|
||||||
#include<assert.h>
|
#include<assert.h>
|
||||||
#include<string.h>
|
#include<string.h>
|
||||||
#include<tmmintrin.h>
|
#include<tmmintrin.h>
|
||||||
@ -21,6 +19,9 @@
|
|||||||
|
|
||||||
#include"node_internal.h"
|
#include"node_internal.h"
|
||||||
|
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include<stb_image.h>
|
||||||
|
|
||||||
CUTIVIS CHiNodeGraph *CHi_NewNodeGraph() {
|
CUTIVIS CHiNodeGraph *CHi_NewNodeGraph() {
|
||||||
static int inited = 0;
|
static int inited = 0;
|
||||||
if(!inited) {
|
if(!inited) {
|
||||||
@ -545,32 +546,26 @@ static int image_perform(CHiPubNode *node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!internal->cacheImg) {
|
if(!internal->cacheImg) {
|
||||||
struct sail_image *simg;
|
size_t w = 0, h = 0, n = 4;
|
||||||
if(sail_load_from_file(fn, &simg) != SAIL_OK) {
|
float *data = stbi_loadf(fn, &w, &h, &n, 4);
|
||||||
|
if(!data) {
|
||||||
CHi_AddError(node, "invalid file", 0);
|
CHi_AddError(node, "invalid file", 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sail_image *cimg;
|
CHiImage *img = CHi_Image_New(2, 4, (w * 8 + 15) & ~15, w, h, NULL);
|
||||||
sail_convert_image(simg, SAIL_PIXEL_FORMAT_BPP64_BGRA, &cimg);
|
|
||||||
|
|
||||||
sail_destroy_image(simg);
|
|
||||||
simg = NULL;
|
|
||||||
|
|
||||||
CHiImage *img = CHi_Image_New(2, 4, (cimg->bytes_per_line + 15) & ~15, cimg->width, cimg->height, NULL);
|
|
||||||
CHi_Restride(cimg->pixels, img->data16, cimg->bytes_per_line, img->stride, img->height);
|
|
||||||
internal->cacheImg = img;
|
internal->cacheImg = img;
|
||||||
|
|
||||||
for(size_t y = 0; y < img->height; y++) {
|
for(size_t y = 0; y < img->height; y++) {
|
||||||
for(size_t x = 0; x < img->stride; x += 16) {
|
for(size_t x = 0; x < img->width; x++) {
|
||||||
__m128i pixels = _mm_load_si128((__m128i*) ((uintptr_t) img->data16 + y * img->stride + x));
|
__m128 pixels = _mm_load_ps((__m128*) &data[w * y + x]);
|
||||||
pixels = apply_gamma_epi16(pixels, _mm_set_ps(1.0f, 2.2f, 2.2f, 2.2f));
|
pixels = apply_gamma_ps(pixels, _mm_set_ps(1.0f, 2.2f, 2.2f, 2.2f));
|
||||||
_mm_stream_si128((__m128i*) ((uintptr_t) img->data16 + y * img->stride + x), pixels);
|
__m128i pixelsi = _mm_cvtps_epi32(_mm_mul_ps(_mm_min_ps(_mm_max_ps(pixels, _mm_set1_ps(0.0f)), _mm_set1_ps(1.0f)), _mm_set1_ps(65535.0f)));
|
||||||
|
pixelsi = _mm_shuffle_epi8(pixelsi, _mm_set_epi8(0, 1, 4, 5, 8, 9, 12, 13, -128, -128, -128, -128, -128, -128, -128, -128));
|
||||||
|
_mm_stream_si128((__m128i*) ((uintptr_t) img->data16 + y * img->stride + x), pixelsi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sail_destroy_image(cimg);
|
|
||||||
|
|
||||||
free(internal->cachePath);
|
free(internal->cachePath);
|
||||||
internal->cachePath = strdup(fn);
|
internal->cachePath = strdup(fn);
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ static int encodeopus_perform(CHiPubNode *pubn) {
|
|||||||
n->pcmSamples += newpcm->width;
|
n->pcmSamples += newpcm->width;
|
||||||
}
|
}
|
||||||
|
|
||||||
CHiBSFrames *frames = malloc(sizeof(*frames));
|
CHiBSFrames *frames = calloc(1, sizeof(*frames));
|
||||||
frames->count = 0;
|
frames->count = 0;
|
||||||
|
|
||||||
if(!n->firstFrame) {
|
if(!n->firstFrame) {
|
||||||
|
149
hi/relay_win.c
Normal file
149
hi/relay_win.c
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
#include"relay.h"
|
||||||
|
|
||||||
|
#include"img.h"
|
||||||
|
#include<tmmintrin.h>
|
||||||
|
#include<stdio.h>
|
||||||
|
#include<pthread.h>
|
||||||
|
#include<stdatomic.h>
|
||||||
|
#include<math.h>
|
||||||
|
#include<windows.h>
|
||||||
|
#include<winuser.h>
|
||||||
|
#include<pthread.h>
|
||||||
|
|
||||||
|
static int scale_perform(CHiPubNode *n) {
|
||||||
|
float *scales = CHi_Crawl(&n->sinks[0])->data.vec4;
|
||||||
|
CHiImage *img = CHi_Crawl(&n->sinks[1])->data.sample;
|
||||||
|
|
||||||
|
if(n->sources[0].data.sample) {
|
||||||
|
CHi_Image_Free(n->sources[0].data.sample);
|
||||||
|
}
|
||||||
|
CHiImage *ret = n->sources[0].data.sample = CHi_Image_New(img->bpc, img->channels, img->stride, img->width, img->height, NULL);
|
||||||
|
|
||||||
|
__m128i iscales = _mm_set_epi16(
|
||||||
|
scales[3] * 65535, scales[0] * 65535, scales[1] * 65535, scales[2] * 65535,
|
||||||
|
scales[3] * 65535, scales[0] * 65535, scales[1] * 65535, scales[2] * 65535
|
||||||
|
);
|
||||||
|
|
||||||
|
for(size_t y = 0; y < img->height; y++) {
|
||||||
|
for(size_t x = 0; x < img->width; x += 16) {
|
||||||
|
__m128i pixels8 = _mm_loadu_si128((__m128i*) ((uintptr_t) img->data16 + y * img->stride + x));
|
||||||
|
__m128i mulled = _mm_mulhi_epu16(pixels8, iscales);
|
||||||
|
_mm_storeu_si128((__m128i*) ((uintptr_t) ret->data16 + y * img->stride + x), mulled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
CUTIVIS CHiPubNode *CHi_ComponentScale() {
|
||||||
|
CHiPubNode *n = calloc(1, sizeof(*n));
|
||||||
|
n->type = CUTIHI_T('CCmp','nScl');
|
||||||
|
n->Start = n->Stop = NULL;
|
||||||
|
n->Perform = scale_perform;
|
||||||
|
n->sinkCount = 2;
|
||||||
|
n->sinks = calloc(sizeof(*n->sinks), n->sinkCount);
|
||||||
|
n->sourceCount = 1;
|
||||||
|
n->sources = calloc(sizeof(*n->sources), n->sourceCount);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
CHiPubNode pub;
|
||||||
|
pthread_t thrd;
|
||||||
|
|
||||||
|
char key[64];
|
||||||
|
atomic_bool on;
|
||||||
|
atomic_bool active;
|
||||||
|
} CHiKeyhookNode;
|
||||||
|
|
||||||
|
static _Thread_local CHiKeyhookNode *lookwhatyoumademedo;
|
||||||
|
static LRESULT CALLBACK keyhook_handler(int nCode, WPARAM wParam, LPARAM lParam) {
|
||||||
|
bool eatKeystroke = false;
|
||||||
|
|
||||||
|
CHiKeyhookNode *n = lookwhatyoumademedo;
|
||||||
|
|
||||||
|
if(nCode == HC_ACTION) {
|
||||||
|
switch(wParam) {
|
||||||
|
case WM_KEYDOWN:
|
||||||
|
case WM_SYSKEYDOWN:
|
||||||
|
case WM_KEYUP:
|
||||||
|
case WM_SYSKEYUP: {
|
||||||
|
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT) lParam;
|
||||||
|
bool press = wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN;
|
||||||
|
|
||||||
|
char keyname[64];
|
||||||
|
GetKeyNameTextA(p->vkCode, keyname, sizeof(keyname));
|
||||||
|
if(!strcmp(keyname, n->key)) {
|
||||||
|
n->on = press;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return eatKeystroke ? true : CallNextHookEx(NULL, nCode, wParam, lParam);
|
||||||
|
}
|
||||||
|
static void *keyhook_thread(void *ud) {
|
||||||
|
CHiKeyhookNode *n = ud;
|
||||||
|
lookwhatyoumademedo = n;
|
||||||
|
|
||||||
|
HHOOK hhkLowLevelKybd = SetWindowsHookEx(WH_KEYBOARD_LL, keyhook_handler, 0, 0);
|
||||||
|
|
||||||
|
MSG msg;
|
||||||
|
while(n->active && !GetMessage(&msg, NULL, NULL, NULL)) {
|
||||||
|
TranslateMessage(&msg);
|
||||||
|
DispatchMessage(&msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
UnhookWindowsHookEx(hhkLowLevelKybd);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int keyhook_perform(CHiPubNode *n) {
|
||||||
|
CHiKeyhookNode *me = (CHiKeyhookNode*) n;
|
||||||
|
|
||||||
|
strncpy(me->key, CHi_Crawl(&n->sinks[0])->data.text, 63);
|
||||||
|
me->key[63] = '\0';
|
||||||
|
|
||||||
|
n->sources[0].type = CUTIHI_VAL_VEC4;
|
||||||
|
|
||||||
|
if(n->ng->compilationStatus == CUTIHI_COMP_READY || n->sinks[1].data.vec4[0] == 0) {
|
||||||
|
n->sources[0].data.vec4[0] = ((CHiKeyhookNode*) n)->on;
|
||||||
|
} else if(((CHiKeyhookNode*) n)->on) {
|
||||||
|
n->sources[0].data.vec4[0] = fminf(1, n->sources[0].data.vec4[0] + CHi_Time_GetDelta(n->ng) * n->sinks[1].data.vec4[0]);
|
||||||
|
} else {
|
||||||
|
n->sources[0].data.vec4[0] = fmaxf(0, n->sources[0].data.vec4[0] - CHi_Time_GetDelta(n->ng) * n->sinks[1].data.vec4[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void keyhook_destroy(CHiPubNode *pubn) {
|
||||||
|
CHiKeyhookNode *n = (void*) pubn;
|
||||||
|
|
||||||
|
n->active = false;
|
||||||
|
pthread_join(n->thrd, NULL);
|
||||||
|
|
||||||
|
free(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
CUTIVIS CHiPubNode *CHi_Keyhook() {
|
||||||
|
CHiKeyhookNode *n = calloc(1, sizeof(*n));
|
||||||
|
n->pub.type = CUTIHI_T('CKey','hook');
|
||||||
|
n->pub.Start = n->pub.Stop = NULL;
|
||||||
|
n->pub.Perform = keyhook_perform;
|
||||||
|
n->pub.Destroy = keyhook_destroy;
|
||||||
|
n->pub.sinkCount = 2;
|
||||||
|
n->pub.sinks = calloc(sizeof(*n->pub.sinks), n->pub.sinkCount);
|
||||||
|
n->pub.sourceCount = 1;
|
||||||
|
n->pub.sources = calloc(sizeof(*n->pub.sources), n->pub.sourceCount);
|
||||||
|
|
||||||
|
n->on = 0;
|
||||||
|
n->key[0] = '\n';
|
||||||
|
|
||||||
|
n->active = true;
|
||||||
|
pthread_create(&n->thrd, NULL, keyhook_thread, n);
|
||||||
|
|
||||||
|
return &n->pub;
|
||||||
|
}
|
@ -9,8 +9,12 @@
|
|||||||
#include<librtmp/rtmp.h>
|
#include<librtmp/rtmp.h>
|
||||||
#include<librtmp/log.h>
|
#include<librtmp/log.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include<winsock2.h>
|
||||||
|
#else
|
||||||
#include<arpa/inet.h>
|
#include<arpa/inet.h>
|
||||||
#include<sys/select.h>
|
#include<sys/select.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include"img.h"
|
#include"img.h"
|
||||||
|
|
||||||
|
@ -218,8 +218,8 @@ static void ebml_exit_callback(EBMLReader *ebml) {
|
|||||||
n = CHi_EncodeVP8();
|
n = CHi_EncodeVP8();
|
||||||
} else if(type == CUTIHI_T('CEnc','GVP9')) {
|
} else if(type == CUTIHI_T('CEnc','GVP9')) {
|
||||||
n = CHi_EncodeVP9();
|
n = CHi_EncodeVP9();
|
||||||
} else if(type == CUTIHI_T('CExp','Webm')) {
|
// } else if(type == CUTIHI_T('CExp','Webm')) {
|
||||||
n = CHi_MuxWebm();
|
// n = CHi_MuxWebm();
|
||||||
} else if(type == CUTIHI_T('CKey','hook')) {
|
} else if(type == CUTIHI_T('CKey','hook')) {
|
||||||
n = CHi_Keyhook();
|
n = CHi_Keyhook();
|
||||||
} else if(type == CUTIHI_T('CKey','hook')) {
|
} else if(type == CUTIHI_T('CKey','hook')) {
|
||||||
|
112
hi/webcam.c
112
hi/webcam.c
@ -1,130 +1,20 @@
|
|||||||
#include"node.h"
|
#include"node.h"
|
||||||
|
|
||||||
#include<sys/ioctl.h>
|
|
||||||
#include<sys/time.h>
|
|
||||||
#include<sys/mman.h>
|
|
||||||
#include<stdlib.h>
|
#include<stdlib.h>
|
||||||
#include<stdio.h>
|
#include<stdio.h>
|
||||||
#include<fcntl.h>
|
|
||||||
#include<string.h>
|
#include<string.h>
|
||||||
#include<time.h>
|
#include<time.h>
|
||||||
#include<linux/videodev2.h>
|
|
||||||
#include<libv4l2.h>
|
|
||||||
#include<errno.h>
|
#include<errno.h>
|
||||||
#include"img.h"
|
#include"img.h"
|
||||||
#include<assert.h>
|
#include<assert.h>
|
||||||
#include<smmintrin.h>
|
#include<smmintrin.h>
|
||||||
|
|
||||||
static int camId = -1;
|
|
||||||
|
|
||||||
static struct Buf {
|
|
||||||
size_t length;
|
|
||||||
uint8_t *ptr;
|
|
||||||
} bufs[2];
|
|
||||||
|
|
||||||
struct v4l2_format fmt;
|
|
||||||
|
|
||||||
static void xioctl(int fh, int request, void *arg) {
|
|
||||||
int r;
|
|
||||||
|
|
||||||
do {
|
|
||||||
r = v4l2_ioctl(fh, request, arg);
|
|
||||||
} while(r == -1 && ((errno == EINTR) || (errno == EAGAIN)));
|
|
||||||
|
|
||||||
if(r == -1) {
|
|
||||||
fprintf(stderr, "error %d, %s\\n", errno, strerror(errno));
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int camera_perform(CHiPubNode *pubn) {
|
static int camera_perform(CHiPubNode *pubn) {
|
||||||
pubn->sources[0].type = CUTIHI_VAL_SAMPLE;
|
pubn->sources[0].type = CUTIHI_VAL_NONE;
|
||||||
|
|
||||||
fd_set fds;
|
|
||||||
FD_ZERO(&fds);
|
|
||||||
FD_SET(camId, &fds);
|
|
||||||
int r = select(camId + 1, &fds, NULL, NULL, &(struct timeval) {.tv_sec = 0, .tv_usec = 100});
|
|
||||||
if(r == -1) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct v4l2_buffer buf;
|
|
||||||
memset(&buf, 0, sizeof(buf));
|
|
||||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
||||||
buf.memory = V4L2_MEMORY_MMAP;
|
|
||||||
xioctl(camId, VIDIOC_DQBUF, &buf);
|
|
||||||
|
|
||||||
CHiImage *ret;
|
|
||||||
if(pubn->sources[0].data.sample) {
|
|
||||||
ret = pubn->sources[0].data.sample;
|
|
||||||
} else {
|
|
||||||
ret = CHi_Image_New(2, 4, 8 * ((fmt.fmt.pix.width + 15) & ~15), fmt.fmt.pix.width, fmt.fmt.pix.height, NULL);
|
|
||||||
pubn->sources[0].data.sample = ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 24-to-32 TODO: make faster by processing 48-to-64 bytes in one iteration (like bgra32torgb24 does) */
|
|
||||||
for(size_t y = 0; y < ret->height; y++) {
|
|
||||||
for(size_t x = 0; x < ret->width; x += 2) {
|
|
||||||
__m128i asdf = _mm_loadu_si128((__m128i*) &bufs[buf.index].ptr[(y * ret->width + x) * 3]);
|
|
||||||
asdf = _mm_shuffle_epi8(asdf, _mm_set_epi8(-128, -128, 5, -128, 4, -128, 3, -128, -128, -128, 2, -128, 1, -128, 0, -128));
|
|
||||||
asdf = _mm_or_si128(asdf, _mm_set_epi32(0xFFFF0000, 0, 0xFFFF0000, 0));
|
|
||||||
_mm_stream_si128((__m128i*) ((uintptr_t) ret->data16 + y * ret->stride + x * 8), asdf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
xioctl(camId, VIDIOC_QBUF, &buf);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
CUTIVIS CHiPubNode *CHi_Camera() {
|
CUTIVIS CHiPubNode *CHi_Camera() {
|
||||||
if(camId == -1) {
|
|
||||||
camId = v4l2_open("/dev/video0", O_RDWR | O_NONBLOCK, 0);
|
|
||||||
|
|
||||||
memset(&fmt, 0, sizeof(fmt));
|
|
||||||
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
||||||
fmt.fmt.pix.width = 640;
|
|
||||||
fmt.fmt.pix.height = 480;
|
|
||||||
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24;
|
|
||||||
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
|
|
||||||
xioctl(camId, VIDIOC_S_FMT, &fmt);
|
|
||||||
assert(fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24);
|
|
||||||
|
|
||||||
struct v4l2_requestbuffers req;
|
|
||||||
memset(&req, 0, sizeof(req));
|
|
||||||
req.count = 2;
|
|
||||||
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
||||||
req.memory = V4L2_MEMORY_MMAP;
|
|
||||||
xioctl(camId, VIDIOC_REQBUFS, &req);
|
|
||||||
|
|
||||||
for(int i = 0; i < 2; i++) {
|
|
||||||
struct v4l2_buffer buf;
|
|
||||||
memset(&buf, 0, sizeof(buf));
|
|
||||||
|
|
||||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
||||||
buf.memory = V4L2_MEMORY_MMAP;
|
|
||||||
buf.index = i;
|
|
||||||
xioctl(camId, VIDIOC_QUERYBUF, &buf);
|
|
||||||
|
|
||||||
bufs[i].length = buf.length;
|
|
||||||
bufs[i].ptr = v4l2_mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, camId, buf.m.offset);
|
|
||||||
|
|
||||||
assert(MAP_FAILED != bufs[i].ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i = 0; i < 2; i++) {
|
|
||||||
struct v4l2_buffer buf;
|
|
||||||
memset(&buf, 0, sizeof(buf));
|
|
||||||
|
|
||||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
||||||
buf.memory = V4L2_MEMORY_MMAP;
|
|
||||||
buf.index = i;
|
|
||||||
xioctl(camId, VIDIOC_QBUF, &buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
xioctl(camId, VIDIOC_STREAMON, &(enum v4l2_buf_type) {V4L2_BUF_TYPE_VIDEO_CAPTURE});
|
|
||||||
}
|
|
||||||
|
|
||||||
CHiPubNode *pubn = calloc(1, sizeof(*pubn));
|
CHiPubNode *pubn = calloc(1, sizeof(*pubn));
|
||||||
pubn->type = CUTIHI_T('CWeb','Cam ');
|
pubn->type = CUTIHI_T('CWeb','Cam ');
|
||||||
pubn->Start = pubn->Stop = NULL;
|
pubn->Start = pubn->Stop = NULL;
|
||||||
|
136
hi/webcam_v4l2.c
Normal file
136
hi/webcam_v4l2.c
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
#include"node.h"
|
||||||
|
|
||||||
|
#include<sys/ioctl.h>
|
||||||
|
#include<sys/time.h>
|
||||||
|
#include<sys/mman.h>
|
||||||
|
#include<stdlib.h>
|
||||||
|
#include<stdio.h>
|
||||||
|
#include<fcntl.h>
|
||||||
|
#include<string.h>
|
||||||
|
#include<time.h>
|
||||||
|
#include<linux/videodev2.h>
|
||||||
|
#include<libv4l2.h>
|
||||||
|
#include<errno.h>
|
||||||
|
#include"img.h"
|
||||||
|
#include<assert.h>
|
||||||
|
#include<smmintrin.h>
|
||||||
|
|
||||||
|
static int camId = -1;
|
||||||
|
|
||||||
|
static struct Buf {
|
||||||
|
size_t length;
|
||||||
|
uint8_t *ptr;
|
||||||
|
} bufs[2];
|
||||||
|
|
||||||
|
struct v4l2_format fmt;
|
||||||
|
|
||||||
|
static void xioctl(int fh, int request, void *arg) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
do {
|
||||||
|
r = v4l2_ioctl(fh, request, arg);
|
||||||
|
} while(r == -1 && ((errno == EINTR) || (errno == EAGAIN)));
|
||||||
|
|
||||||
|
if(r == -1) {
|
||||||
|
fprintf(stderr, "error %d, %s\\n", errno, strerror(errno));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int camera_perform(CHiPubNode *pubn) {
|
||||||
|
pubn->sources[0].type = CUTIHI_VAL_SAMPLE;
|
||||||
|
|
||||||
|
fd_set fds;
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(camId, &fds);
|
||||||
|
int r = select(camId + 1, &fds, NULL, NULL, &(struct timeval) {.tv_sec = 0, .tv_usec = 100});
|
||||||
|
if(r == -1) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct v4l2_buffer buf;
|
||||||
|
memset(&buf, 0, sizeof(buf));
|
||||||
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
buf.memory = V4L2_MEMORY_MMAP;
|
||||||
|
xioctl(camId, VIDIOC_DQBUF, &buf);
|
||||||
|
|
||||||
|
CHiImage *ret;
|
||||||
|
if(pubn->sources[0].data.sample) {
|
||||||
|
ret = pubn->sources[0].data.sample;
|
||||||
|
} else {
|
||||||
|
ret = CHi_Image_New(2, 4, 8 * ((fmt.fmt.pix.width + 15) & ~15), fmt.fmt.pix.width, fmt.fmt.pix.height, NULL);
|
||||||
|
pubn->sources[0].data.sample = ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 24-to-32 TODO: make faster by processing 48-to-64 bytes in one iteration (like bgra32torgb24 does) */
|
||||||
|
for(size_t y = 0; y < ret->height; y++) {
|
||||||
|
for(size_t x = 0; x < ret->width; x += 2) {
|
||||||
|
__m128i asdf = _mm_loadu_si128((__m128i*) &bufs[buf.index].ptr[(y * ret->width + x) * 3]);
|
||||||
|
asdf = _mm_shuffle_epi8(asdf, _mm_set_epi8(-128, -128, 5, -128, 4, -128, 3, -128, -128, -128, 2, -128, 1, -128, 0, -128));
|
||||||
|
asdf = _mm_or_si128(asdf, _mm_set_epi32(0xFFFF0000, 0, 0xFFFF0000, 0));
|
||||||
|
_mm_stream_si128((__m128i*) ((uintptr_t) ret->data16 + y * ret->stride + x * 8), asdf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xioctl(camId, VIDIOC_QBUF, &buf);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
CUTIVIS CHiPubNode *CHi_Camera() {
|
||||||
|
if(camId == -1) {
|
||||||
|
camId = v4l2_open("/dev/video0", O_RDWR | O_NONBLOCK, 0);
|
||||||
|
|
||||||
|
memset(&fmt, 0, sizeof(fmt));
|
||||||
|
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
fmt.fmt.pix.width = 640;
|
||||||
|
fmt.fmt.pix.height = 480;
|
||||||
|
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24;
|
||||||
|
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
|
||||||
|
xioctl(camId, VIDIOC_S_FMT, &fmt);
|
||||||
|
assert(fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24);
|
||||||
|
|
||||||
|
struct v4l2_requestbuffers req;
|
||||||
|
memset(&req, 0, sizeof(req));
|
||||||
|
req.count = 2;
|
||||||
|
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
req.memory = V4L2_MEMORY_MMAP;
|
||||||
|
xioctl(camId, VIDIOC_REQBUFS, &req);
|
||||||
|
|
||||||
|
for(int i = 0; i < 2; i++) {
|
||||||
|
struct v4l2_buffer buf;
|
||||||
|
memset(&buf, 0, sizeof(buf));
|
||||||
|
|
||||||
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
buf.memory = V4L2_MEMORY_MMAP;
|
||||||
|
buf.index = i;
|
||||||
|
xioctl(camId, VIDIOC_QUERYBUF, &buf);
|
||||||
|
|
||||||
|
bufs[i].length = buf.length;
|
||||||
|
bufs[i].ptr = v4l2_mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, camId, buf.m.offset);
|
||||||
|
|
||||||
|
assert(MAP_FAILED != bufs[i].ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < 2; i++) {
|
||||||
|
struct v4l2_buffer buf;
|
||||||
|
memset(&buf, 0, sizeof(buf));
|
||||||
|
|
||||||
|
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
buf.memory = V4L2_MEMORY_MMAP;
|
||||||
|
buf.index = i;
|
||||||
|
xioctl(camId, VIDIOC_QBUF, &buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
xioctl(camId, VIDIOC_STREAMON, &(enum v4l2_buf_type) {V4L2_BUF_TYPE_VIDEO_CAPTURE});
|
||||||
|
}
|
||||||
|
|
||||||
|
CHiPubNode *pubn = calloc(1, sizeof(*pubn));
|
||||||
|
pubn->type = CUTIHI_T('CWeb','Cam ');
|
||||||
|
pubn->Start = pubn->Stop = NULL;
|
||||||
|
pubn->Perform = camera_perform;
|
||||||
|
pubn->sinks = calloc(sizeof(*pubn->sinks), pubn->sinkCount = 0);
|
||||||
|
pubn->sources = calloc(sizeof(*pubn->sources), pubn->sourceCount = 1);
|
||||||
|
pubn->ng = NULL;
|
||||||
|
return pubn;
|
||||||
|
}
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include<ScreenCapture.h>
|
#include<ScreenCapture.h>
|
||||||
#include<mutex>
|
#include<mutex>
|
||||||
|
#include<atomic>
|
||||||
|
|
||||||
#include<tmmintrin.h>
|
#include<tmmintrin.h>
|
||||||
#include<smmintrin.h>
|
#include<smmintrin.h>
|
||||||
@ -26,6 +27,7 @@ typedef struct {
|
|||||||
|
|
||||||
std::mutex mut;
|
std::mutex mut;
|
||||||
std::vector<CHiImage*> images;
|
std::vector<CHiImage*> images;
|
||||||
|
std::atomic<bool> ignoreAlpha;
|
||||||
} CHiWindowNode;
|
} CHiWindowNode;
|
||||||
|
|
||||||
static int window_perform(CHiPubNode *n) {
|
static int window_perform(CHiPubNode *n) {
|
||||||
@ -33,6 +35,9 @@ static int window_perform(CHiPubNode *n) {
|
|||||||
|
|
||||||
MTR_BEGIN("CHi", "window_perform");
|
MTR_BEGIN("CHi", "window_perform");
|
||||||
|
|
||||||
|
CHiValue *ignoreAlphaVal = CHi_Crawl(&w->pub.sinks[1]);
|
||||||
|
w->ignoreAlpha.store(ignoreAlphaVal ? (bool) ignoreAlphaVal->data.vec4[0] : true);
|
||||||
|
|
||||||
const char *expectedTitle = CHi_Crawl(&w->pub.sinks[0])->data.text;
|
const char *expectedTitle = CHi_Crawl(&w->pub.sinks[0])->data.text;
|
||||||
|
|
||||||
if(w->lastWindowString == nullptr || strcmp(w->lastWindowString, expectedTitle)) {
|
if(w->lastWindowString == nullptr || strcmp(w->lastWindowString, expectedTitle)) {
|
||||||
@ -52,6 +57,8 @@ static int window_perform(CHiPubNode *n) {
|
|||||||
CHiImage *new_image = CHi_Image_New(2, 4, (window.Size.x * 8 + 15) & ~15, window.Size.x, window.Size.y, nullptr);
|
CHiImage *new_image = CHi_Image_New(2, 4, (window.Size.x * 8 + 15) & ~15, window.Size.x, window.Size.y, nullptr);
|
||||||
memset(new_image->data8, 0, new_image->stride * new_image->height);
|
memset(new_image->data8, 0, new_image->stride * new_image->height);
|
||||||
|
|
||||||
|
bool ignoreAlpha = w->ignoreAlpha.load();
|
||||||
|
|
||||||
#pragma omp parallel for
|
#pragma omp parallel for
|
||||||
for(size_t y = 0; y < new_image->height; y++) {
|
for(size_t y = 0; y < new_image->height; y++) {
|
||||||
uint8_t buf[16] = {};
|
uint8_t buf[16] = {};
|
||||||
@ -60,6 +67,9 @@ static int window_perform(CHiPubNode *n) {
|
|||||||
|
|
||||||
__m128i c = _mm_loadu_si128((__m128i*) buf);
|
__m128i c = _mm_loadu_si128((__m128i*) buf);
|
||||||
c = _mm_shuffle_epi8(c, _mm_set_epi8(7, -128, 6, -128, 5, -128, 4, -128, 3, -128, 2, -128, 1, -128, 0, -128));
|
c = _mm_shuffle_epi8(c, _mm_set_epi8(7, -128, 6, -128, 5, -128, 4, -128, 3, -128, 2, -128, 1, -128, 0, -128));
|
||||||
|
if(ignoreAlpha) {
|
||||||
|
c = _mm_or_si128(c, _mm_set_epi16(0xFFFF, 0, 0, 0, 0xFFFF, 0, 0, 0));
|
||||||
|
}
|
||||||
c = apply_gamma_epi16(c, _mm_set_ps(1, 2.2f, 2.2f, 2.2f));
|
c = apply_gamma_epi16(c, _mm_set_ps(1, 2.2f, 2.2f, 2.2f));
|
||||||
_mm_store_si128((__m128i*) ((uintptr_t) new_image->data8 + y * new_image->stride + x * 8), c);
|
_mm_store_si128((__m128i*) ((uintptr_t) new_image->data8 + y * new_image->stride + x * 8), c);
|
||||||
}
|
}
|
||||||
@ -103,7 +113,7 @@ CUTIVIS CHiPubNode *CHi_Window() {
|
|||||||
n->pub.Perform = window_perform;
|
n->pub.Perform = window_perform;
|
||||||
n->pub.Destroy = window_destroy;
|
n->pub.Destroy = window_destroy;
|
||||||
n->pub.sinkCount = 1;
|
n->pub.sinkCount = 1;
|
||||||
n->pub.sinks = (CHiValue*) calloc(sizeof(*n->pub.sinks), 1);
|
n->pub.sinks = (CHiValue*) calloc(sizeof(*n->pub.sinks), 2);
|
||||||
n->pub.sourceCount = 1;
|
n->pub.sourceCount = 1;
|
||||||
n->pub.sources = (CHiValue*) calloc(sizeof(*n->pub.sources), 1);
|
n->pub.sources = (CHiValue*) calloc(sizeof(*n->pub.sources), 1);
|
||||||
|
|
218
hi/window_x11.cpp
Normal file
218
hi/window_x11.cpp
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
#include"node.h"
|
||||||
|
|
||||||
|
#include<stdlib.h>
|
||||||
|
|
||||||
|
#include<X11/Xlib.h>
|
||||||
|
#include<X11/Xutil.h>
|
||||||
|
#include<sys/ipc.h>
|
||||||
|
#include<sys/shm.h>
|
||||||
|
#include<X11/extensions/XShm.h>
|
||||||
|
#include<tmmintrin.h>
|
||||||
|
#include<smmintrin.h>
|
||||||
|
|
||||||
|
#include<time.h>
|
||||||
|
|
||||||
|
#include<string.h>
|
||||||
|
|
||||||
|
#include"img.h"
|
||||||
|
|
||||||
|
#include"linearity.h"
|
||||||
|
|
||||||
|
#include"minitrace.h"
|
||||||
|
|
||||||
|
static Display *d;
|
||||||
|
static Window root;
|
||||||
|
|
||||||
|
static int find_window(Display *d, Window *w, const char *contains) {
|
||||||
|
if(contains) {
|
||||||
|
int found = 0;
|
||||||
|
Atom atom = XInternAtom(d, "_NET_CLIENT_LIST", 1);
|
||||||
|
Atom actualType;
|
||||||
|
int format;
|
||||||
|
unsigned long numItems, bytesAfter;
|
||||||
|
|
||||||
|
Window *list;
|
||||||
|
XTextProperty windowName;
|
||||||
|
|
||||||
|
int status = XGetWindowProperty(d, root, atom, 0L, ~0L, 0, AnyPropertyType, &actualType, &format, &numItems, &bytesAfter, (unsigned char**) &list);
|
||||||
|
|
||||||
|
if(status >= Success) {
|
||||||
|
for(int i = 0; i < numItems; i++) {
|
||||||
|
status = XGetWMName(d, list[i], &windowName);
|
||||||
|
if(status >= Success) {
|
||||||
|
if(windowName.value && strstr(windowName.value, contains)) {
|
||||||
|
*w = list[i];
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XFree(list);
|
||||||
|
|
||||||
|
return found;
|
||||||
|
} else {
|
||||||
|
*w = root;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
CHiPubNode pub;
|
||||||
|
|
||||||
|
Window xcache;
|
||||||
|
XImage *ximg;
|
||||||
|
XShmSegmentInfo shminfo;
|
||||||
|
|
||||||
|
CHiImage *vcache;
|
||||||
|
} CHiWindowNode;
|
||||||
|
|
||||||
|
static int window_perform(CHiPubNode *n) {
|
||||||
|
CHiWindowNode *w = (CHiWindowNode*) n;
|
||||||
|
|
||||||
|
MTR_BEGIN("CHi", "window_perform");
|
||||||
|
|
||||||
|
Window toshoot;
|
||||||
|
if(!find_window(d, &toshoot, CHi_Crawl(&n->sinks[0])->data.text)) return 0;
|
||||||
|
|
||||||
|
size_t stride;
|
||||||
|
if(!w->xcache || w->xcache != toshoot) {
|
||||||
|
w->xcache = toshoot;
|
||||||
|
|
||||||
|
XWindowAttributes attrs;
|
||||||
|
XGetWindowAttributes(d, toshoot, &attrs);
|
||||||
|
|
||||||
|
w->ximg = XShmCreateImage(d, attrs.visual, 32, ZPixmap, NULL, &w->shminfo, attrs.width, attrs.height);
|
||||||
|
stride = ((w->ximg->bytes_per_line + 15) & ~15);
|
||||||
|
w->shminfo.shmid = shmget(IPC_PRIVATE, stride * w->ximg->height, IPC_CREAT | 0777);
|
||||||
|
w->shminfo.shmaddr = w->ximg->data = shmat(w->shminfo.shmid, 0, 0);
|
||||||
|
w->shminfo.readOnly = False;
|
||||||
|
XShmAttach(d, &w->shminfo);
|
||||||
|
|
||||||
|
w->vcache = CHi_Image_New(2, 4, 8 * attrs.width, attrs.width, attrs.height, NULL);
|
||||||
|
} else {
|
||||||
|
stride = ((w->ximg->bytes_per_line + 15) & ~15);
|
||||||
|
}
|
||||||
|
|
||||||
|
XWindowAttributes toshootattrs;
|
||||||
|
XGetWindowAttributes(d, w->xcache, &toshootattrs);
|
||||||
|
|
||||||
|
XShmGetImage(d, w->xcache, w->ximg, 0, 0, AllPlanes);
|
||||||
|
|
||||||
|
// Turn u8 image to u16
|
||||||
|
#pragma omp parallel for
|
||||||
|
for(size_t y = 0; y < w->vcache->height; y++) {
|
||||||
|
for(size_t x = 0; x < w->vcache->width; x += 2) {
|
||||||
|
__m128i c = _mm_loadu_si128((__m128i*) ((uintptr_t) w->ximg->data + y * w->ximg->bytes_per_line + x * 4));
|
||||||
|
c = _mm_shuffle_epi8(c, _mm_set_epi8(7, -128, 6, -128, 5, -128, 4, -128, 3, -128, 2, -128, 1, -128, 0, -128));
|
||||||
|
c = apply_gamma_epi16(c, _mm_set_ps(1, 2.2f, 2.2f, 2.2f));
|
||||||
|
_mm_storeu_si128((__m128i*) ((uintptr_t) w->vcache->data16 + y * w->vcache->stride + x * 8), c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
n->sources[0].type = CUTIHI_VAL_SAMPLE;
|
||||||
|
n->sources[0].data.sample = w->vcache;
|
||||||
|
|
||||||
|
MTR_END("CHi", "window_perform");
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void window_destroy(CHiPubNode *pubn) {
|
||||||
|
CHiWindowNode *n = (void*) pubn;
|
||||||
|
|
||||||
|
if(n->vcache) {
|
||||||
|
XShmDetach(d, &n->shminfo);
|
||||||
|
shmdt(n->shminfo.shmaddr);
|
||||||
|
XDestroyImage(n->ximg);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(pubn);
|
||||||
|
}
|
||||||
|
|
||||||
|
CUTIVIS CHiPubNode *CHi_Window() {
|
||||||
|
if(!d) {
|
||||||
|
d = XOpenDisplay(NULL);
|
||||||
|
root = RootWindow(d, DefaultScreen(d));
|
||||||
|
}
|
||||||
|
|
||||||
|
CHiWindowNode *n = calloc(1, sizeof(*n));
|
||||||
|
n->pub.type = CUTIHI_T('CWin','dow ');
|
||||||
|
n->pub.Start = n->pub.Stop = NULL;
|
||||||
|
n->pub.Perform = window_perform;
|
||||||
|
n->pub.Destroy = window_destroy;
|
||||||
|
n->pub.sinkCount = 1;
|
||||||
|
n->pub.sinks = calloc(sizeof(*n->pub.sinks), 1);
|
||||||
|
n->pub.sourceCount = 1;
|
||||||
|
n->pub.sources = calloc(sizeof(*n->pub.sources), 1);
|
||||||
|
|
||||||
|
n->xcache = 0;
|
||||||
|
n->vcache = NULL;
|
||||||
|
|
||||||
|
return &n->pub;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All of the following are ews
|
||||||
|
|
||||||
|
CUTIVIS size_t CHi_Window_GetSourceCount() {
|
||||||
|
Atom atom = XInternAtom(d, "_NET_CLIENT_LIST", 1);
|
||||||
|
Atom actualType;
|
||||||
|
int format;
|
||||||
|
unsigned long numItems, bytesAfter;
|
||||||
|
|
||||||
|
Window *list;
|
||||||
|
|
||||||
|
int status = XGetWindowProperty(d, root, atom, 0L, ~0L, 0, AnyPropertyType, &actualType, &format, &numItems, &bytesAfter, (unsigned char**) &list);
|
||||||
|
|
||||||
|
//XFree(list);
|
||||||
|
|
||||||
|
return status >= Success ? numItems : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CUTIVIS const char *CHi_Window_GetSourceName(size_t idx) {
|
||||||
|
int found = 0;
|
||||||
|
Atom atom = XInternAtom(d, "_NET_CLIENT_LIST", 1);
|
||||||
|
Atom actualType;
|
||||||
|
int format;
|
||||||
|
unsigned long numItems, bytesAfter;
|
||||||
|
|
||||||
|
Window *list;
|
||||||
|
XTextProperty windowName;
|
||||||
|
|
||||||
|
int status = XGetWindowProperty(d, root, atom, 0L, ~0L, 0, AnyPropertyType, &actualType, &format, &numItems, &bytesAfter, (unsigned char**) &list);
|
||||||
|
|
||||||
|
if(status >= Success) {
|
||||||
|
//XFree(list);
|
||||||
|
|
||||||
|
status = XGetWMName(d, list[idx], &windowName);
|
||||||
|
if(status >= Success) {
|
||||||
|
found = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return found ? strdup(windowName.value ? windowName.value : "") : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
CUTIVIS uintptr_t CHi_Window_GetSourceData(size_t idx) {
|
||||||
|
Atom atom = XInternAtom(d, "_NET_CLIENT_LIST", 1);
|
||||||
|
Atom actualType;
|
||||||
|
int format;
|
||||||
|
unsigned long numItems, bytesAfter;
|
||||||
|
|
||||||
|
Window *list;
|
||||||
|
|
||||||
|
int status = XGetWindowProperty(d, root, atom, 0L, ~0L, 0, AnyPropertyType, &actualType, &format, &numItems, &bytesAfter, (unsigned char**) &list);
|
||||||
|
|
||||||
|
if(status >= Success) {
|
||||||
|
Window ret = list[idx];
|
||||||
|
//XFree(list);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CUTIVIS size_t CHi_Window_GetNextSource(size_t i) {
|
||||||
|
return i + 1;
|
||||||
|
}
|
117
ui/frame.cpp
117
ui/frame.cpp
@ -135,19 +135,19 @@ static void ShapeGrNode(GrNode *gn) {
|
|||||||
gn->sinks.push_back({" Size", GrNode::Port::Type::VEC1, true});
|
gn->sinks.push_back({" Size", GrNode::Port::Type::VEC1, true});
|
||||||
}
|
}
|
||||||
} else if(gn->logical->type == CUTIHI_T('CIma','ge ')) {
|
} else if(gn->logical->type == CUTIHI_T('CIma','ge ')) {
|
||||||
gn->sinks = {{"Filepath", GrNode::Port::Type::FILE_OPEN}};
|
gn->sinks = {{"Filepath", GrNode::Port::Type::FILE_OPENING}};
|
||||||
gn->sources = {{"Sample", GrNode::Port::Type::SAMPLE}};
|
gn->sources = {{"Sample", GrNode::Port::Type::SAMPLE}};
|
||||||
} else if(gn->logical->type == CUTIHI_T('CWin','dow ')) {
|
} else if(gn->logical->type == CUTIHI_T('CWin','dow ')) {
|
||||||
gn->sinks = {{"Name", GrNode::Port::Type::WINDOW_SOURCE}};
|
gn->sinks = {{"Name", GrNode::Port::Type::WINDOW_SOURCE}, {"Ignore Alpha", GrNode::Port::Type::CHECKBOX}};
|
||||||
gn->sources = {{"Sample", GrNode::Port::Type::SAMPLE}};
|
gn->sources = {{"Sample", GrNode::Port::Type::SAMPLE}};
|
||||||
} else if(gn->logical->type == CUTIHI_T('CInA','udio')) {
|
} else if(gn->logical->type == CUTIHI_T('CInA','udio')) {
|
||||||
gn->sinks = {{"Source", GrNode::Port::Type::MIC_SOURCE}};
|
gn->sinks = {{"Source", GrNode::Port::Type::MIC_SOURCE}};
|
||||||
gn->sources = {{"Audio", GrNode::Port::Type::SAMPLE}};
|
gn->sources = {{"Audio", GrNode::Port::Type::SAMPLE}};
|
||||||
} else if(gn->logical->type == CUTIHI_T('CExp','Wave')) {
|
} else if(gn->logical->type == CUTIHI_T('CExp','Wave')) {
|
||||||
gn->sinks = {{"Filename", GrNode::Port::Type::FILE_SAVE}, {"Audio", GrNode::Port::Type::SAMPLE}};
|
gn->sinks = {{"Filename", GrNode::Port::Type::FILE_SAVING}, {"Audio", GrNode::Port::Type::SAMPLE}};
|
||||||
gn->sources = {};
|
gn->sources = {};
|
||||||
} else if(gn->logical->type == CUTIHI_T('CMov','ie ')) {
|
} else if(gn->logical->type == CUTIHI_T('CMov','ie ')) {
|
||||||
gn->sinks = {{"Filepath", GrNode::Port::Type::FILE_OPEN}, {"Time", GrNode::Port::Type::VEC1}};
|
gn->sinks = {{"Filepath", GrNode::Port::Type::FILE_OPENING}, {"Time", GrNode::Port::Type::VEC1}};
|
||||||
gn->sources = {{"Sample", GrNode::Port::Type::SAMPLE}, {"Audio", GrNode::Port::Type::SAMPLE}};
|
gn->sources = {{"Sample", GrNode::Port::Type::SAMPLE}, {"Audio", GrNode::Port::Type::SAMPLE}};
|
||||||
} else if(gn->logical->type == CUTIHI_T('CEnc','GVP8')) {
|
} else if(gn->logical->type == CUTIHI_T('CEnc','GVP8')) {
|
||||||
gn->sinks = {{"Sample", GrNode::Port::Type::SAMPLE}};
|
gn->sinks = {{"Sample", GrNode::Port::Type::SAMPLE}};
|
||||||
@ -159,7 +159,7 @@ static void ShapeGrNode(GrNode *gn) {
|
|||||||
gn->sinks = {{"Sample", GrNode::Port::Type::SAMPLE}};
|
gn->sinks = {{"Sample", GrNode::Port::Type::SAMPLE}};
|
||||||
gn->sources = {{"Bitstream"}};
|
gn->sources = {{"Bitstream"}};
|
||||||
} else if(gn->logical->type == CUTIHI_T('CExp','Webm')) {
|
} else if(gn->logical->type == CUTIHI_T('CExp','Webm')) {
|
||||||
gn->sinks = {{"Video Bitstream"}, {"Audio Bitstream"}, {"Filename", GrNode::Port::Type::FILE_SAVE}};
|
gn->sinks = {{"Video Bitstream"}, {"Audio Bitstream"}, {"Filename", GrNode::Port::Type::FILE_SAVING}};
|
||||||
gn->sources = {};
|
gn->sources = {};
|
||||||
} else if(gn->logical->type == CUTIHI_T('CKey','hook')) {
|
} else if(gn->logical->type == CUTIHI_T('CKey','hook')) {
|
||||||
gn->sinks = {{"Key", GrNode::Port::Type::TEXT}, {"Smooth Time", GrNode::Port::Type::VEC1}};
|
gn->sinks = {{"Key", GrNode::Port::Type::TEXT}, {"Smooth Time", GrNode::Port::Type::VEC1}};
|
||||||
@ -183,7 +183,7 @@ static void ShapeGrNode(GrNode *gn) {
|
|||||||
gn->sinks = {{"Audio", GrNode::Port::Type::SAMPLE}};
|
gn->sinks = {{"Audio", GrNode::Port::Type::SAMPLE}};
|
||||||
gn->sources = {{"Bitstream"}};
|
gn->sources = {{"Bitstream"}};
|
||||||
} else if(gn->logical->type == CUTIHI_T('CExp','Mkv ')) {
|
} else if(gn->logical->type == CUTIHI_T('CExp','Mkv ')) {
|
||||||
gn->sinks = {{"Video Bitstream"}, {"Audio Bitstream"}, {"Filename", GrNode::Port::Type::FILE_SAVE}};
|
gn->sinks = {{"Video Bitstream"}, {"Audio Bitstream"}, {"Filename", GrNode::Port::Type::FILE_SAVING}};
|
||||||
gn->sources = {};
|
gn->sources = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -484,8 +484,8 @@ GrNode::GrNode(NodeGraph *parent) : wxPanel(parent, wxID_ANY, {0, 0}, {175, 80})
|
|||||||
int y = 13;
|
int y = 13;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for(Port &p : sinks) {
|
for(Port &p : sinks) {
|
||||||
wxColour col = p.type == GrNode::Port::Type::FILE_OPEN ? wxColour{255, 0, 0}
|
wxColour col = p.type == GrNode::Port::Type::FILE_OPENING ? wxColour{255, 0, 0}
|
||||||
: p.type == GrNode::Port::Type::FILE_SAVE ? wxColour{255, 0, 0}
|
: p.type == GrNode::Port::Type::FILE_SAVING ? wxColour{255, 0, 0}
|
||||||
: p.type == GrNode::Port::Type::COLOR ? wxColour{0, 0, 255}
|
: p.type == GrNode::Port::Type::COLOR ? wxColour{0, 0, 255}
|
||||||
: p.type == GrNode::Port::Type::VEC2 ? wxColour{0, 255, 0}
|
: p.type == GrNode::Port::Type::VEC2 ? wxColour{0, 255, 0}
|
||||||
: p.type == GrNode::Port::Type::TEXT ? wxColour{255, 255, 0}
|
: p.type == GrNode::Port::Type::TEXT ? wxColour{255, 255, 0}
|
||||||
@ -512,8 +512,8 @@ GrNode::GrNode(NodeGraph *parent) : wxPanel(parent, wxID_ANY, {0, 0}, {175, 80})
|
|||||||
y = 13;
|
y = 13;
|
||||||
i = 0;
|
i = 0;
|
||||||
for(Port &p : sources) {
|
for(Port &p : sources) {
|
||||||
wxColour col = p.type == GrNode::Port::Type::FILE_OPEN ? wxColour{255, 0, 0}
|
wxColour col = p.type == GrNode::Port::Type::FILE_OPENING ? wxColour{255, 0, 0}
|
||||||
: p.type == GrNode::Port::Type::FILE_SAVE ? wxColour{255, 0, 0}
|
: p.type == GrNode::Port::Type::FILE_SAVING ? wxColour{255, 0, 0}
|
||||||
: p.type == GrNode::Port::Type::COLOR ? wxColour{0, 0, 255}
|
: p.type == GrNode::Port::Type::COLOR ? wxColour{0, 0, 255}
|
||||||
: p.type == GrNode::Port::Type::VEC2 ? wxColour{0, 255, 0}
|
: p.type == GrNode::Port::Type::VEC2 ? wxColour{0, 255, 0}
|
||||||
: p.type == GrNode::Port::Type::TEXT ? wxColour{255, 255, 0}
|
: p.type == GrNode::Port::Type::TEXT ? wxColour{255, 255, 0}
|
||||||
@ -650,7 +650,7 @@ GrNode::GrNode(NodeGraph *parent) : wxPanel(parent, wxID_ANY, {0, 0}, {175, 80})
|
|||||||
|
|
||||||
pthread_mutex_unlock(&this->logical->ng->mut);
|
pthread_mutex_unlock(&this->logical->ng->mut);
|
||||||
}
|
}
|
||||||
} else if(sinks[p].type == Port::Type::FILE_OPEN) {
|
} else if(sinks[p].type == Port::Type::FILE_OPENING) {
|
||||||
wxFileDialog dlg(this, wxFileSelectorPromptStr, wxEmptyString, wxEmptyString, wxFileSelectorDefaultWildcardStr, wxFD_OPEN | wxFD_PREVIEW);
|
wxFileDialog dlg(this, wxFileSelectorPromptStr, wxEmptyString, wxEmptyString, wxFileSelectorDefaultWildcardStr, wxFD_OPEN | wxFD_PREVIEW);
|
||||||
if(dlg.ShowModal() == wxID_OK) {
|
if(dlg.ShowModal() == wxID_OK) {
|
||||||
pthread_mutex_lock(&this->logical->ng->mut);
|
pthread_mutex_lock(&this->logical->ng->mut);
|
||||||
@ -663,7 +663,7 @@ GrNode::GrNode(NodeGraph *parent) : wxPanel(parent, wxID_ANY, {0, 0}, {175, 80})
|
|||||||
|
|
||||||
pthread_mutex_unlock(&this->logical->ng->mut);
|
pthread_mutex_unlock(&this->logical->ng->mut);
|
||||||
}
|
}
|
||||||
} else if(sinks[p].type == Port::Type::FILE_SAVE) {
|
} else if(sinks[p].type == Port::Type::FILE_SAVING) {
|
||||||
wxFileDialog dlg(this, wxFileSelectorPromptStr, wxEmptyString, wxEmptyString, wxFileSelectorDefaultWildcardStr, wxFD_SAVE | wxFD_PREVIEW | wxFD_OVERWRITE_PROMPT);
|
wxFileDialog dlg(this, wxFileSelectorPromptStr, wxEmptyString, wxEmptyString, wxFileSelectorDefaultWildcardStr, wxFD_SAVE | wxFD_PREVIEW | wxFD_OVERWRITE_PROMPT);
|
||||||
if(dlg.ShowModal() == wxID_OK) {
|
if(dlg.ShowModal() == wxID_OK) {
|
||||||
pthread_mutex_lock(&this->logical->ng->mut);
|
pthread_mutex_lock(&this->logical->ng->mut);
|
||||||
@ -679,28 +679,29 @@ GrNode::GrNode(NodeGraph *parent) : wxPanel(parent, wxID_ANY, {0, 0}, {175, 80})
|
|||||||
} else if(sinks[p].type >= Port::Type::VEC1 && sinks[p].type <= Port::Type::VEC4) {
|
} else if(sinks[p].type >= Port::Type::VEC1 && sinks[p].type <= Port::Type::VEC4) {
|
||||||
auto ctrls = std::make_shared<std::vector<wxTextCtrl*>>();
|
auto ctrls = std::make_shared<std::vector<wxTextCtrl*>>();
|
||||||
for(int i = 0; i <= (int) sinks[p].type - (int) Port::Type::VEC1; i++) {
|
for(int i = 0; i <= (int) sinks[p].type - (int) Port::Type::VEC1; i++) {
|
||||||
wxTextCtrl *tc = new wxTextCtrl(GetParent(), wxID_ANY, wxString::Format("%f", this->logical->sinks[p].data.vec4[i]), GetParent()->ScreenToClient(ClientToScreen({5 + 60 * i, (p + 1) * 20})));
|
wxTextCtrl *tc = new wxTextCtrl(GetParent(), wxID_ANY, wxString::Format("%f", this->logical->sinks[p].data.vec4[i]), GetParent()->ScreenToClient(ClientToScreen({5 + 60 * i, (p + 1) * 20})), wxDefaultSize, wxTE_PROCESS_ENTER);
|
||||||
tc->Bind(wxEVT_KEY_DOWN, [=](wxKeyEvent &ev){
|
tc->Bind(wxEVT_TEXT_ENTER, [=](wxCommandEvent &ev){
|
||||||
if(ev.GetKeyCode() == WXK_RETURN) {
|
double d;
|
||||||
double d;
|
if(tc->GetValue().ToDouble(&d)) {
|
||||||
if(tc->GetValue().ToDouble(&d)) {
|
pthread_mutex_lock(&this->logical->ng->mut);
|
||||||
pthread_mutex_lock(&this->logical->ng->mut);
|
|
||||||
|
|
||||||
CHiValue newv = *CHi_Crawl(&this->logical->sinks[p]);
|
|
||||||
newv.type = CUTIHI_VAL_VEC4;
|
|
||||||
newv.data.vec4[i] = d;
|
|
||||||
CHi_ConfigureSink(this->logical, p, newv);
|
|
||||||
|
|
||||||
auto it = std::find(ctrls->begin(), ctrls->end(), tc);
|
CHiValue newv = *CHi_Crawl(&this->logical->sinks[p]);
|
||||||
ctrls->operator[]((it - ctrls->begin() + 1) % ctrls->size())->SetFocus();
|
newv.type = CUTIHI_VAL_VEC4;
|
||||||
ctrls->erase(it);
|
newv.data.vec4[i] = d;
|
||||||
|
CHi_ConfigureSink(this->logical, p, newv);
|
||||||
CallAfter([tc](){tc->Destroy();});
|
|
||||||
parent->Dirtify(this);
|
auto it = std::find(ctrls->begin(), ctrls->end(), tc);
|
||||||
|
ctrls->operator[]((it - ctrls->begin() + 1) % ctrls->size())->SetFocus();
|
||||||
pthread_mutex_unlock(&this->logical->ng->mut);
|
ctrls->erase(it);
|
||||||
}
|
|
||||||
} else if(ev.GetKeyCode() == WXK_TAB) {
|
CallAfter([tc](){tc->Destroy();});
|
||||||
|
parent->Dirtify(this);
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&this->logical->ng->mut);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tc->Bind(wxEVT_KEY_DOWN, [=](wxKeyEvent &ev){
|
||||||
|
if(ev.GetKeyCode() == WXK_TAB) {
|
||||||
ctrls->operator[]((i + ctrls->size() + (wxGetKeyState(WXK_SHIFT) ? -1 : 1)) % ctrls->size())->SetFocus();
|
ctrls->operator[]((i + ctrls->size() + (wxGetKeyState(WXK_SHIFT) ? -1 : 1)) % ctrls->size())->SetFocus();
|
||||||
|
|
||||||
parent->Dirtify(this);
|
parent->Dirtify(this);
|
||||||
@ -710,7 +711,7 @@ GrNode::GrNode(NodeGraph *parent) : wxPanel(parent, wxID_ANY, {0, 0}, {175, 80})
|
|||||||
}
|
}
|
||||||
ctrls->operator[](0)->SetFocus();
|
ctrls->operator[](0)->SetFocus();
|
||||||
} else if(sinks[p].type == Port::Type::TEXT) {
|
} else if(sinks[p].type == Port::Type::TEXT) {
|
||||||
wxTextCtrl *ctrl = new wxTextCtrl(GetParent(), wxID_ANY, this->logical->sinks[p].data.text, GetParent()->ScreenToClient(ClientToScreen({5, (p + 1) * 26})));
|
wxTextCtrl *ctrl = new wxTextCtrl(GetParent(), wxID_ANY, this->logical->sinks[p].data.text, GetParent()->ScreenToClient(ClientToScreen({5, (p + 1) * 26})), wxDefaultSize, wxTE_PROCESS_ENTER);
|
||||||
ctrl->SetValue(wxString{CHi_Crawl(&this->logical->sinks[p])->data.text});
|
ctrl->SetValue(wxString{CHi_Crawl(&this->logical->sinks[p])->data.text});
|
||||||
ctrl->SetFocus();
|
ctrl->SetFocus();
|
||||||
ctrl->Bind(wxEVT_KILL_FOCUS, [=](wxFocusEvent &ev){
|
ctrl->Bind(wxEVT_KILL_FOCUS, [=](wxFocusEvent &ev){
|
||||||
@ -727,21 +728,19 @@ GrNode::GrNode(NodeGraph *parent) : wxPanel(parent, wxID_ANY, {0, 0}, {175, 80})
|
|||||||
|
|
||||||
pthread_mutex_unlock(&this->logical->ng->mut);
|
pthread_mutex_unlock(&this->logical->ng->mut);
|
||||||
});
|
});
|
||||||
ctrl->Bind(wxEVT_KEY_DOWN, [=](wxKeyEvent &ev){
|
ctrl->Bind(wxEVT_TEXT_ENTER, [=](wxCommandEvent &ev){
|
||||||
if(ev.GetKeyCode() == WXK_RETURN) {
|
pthread_mutex_lock(&this->logical->ng->mut);
|
||||||
pthread_mutex_lock(&this->logical->ng->mut);
|
|
||||||
|
CHiValue newv = {};
|
||||||
CHiValue newv = {};
|
newv.type = CUTIHI_VAL_TEXT;
|
||||||
newv.type = CUTIHI_VAL_TEXT;
|
char *c = (char*) malloc(ctrl->GetValue().Len() + 1);
|
||||||
char *c = (char*) malloc(ctrl->GetValue().Len() + 1);
|
memcpy(c, ctrl->GetValue().c_str(), ctrl->GetValue().Len() + 1);
|
||||||
memcpy(c, ctrl->GetValue().c_str(), ctrl->GetValue().Len() + 1);
|
newv.data.text = c;
|
||||||
newv.data.text = c;
|
CHi_ConfigureSink(this->logical, p, newv);
|
||||||
CHi_ConfigureSink(this->logical, p, newv);
|
CallAfter([ctrl](){ctrl->Destroy();});
|
||||||
CallAfter([ctrl](){ctrl->Destroy();});
|
parent->Dirtify(this);
|
||||||
parent->Dirtify(this);
|
|
||||||
|
pthread_mutex_unlock(&this->logical->ng->mut);
|
||||||
pthread_mutex_unlock(&this->logical->ng->mut);
|
|
||||||
} else ev.Skip();
|
|
||||||
});
|
});
|
||||||
} else if(sinks[p].type == Port::Type::MIC_SOURCE) {
|
} else if(sinks[p].type == Port::Type::MIC_SOURCE) {
|
||||||
std::vector<wxString> choices;
|
std::vector<wxString> choices;
|
||||||
@ -790,6 +789,26 @@ GrNode::GrNode(NodeGraph *parent) : wxPanel(parent, wxID_ANY, {0, 0}, {175, 80})
|
|||||||
}
|
}
|
||||||
|
|
||||||
CHi_Window_FreeList(wbuf);
|
CHi_Window_FreeList(wbuf);
|
||||||
|
} else if(sinks[p].type == Port::Type::CHECKBOX) {
|
||||||
|
wxCheckBox *cb = new wxCheckBox(this, wxID_ANY, sinks[p].name);
|
||||||
|
cb->SetValue((bool) this->logical->sinks[p].data.vec4[0]);
|
||||||
|
cb->SetFocus();
|
||||||
|
cb->Bind(wxEVT_KILL_FOCUS, [=](wxFocusEvent &ev){
|
||||||
|
pthread_mutex_lock(&this->logical->ng->mut);
|
||||||
|
|
||||||
|
CHiValue newv = {};
|
||||||
|
newv.type = CUTIHI_VAL_VEC4;
|
||||||
|
newv.data.vec4[0] = cb->IsChecked();
|
||||||
|
newv.data.vec4[1] = cb->IsChecked();
|
||||||
|
newv.data.vec4[2] = cb->IsChecked();
|
||||||
|
newv.data.vec4[3] = cb->IsChecked();
|
||||||
|
CHi_ConfigureSink(this->logical, p, newv);
|
||||||
|
parent->Dirtify(this);
|
||||||
|
|
||||||
|
CallAfter([cb](){cb->Destroy();});
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&this->logical->ng->mut);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -51,7 +51,7 @@ struct GrNode : wxPanel {
|
|||||||
struct Port {
|
struct Port {
|
||||||
wxString name;
|
wxString name;
|
||||||
enum class Type {
|
enum class Type {
|
||||||
NONE, FILE_OPEN, COLOR, VEC1, VEC2, VEC3, VEC4, TEXT, SAMPLE, FILE_SAVE, MIC_SOURCE, WINDOW_SOURCE
|
NONE, FILE_OPENING, COLOR, VEC1, VEC2, VEC3, VEC4, TEXT, SAMPLE, FILE_SAVING, MIC_SOURCE, WINDOW_SOURCE, CHECKBOX
|
||||||
} type;
|
} type;
|
||||||
bool separator;
|
bool separator;
|
||||||
|
|
||||||
|
@ -6,6 +6,9 @@ Frame *globaldis;
|
|||||||
|
|
||||||
struct App : wxApp {
|
struct App : wxApp {
|
||||||
virtual bool OnInit() {
|
virtual bool OnInit() {
|
||||||
|
#if wxCHECK_VERSION(3, 3, 0)
|
||||||
|
SetAppearance(Appearance::System);
|
||||||
|
#endif
|
||||||
(new Frame())->Show(true);
|
(new Frame())->Show(true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -259,8 +259,8 @@ Timeline::Timeline(struct Frame *parent) : wxPanel(parent, wxID_ANY) {
|
|||||||
|
|
||||||
switch(sinks[i].type) {
|
switch(sinks[i].type) {
|
||||||
case GrNode::Port::Type::TEXT:
|
case GrNode::Port::Type::TEXT:
|
||||||
case GrNode::Port::Type::FILE_OPEN:
|
case GrNode::Port::Type::FILE_OPENING:
|
||||||
case GrNode::Port::Type::FILE_SAVE:
|
case GrNode::Port::Type::FILE_SAVING:
|
||||||
SetToolTip(wxString{val->text});
|
SetToolTip(wxString{val->text});
|
||||||
break;
|
break;
|
||||||
case GrNode::Port::Type::VEC1:
|
case GrNode::Port::Type::VEC1:
|
||||||
|
Loading…
Reference in New Issue
Block a user