Compare commits

..

No commits in common. "8b78f0cdf70807c39a51cb0f7adbedda4357883c" and "aff60df9da0aacbe6a0e5fc10cf4f18d1277f2de" have entirely different histories.

20 changed files with 204 additions and 658 deletions

3
.gitignore vendored
View File

@ -3,6 +3,3 @@ tests
*.webm
/cuticle
*.so
*.dll
*.exe

View File

@ -1,26 +1,6 @@
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 -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
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
LDFLAGS := -lwebm -lpng -lvpx -lsail -lsail-manip `pkg-config --libs pango opus libv4l2` -lportaudio -lXtst -lrtmp -lfdk-aac -leebie -lscreen_capture_lite_shared
ifneq ($(RELEASE),0)
CXXFLAGS := $(CXXFLAGS) -O0 -gdwarf-2 -DMTR_ENABLED
@ -28,29 +8,24 @@ else
CXXFLAGS := $(CXXFLAGS) -O3 -fopenmp -DMTR_ENABLED
endif
ifneq ($(SANITIZE),0)
else
CXXFLAGS := -fsanitize=address $(CXXFLAGS)
endif
all:
$(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_C) $(LDFLAGS)
$(CXX) $(CXXFLAGS) -std=c++17 -shared -c -o window.o hi/window.cpp $(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 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 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 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 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 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 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 serialize.o hi/serialize.c $(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)
$(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)
$(CXX) $(CXXFLAGS) $(WXCFLAGS) -std=c++11 -o cuticle ui/main.cpp ui/frame.cpp ui/textctrl.cpp ui/timeline.cpp -L./ -lcutihi $(LDFLAGS) $(WXLDFLAGS)
$(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`

View File

@ -12,7 +12,7 @@ CUTIVIS CHiImage* CHi_Image_New(uint8_t bpc, uint8_t channels, uint16_t stride,
img->width = width;
img->height = height;
if(data) img->data16 = data;
else img->data16 = _mm_malloc(bpc * stride * height + 16, 16);
else img->data16 = _mm_malloc(bpc * stride * height, 16);
img->owned = !data;
assert(stride % 16 == 0);

View File

@ -219,7 +219,7 @@ _PS_CONST(cephes_log_q2, 0.693359375);
*/
inline __m128 my_movehl_ps(__m128 a, const __m128 b) {
__asm__ (
asm (
"movhlps %2,%0\n\t"
: "=x" (a)
: "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
inline __m128 my_cmplt_ps(__m128 a, const __m128 b) {
__asm__ (
asm (
"cmpltps %2,%0\n\t"
: "=x" (a)
: "0" (a), "x"(b)
@ -237,7 +237,7 @@ inline __m128 my_cmplt_ps(__m128 a, const __m128 b) {
return a;
}
inline __m128 my_cmpgt_ps(__m128 a, const __m128 b) {
__asm__ (
asm (
"cmpnleps %2,%0\n\t"
: "=x" (a)
: "0" (a), "x"(b)
@ -245,7 +245,7 @@ inline __m128 my_cmpgt_ps(__m128 a, const __m128 b) {
return a;
}
inline __m128 my_cmpeq_ps(__m128 a, const __m128 b) {
__asm__ (
asm (
"cmpeqps %2,%0\n\t"
: "=x" (a)
: "0" (a), "x"(b)

View File

@ -24,15 +24,8 @@
#include<stdio.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<arpa/inet.h>
#include<sys/random.h>
#endif
#define NALLENSZ 4
@ -279,7 +272,7 @@ struct Internal {
size_t videoTrack, audioTrack;
size_t currentClusterTimecode;
bool beforeFirstCluster;
bool codecPrivatesFound;
CHiBSFrames *audioBacklog;
@ -322,13 +315,12 @@ static int muxmkv_perform(CHiPubNode *pubn) {
size_t nextTimestamp = next_timestamp(this);
bool shouldUpdateCluster = this->beforeFirstCluster || (this->videoBacklog && this->videoBacklog->count && (this->videoBacklog->data[0].flags & CUTIHI_BS_FLAG_KEY)) || (nextTimestamp - this->currentClusterTimecode > 15000);
bool shouldUpdateCluster = (this->videoBacklog && this->videoBacklog->count && (this->videoBacklog->data[0].flags & CUTIHI_BS_FLAG_KEY)) || (nextTimestamp - this->currentClusterTimecode > 15000);
if(shouldUpdateCluster) {
if(!this->beforeFirstCluster) {
if(this->currentClusterTimecode != 0) {
ebml_writer_pop(&this->wr);
}
this->beforeFirstCluster = false;
// Cluster
ebml_writer_push(&this->wr, 0x1F43B675);
@ -501,14 +493,14 @@ static int muxmkv_perform(CHiPubNode *pubn) {
assert(this->audioBacklog->data[0].flags & CUTIHI_BS_SETUP_PACKET);
if(CHi_Crawl(&pubn->sinks[1])->type == CUTIHI_VAL_OPUSBS) {
if(CHi_Crawl(&pubn->sinks[0])->type == CUTIHI_VAL_OPUSBS) {
ebml_writer_put(&this->wr, 0x86, EBML_STRING, (EBMLPrimitive) {.string = "A_OPUS"});
CHiBSFrame *opusHead = &this->audioBacklog->data[0];
// CodecPrivate
ebml_writer_put(&this->wr, 0x63A2, EBML_BINARY, (EBMLPrimitive) {.binary = {.length = opusHead->sz, .ptr = opusHead->ptr}});
} else if(CHi_Crawl(&pubn->sinks[1])->type == CUTIHI_VAL_AACBS) {
} else if(CHi_Crawl(&pubn->sinks[0])->type == CUTIHI_VAL_AACBS) {
ebml_writer_put(&this->wr, 0x86, EBML_STRING, (EBMLPrimitive) {.string = "A_AAC/MPEG2/LC"});
}
@ -555,7 +547,6 @@ static int muxmkv_start(CHiPubNode *pubn) {
this->currentClusterTimecode = 0;
this->codecPrivatesFound = false;
this->beforeFirstCluster = true;
int trackNum = 1;

View File

@ -2,6 +2,8 @@
#include<stdlib.h>
#include"img.h"
#include<sail/sail.h>
#include<sail-manip/sail-manip.h>
#include<assert.h>
#include<string.h>
#include<tmmintrin.h>
@ -19,9 +21,6 @@
#include"node_internal.h"
#define STB_IMAGE_IMPLEMENTATION
#include<stb_image.h>
CUTIVIS CHiNodeGraph *CHi_NewNodeGraph() {
static int inited = 0;
if(!inited) {
@ -546,26 +545,32 @@ static int image_perform(CHiPubNode *node) {
}
if(!internal->cacheImg) {
size_t w = 0, h = 0, n = 4;
float *data = stbi_loadf(fn, &w, &h, &n, 4);
if(!data) {
struct sail_image *simg;
if(sail_load_from_file(fn, &simg) != SAIL_OK) {
CHi_AddError(node, "invalid file", 0);
return 1;
}
CHiImage *img = CHi_Image_New(2, 4, (w * 8 + 15) & ~15, w, h, NULL);
struct sail_image *cimg;
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;
for(size_t y = 0; y < img->height; y++) {
for(size_t x = 0; x < img->width; x++) {
__m128 pixels = _mm_loadu_ps((__m128*) &data[w * y + x]);
pixels = apply_gamma_ps(pixels, _mm_set_ps(1.0f, 2.2f, 2.2f, 2.2f));
__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);
for(size_t x = 0; x < img->stride; x += 16) {
__m128i pixels = _mm_load_si128((__m128i*) ((uintptr_t) img->data16 + y * img->stride + x));
pixels = apply_gamma_epi16(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);
}
}
sail_destroy_image(cimg);
free(internal->cachePath);
internal->cachePath = strdup(fn);
}

View File

@ -33,7 +33,7 @@ static int encodeopus_perform(CHiPubNode *pubn) {
n->pcmSamples += newpcm->width;
}
CHiBSFrames *frames = calloc(1, sizeof(*frames));
CHiBSFrames *frames = malloc(sizeof(*frames));
frames->count = 0;
if(!n->firstFrame) {

View File

@ -1,149 +0,0 @@
#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;
}

View File

@ -9,12 +9,8 @@
#include<librtmp/rtmp.h>
#include<librtmp/log.h>
#ifdef _WIN32
#include<winsock2.h>
#else
#include<arpa/inet.h>
#include<sys/select.h>
#endif
#include"img.h"

View File

@ -218,8 +218,8 @@ static void ebml_exit_callback(EBMLReader *ebml) {
n = CHi_EncodeVP8();
} else if(type == CUTIHI_T('CEnc','GVP9')) {
n = CHi_EncodeVP9();
// } else if(type == CUTIHI_T('CExp','Webm')) {
// n = CHi_MuxWebm();
} else if(type == CUTIHI_T('CExp','Webm')) {
n = CHi_MuxWebm();
} else if(type == CUTIHI_T('CKey','hook')) {
n = CHi_Keyhook();
} else if(type == CUTIHI_T('CKey','hook')) {

View File

@ -1,20 +1,130 @@
#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_NONE;
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;

View File

@ -1,136 +0,0 @@
#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;
}

0
hi/window.c Normal file
View File

View File

@ -4,7 +4,6 @@
#include<ScreenCapture.h>
#include<mutex>
#include<atomic>
#include<tmmintrin.h>
#include<smmintrin.h>
@ -27,7 +26,6 @@ typedef struct {
std::mutex mut;
std::vector<CHiImage*> images;
std::atomic<bool> ignoreAlpha;
} CHiWindowNode;
static int window_perform(CHiPubNode *n) {
@ -35,9 +33,6 @@ static int window_perform(CHiPubNode *n) {
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;
if(w->lastWindowString == nullptr || strcmp(w->lastWindowString, expectedTitle)) {
@ -57,8 +52,6 @@ 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);
memset(new_image->data8, 0, new_image->stride * new_image->height);
bool ignoreAlpha = w->ignoreAlpha.load();
#pragma omp parallel for
for(size_t y = 0; y < new_image->height; y++) {
uint8_t buf[16] = {};
@ -67,9 +60,6 @@ static int window_perform(CHiPubNode *n) {
__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));
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));
_mm_store_si128((__m128i*) ((uintptr_t) new_image->data8 + y * new_image->stride + x * 8), c);
}
@ -113,7 +103,7 @@ CUTIVIS CHiPubNode *CHi_Window() {
n->pub.Perform = window_perform;
n->pub.Destroy = window_destroy;
n->pub.sinkCount = 1;
n->pub.sinks = (CHiValue*) calloc(sizeof(*n->pub.sinks), 2);
n->pub.sinks = (CHiValue*) calloc(sizeof(*n->pub.sinks), 1);
n->pub.sourceCount = 1;
n->pub.sources = (CHiValue*) calloc(sizeof(*n->pub.sources), 1);

View File

@ -1,211 +0,0 @@
#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((const char*) 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 = (char*) shmat(w->shminfo.shmid, 0, 0);
w->shminfo.readOnly = False;
XShmAttach(d, &w->shminfo);
w->vcache = CHi_Image_New(2, 4, (8 * attrs.width + 15) & ~15, 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);
bool ignoreAlpha = CHi_Crawl(&w->pub.sinks[1])->data.vec4[0] != 0;
// 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));
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));
_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 = (CHiWindowNode*) 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 = (CHiWindowNode*) 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 = (CHiValue*) calloc(sizeof(*n->pub.sinks), 2);
n->pub.sourceCount = 1;
n->pub.sources = (CHiValue*) calloc(sizeof(*n->pub.sources), 1);
n->xcache = 0;
n->vcache = NULL;
return &n->pub;
}
// All of the following are ews
struct WindowListDatum {
Window handle;
char name[128];
};
CUTIVIS size_t CHi_Window_GetList(void **buf) {
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) {
WindowListDatum *data = (WindowListDatum*) calloc(numItems, sizeof(*data));
size_t successfulWindows = 0;
for(size_t i = 0; i < numItems; i++) {
status = XGetWMName(d, list[i], &windowName);
if(status >= Success) {
data[successfulWindows].handle = list[i];
strncpy(data[successfulWindows].name, (char*) windowName.value, sizeof(data[successfulWindows].name));
successfulWindows++;
}
}
XFree(list);
*buf = data;
return successfulWindows;
}
*buf = nullptr;
return 0;
}
CUTIVIS const char *CHi_Window_GetName(void *buf, size_t i) {
return ((WindowListDatum*) buf)[i].name;
}
CUTIVIS size_t CHi_Window_GetHandle(void *buf, size_t i) {
return ((WindowListDatum*) buf)[i].handle;
}
CUTIVIS void CHi_Window_FreeList(void *buf) {
free(buf);
}

View File

@ -135,19 +135,19 @@ static void ShapeGrNode(GrNode *gn) {
gn->sinks.push_back({" Size", GrNode::Port::Type::VEC1, true});
}
} else if(gn->logical->type == CUTIHI_T('CIma','ge ')) {
gn->sinks = {{"Filepath", GrNode::Port::Type::FILE_OPENING}};
gn->sinks = {{"Filepath", GrNode::Port::Type::FILE_OPEN}};
gn->sources = {{"Sample", GrNode::Port::Type::SAMPLE}};
} else if(gn->logical->type == CUTIHI_T('CWin','dow ')) {
gn->sinks = {{"Name", GrNode::Port::Type::WINDOW_SOURCE}, {"Ignore Alpha", GrNode::Port::Type::CHECKBOX}};
gn->sinks = {{"Name", GrNode::Port::Type::WINDOW_SOURCE}};
gn->sources = {{"Sample", GrNode::Port::Type::SAMPLE}};
} else if(gn->logical->type == CUTIHI_T('CInA','udio')) {
gn->sinks = {{"Source", GrNode::Port::Type::MIC_SOURCE}};
gn->sources = {{"Audio", GrNode::Port::Type::SAMPLE}};
} else if(gn->logical->type == CUTIHI_T('CExp','Wave')) {
gn->sinks = {{"Filename", GrNode::Port::Type::FILE_SAVING}, {"Audio", GrNode::Port::Type::SAMPLE}};
gn->sinks = {{"Filename", GrNode::Port::Type::FILE_SAVE}, {"Audio", GrNode::Port::Type::SAMPLE}};
gn->sources = {};
} else if(gn->logical->type == CUTIHI_T('CMov','ie ')) {
gn->sinks = {{"Filepath", GrNode::Port::Type::FILE_OPENING}, {"Time", GrNode::Port::Type::VEC1}};
gn->sinks = {{"Filepath", GrNode::Port::Type::FILE_OPEN}, {"Time", GrNode::Port::Type::VEC1}};
gn->sources = {{"Sample", GrNode::Port::Type::SAMPLE}, {"Audio", GrNode::Port::Type::SAMPLE}};
} else if(gn->logical->type == CUTIHI_T('CEnc','GVP8')) {
gn->sinks = {{"Sample", GrNode::Port::Type::SAMPLE}};
@ -159,7 +159,7 @@ static void ShapeGrNode(GrNode *gn) {
gn->sinks = {{"Sample", GrNode::Port::Type::SAMPLE}};
gn->sources = {{"Bitstream"}};
} else if(gn->logical->type == CUTIHI_T('CExp','Webm')) {
gn->sinks = {{"Video Bitstream"}, {"Audio Bitstream"}, {"Filename", GrNode::Port::Type::FILE_SAVING}};
gn->sinks = {{"Video Bitstream"}, {"Audio Bitstream"}, {"Filename", GrNode::Port::Type::FILE_SAVE}};
gn->sources = {};
} else if(gn->logical->type == CUTIHI_T('CKey','hook')) {
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->sources = {{"Bitstream"}};
} else if(gn->logical->type == CUTIHI_T('CExp','Mkv ')) {
gn->sinks = {{"Video Bitstream"}, {"Audio Bitstream"}, {"Filename", GrNode::Port::Type::FILE_SAVING}};
gn->sinks = {{"Video Bitstream"}, {"Audio Bitstream"}, {"Filename", GrNode::Port::Type::FILE_SAVE}};
gn->sources = {};
}
@ -484,8 +484,8 @@ GrNode::GrNode(NodeGraph *parent) : wxPanel(parent, wxID_ANY, {0, 0}, {175, 80})
int y = 13;
int i = 0;
for(Port &p : sinks) {
wxColour col = p.type == GrNode::Port::Type::FILE_OPENING ? wxColour{255, 0, 0}
: p.type == GrNode::Port::Type::FILE_SAVING ? wxColour{255, 0, 0}
wxColour col = p.type == GrNode::Port::Type::FILE_OPEN ? wxColour{255, 0, 0}
: p.type == GrNode::Port::Type::FILE_SAVE ? wxColour{255, 0, 0}
: 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::TEXT ? wxColour{255, 255, 0}
@ -512,8 +512,8 @@ GrNode::GrNode(NodeGraph *parent) : wxPanel(parent, wxID_ANY, {0, 0}, {175, 80})
y = 13;
i = 0;
for(Port &p : sources) {
wxColour col = p.type == GrNode::Port::Type::FILE_OPENING ? wxColour{255, 0, 0}
: p.type == GrNode::Port::Type::FILE_SAVING ? wxColour{255, 0, 0}
wxColour col = p.type == GrNode::Port::Type::FILE_OPEN ? wxColour{255, 0, 0}
: p.type == GrNode::Port::Type::FILE_SAVE ? wxColour{255, 0, 0}
: 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::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);
}
} else if(sinks[p].type == Port::Type::FILE_OPENING) {
} else if(sinks[p].type == Port::Type::FILE_OPEN) {
wxFileDialog dlg(this, wxFileSelectorPromptStr, wxEmptyString, wxEmptyString, wxFileSelectorDefaultWildcardStr, wxFD_OPEN | wxFD_PREVIEW);
if(dlg.ShowModal() == wxID_OK) {
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);
}
} else if(sinks[p].type == Port::Type::FILE_SAVING) {
} else if(sinks[p].type == Port::Type::FILE_SAVE) {
wxFileDialog dlg(this, wxFileSelectorPromptStr, wxEmptyString, wxEmptyString, wxFileSelectorDefaultWildcardStr, wxFD_SAVE | wxFD_PREVIEW | wxFD_OVERWRITE_PROMPT);
if(dlg.ShowModal() == wxID_OK) {
pthread_mutex_lock(&this->logical->ng->mut);
@ -679,29 +679,28 @@ 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) {
auto ctrls = std::make_shared<std::vector<wxTextCtrl*>>();
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})), wxDefaultSize, wxTE_PROCESS_ENTER);
tc->Bind(wxEVT_TEXT_ENTER, [=](wxCommandEvent &ev){
double d;
if(tc->GetValue().ToDouble(&d)) {
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);
ctrls->operator[]((it - ctrls->begin() + 1) % ctrls->size())->SetFocus();
ctrls->erase(it);
CallAfter([tc](){tc->Destroy();});
parent->Dirtify(this);
pthread_mutex_unlock(&this->logical->ng->mut);
}
});
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})));
tc->Bind(wxEVT_KEY_DOWN, [=](wxKeyEvent &ev){
if(ev.GetKeyCode() == WXK_TAB) {
if(ev.GetKeyCode() == WXK_RETURN) {
double d;
if(tc->GetValue().ToDouble(&d)) {
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);
ctrls->operator[]((it - ctrls->begin() + 1) % ctrls->size())->SetFocus();
ctrls->erase(it);
CallAfter([tc](){tc->Destroy();});
parent->Dirtify(this);
pthread_mutex_unlock(&this->logical->ng->mut);
}
} else if(ev.GetKeyCode() == WXK_TAB) {
ctrls->operator[]((i + ctrls->size() + (wxGetKeyState(WXK_SHIFT) ? -1 : 1)) % ctrls->size())->SetFocus();
parent->Dirtify(this);
@ -711,7 +710,7 @@ GrNode::GrNode(NodeGraph *parent) : wxPanel(parent, wxID_ANY, {0, 0}, {175, 80})
}
ctrls->operator[](0)->SetFocus();
} 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})), wxDefaultSize, wxTE_PROCESS_ENTER);
wxTextCtrl *ctrl = new wxTextCtrl(GetParent(), wxID_ANY, this->logical->sinks[p].data.text, GetParent()->ScreenToClient(ClientToScreen({5, (p + 1) * 26})));
ctrl->SetValue(wxString{CHi_Crawl(&this->logical->sinks[p])->data.text});
ctrl->SetFocus();
ctrl->Bind(wxEVT_KILL_FOCUS, [=](wxFocusEvent &ev){
@ -728,19 +727,21 @@ GrNode::GrNode(NodeGraph *parent) : wxPanel(parent, wxID_ANY, {0, 0}, {175, 80})
pthread_mutex_unlock(&this->logical->ng->mut);
});
ctrl->Bind(wxEVT_TEXT_ENTER, [=](wxCommandEvent &ev){
pthread_mutex_lock(&this->logical->ng->mut);
CHiValue newv = {};
newv.type = CUTIHI_VAL_TEXT;
char *c = (char*) malloc(ctrl->GetValue().Len() + 1);
memcpy(c, ctrl->GetValue().c_str(), ctrl->GetValue().Len() + 1);
newv.data.text = c;
CHi_ConfigureSink(this->logical, p, newv);
CallAfter([ctrl](){ctrl->Destroy();});
parent->Dirtify(this);
pthread_mutex_unlock(&this->logical->ng->mut);
ctrl->Bind(wxEVT_KEY_DOWN, [=](wxKeyEvent &ev){
if(ev.GetKeyCode() == WXK_RETURN) {
pthread_mutex_lock(&this->logical->ng->mut);
CHiValue newv = {};
newv.type = CUTIHI_VAL_TEXT;
char *c = (char*) malloc(ctrl->GetValue().Len() + 1);
memcpy(c, ctrl->GetValue().c_str(), ctrl->GetValue().Len() + 1);
newv.data.text = c;
CHi_ConfigureSink(this->logical, p, newv);
CallAfter([ctrl](){ctrl->Destroy();});
parent->Dirtify(this);
pthread_mutex_unlock(&this->logical->ng->mut);
} else ev.Skip();
});
} else if(sinks[p].type == Port::Type::MIC_SOURCE) {
std::vector<wxString> choices;
@ -789,26 +790,6 @@ GrNode::GrNode(NodeGraph *parent) : wxPanel(parent, wxID_ANY, {0, 0}, {175, 80})
}
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);
});
}
}
});
@ -992,7 +973,7 @@ void ImageViewer::SetImage(CHiImage *chim) {
ResizeImage(siez);
}
void ImageViewer::ResizeImage(float size) {
float w = size, h = (float) bufH / bufW * size;
float w = size, h = (float) bufH / bufW * siez;
if(w <= 1 || h <= 1) {
return;

View File

@ -51,7 +51,7 @@ struct GrNode : wxPanel {
struct Port {
wxString name;
enum class Type {
NONE, FILE_OPENING, COLOR, VEC1, VEC2, VEC3, VEC4, TEXT, SAMPLE, FILE_SAVING, MIC_SOURCE, WINDOW_SOURCE, CHECKBOX
NONE, FILE_OPEN, COLOR, VEC1, VEC2, VEC3, VEC4, TEXT, SAMPLE, FILE_SAVE, MIC_SOURCE, WINDOW_SOURCE
} type;
bool separator;

View File

@ -6,9 +6,6 @@ Frame *globaldis;
struct App : wxApp {
virtual bool OnInit() {
#if wxCHECK_VERSION(3, 3, 0)
SetAppearance(Appearance::System);
#endif
(new Frame())->Show(true);
return true;
}

View File

@ -259,8 +259,8 @@ Timeline::Timeline(struct Frame *parent) : wxPanel(parent, wxID_ANY) {
switch(sinks[i].type) {
case GrNode::Port::Type::TEXT:
case GrNode::Port::Type::FILE_OPENING:
case GrNode::Port::Type::FILE_SAVING:
case GrNode::Port::Type::FILE_OPEN:
case GrNode::Port::Type::FILE_SAVE:
SetToolTip(wxString{val->text});
break;
case GrNode::Port::Type::VEC1: