Save
Saving
  • guluting

    给一段使用glfw创建窗口的代码:

    const GLuint SCREEN_WIDTH = 800;
    const GLuint SCREEN_HEIGHT = 600;
    GLFWwindow *window = glfwCreateWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "GuaikDemo", nullptr, nullptr);
    

    我想创建一个800 * 600 像素的窗口程序,然后使用默认的帧缓冲可以正常的绘制出三角形或者纹理。

    但是如果使用glGenFramebuffers等函数创建帧缓冲做后期处理,在MacOS中就出现问题了(只显示了左下角的1/4图像),效果图如下所示,在MacOS中仅显示部分图像,但是拖动到扩展屏后就一切正常。


    7CB72945-B274-421E-A1A6-B1E3364E9438.gif


    这是为什么呢?既然是像素问题,那就把一些数据打印出来看看吧,在glfwCreateWindow之后使用glfwGetFramebufferSize函数把窗口的长宽像素打印出来看下

    int ScreenX;
    int ScreenY;
    glfwGetFramebufferSize(window, &ScreenX, &ScreenY);
    std::cout << "Width: " << ScreenX << " Height: " << ScreenY << std::endl;
    

    结果跟想的一样,虽然设置了800 * 600,但是打印结果是 Width: 1600 Height: 1200,都翻了一倍,所以最后在使用像素的任何地方都用glfwGetFramebufferSize获取到的宽高作为参数,并且glViewport也设置了同样的像素。

    // 渲染
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glViewport(0, 0, ScreenX, ScreenY);
    ......
    glfwSwapBuffers(window);
    

    问题完美解决。


    但是,在MacOS中显示正常了,拖动到扩展屏显示却出现异常,要解决这个问题的话应该检测当前所激活的显示设备,然后动态设置像素参数并调用glViewport。

    posted in GuaiK实验室 read more
  • guluting

    设计理念:

    LOGO图形设计及字体设计,LOGO以乌鸦为设计原型,将带巫师帽的乌鸦拟人化成黑衣人形象,以怪化鸦及科学怪鸦为主轴。字体设计以乌鸦羽翼及乌鸦爪痕为原型。整体以黑白颜色为主,黑乌鸦及白底色,亦可白乌鸦及黑底色使用。

    设计师:

    @Joy

    版权申明:

    以下图案已注册版权保护,LOGO及字体设计可以免费非商业使用,若要使用需保留GuaiK、设计者及使用出处,否则视为侵权。


    白底LOGO

    GuaiK_white_画板 1.png


    黑底LOGO

    GuaiK_black_画板 1.png

    posted in GuaiK新闻 read more
  • guluting

    nginx configuration which uses SSL

    ### redirects http requests to https
    server {
        listen 80;
        server_name forum.example.org;
    
        return 302 https://$server_name$request_uri;
    }
    
    ### the https server
    server {
        # listen on ssl, deliver with speedy if possible
        listen 443 ssl spdy;
    
        server_name forum.example.org;
    
        # change these paths!
        ssl_certificate /path/to/cert/bundle.crt;
        ssl_certificate_key /path/to/cert/forum.example.org.key;
    
        # enables all versions of TLS, but not SSLv2 or 3 which are weak and now deprecated.
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    
        # disables all weak ciphers
        ssl_ciphers 'AES128+EECDH:AES128+EDH';
    
        ssl_prefer_server_ciphers on;
    
        location / {
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header Host $http_host;
            proxy_set_header X-NginX-Proxy true;
    
            proxy_pass http://127.0.0.1:8888;
            proxy_redirect off;
    
            # Socket.IO Support
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
    }
    

    Nodebb config.json

    {
        "url": "https://xxx.domain.org",
        "secret": "UUID",
        "database": "mongo",
        "port": "8888",
        "mongo": {
            "host": "127.0.0.1",
            "port": "27017",
            "username": "",
            "password": "",
            "database": "nodebb",
            "uri": ""
        }
    }
    

    posted in GuaiK机房 read more
  • guluting

    通过对音频波形文件(PCM格式)进行自相关的计算,检测出音频基音所在的频率,最后通过查表将频率转换成MIDI格式的音符。


    # -*- coding: utf-8 -*-
    import wave
    import pyaudio
    import numpy as np
    import math
    import matplotlib.pyplot as pyplot
    from numpy.fft import rfft, rfftfreq
    import time
    import scipy.signal as signal
    import midi
    from midiutil import MIDIFile
    import pygame
    
    def play_music(music_file):
      clock = pygame.time.Clock()
      try:
        pygame.mixer.music.load(music_file)
        print("Music file {} loaded!".format(music_file))
      except pygame.error:
        print("File {} not found! {}".format(music_file, pygame.get_error()))
        return
      pygame.mixer.music.play()
      # check if playback has finished
      while pygame.mixer.music.get_busy():
        clock.tick(30)
    
    freq = 44100  # audio CD quality
    bitsize = -16  # unsigned 16 bit
    channels = 2  # 1 is mono, 2 is stereo
    buffer = 2048  # number of samples (experiment to get right sound)
    pygame.mixer.init(freq, bitsize, channels, buffer)
    # optional volume 0 to 1.0
    pygame.mixer.music.set_volume(0.8)
    
    
    midi_hz = [27.500, 29.135, 30.868, 32.703, 34.648, 36.708, 38.891,
                    41.203, 43.654, 46.249, 48.999, 51.913, 55.0, 58.270,
                    61.735, 65.406, 69.269, 73.416, 77.782, 82.407, 87.307,
                    92.499, 97.999, 103.83 ,110.00, 116.34, 123.47, 130.81, 138.59,
                    146.83, 155.36, 164.81, 174.61, 185.0, 196.0, 207.65,
                    220.0, 233.08, 246.94, 261.63, 277.18, 293.66, 311.13,
                    329.63, 349.23, 369.99, 392.0, 415.3, 440.0, 466.16,
                    493.88, 523.25, 554.37, 587.33, 622.23, 659.26, 698.46,
                    739.99, 783.99, 830.61, 880.0, 932.33, 987.77, 1046.5,
                    1108.7, 1174.7, 1244.5, 1318.5, 1396.9, 1480.0, 1568.0,
                    1661.2, 1760.0,1864.7, 1975.5, 2093.0, 2217.5, 2349.3,
                    2489.0, 2637.0, 2793.0, 2960.0, 3136.0, 3322.4, 3520.0,
                    3729.3, 3951.1, 4186.0]
    midi_num = [x for x in range(21, 21 + 88)]
    
    
    class Wave:
        def __init__(self, filename):
            self.f = wave.open(filename,"rb")
            self.nchannels, self.sampwidth, self.framerate, self.nframes = self.f.getparams()[0:4]
            print self.nchannels, self.sampwidth, self.framerate, self.nframes
            self.data = self.f.readframes(self.nframes)
            self.f.close()
            self.frame_size = self.sampwidth * self.nchannels
            self.frame_time = 1.0 / self.framerate
            self.len = self.nframes * self.frame_size
            self.player = pyaudio.PyAudio()
            self.stream = self.player.open(format=self.player.get_format_from_width(self.sampwidth),
                    channels=self.nchannels,
                    rate=self.framerate,
                    output=True)
    
        def play(self):
            pos = 0
            while pos + self.frame_size * self.framerate < self.len:
                print "current pos -> {}\t/{}".format(pos + self.frame_size * self.framerate, self.len)
                self.stream.write(self.data[pos:pos + self.frame_size * self.framerate])
                pos += self.frame_size * self.framerate
            print "current pos -> {}\t/{} over!".format(pos + self.frame_size * self.framerate, self.len)
    
    
        def make_spectrum(self, start, duration):
            dtype_map = {1:np.int8, 2:np.int16, 3:'special', 4:np.int32}
            ys = None
            if self.sampwidth not in dtype_map:
                raise ValueError('sampwidth %d unknown' % self.sampwidth)
            if self.sampwidth == 3:
                xs = np.fromstring(self.data, dtype=np.int8).astype(np.int32)
                ys = (xs[2::3] * 256 + xs[1::3]) * 256 + xs[0::3]
            else:
                ys = np.fromstring(self.data, dtype=dtype_map[self.sampwidth])
            print ys
            ys.shape = -1,2
            print ys
            ys = ys.T[0]
            print len(ys)
            start_frame = int(start * self.framerate)
            end_frame = int(start_frame + duration * self.framerate)
            ys = ys[start_frame:end_frame]
            n = len(ys)
            d = 1.0 / self.framerate
            fs = np.fft.rfftfreq(n, d)
            hs = np.fft.rfft(ys)
            hs = hs / (len(hs)) # 归一化处理
            return Spectrum(hs, fs, self.framerate)
    
        def ploat(self):
            wave_data = None
            if self.sampwidth == 1:
                wave_data = np.fromstring(self.data, dtype=np.int8)
            elif self.sampwidth == 2:
                wave_data = np.fromstring(self.data, dtype=np.int16)
            elif self.sampwidth == 3:
                data = []
                for i in range(len(self.data)):
                    if i % 3 == 0: data.append("\0")
                    data.append(self.data[i])
                wave_data = np.fromstring("".join(data), dtype=np.int32)
    
            t = np.arange(0, self.nframes) * self.frame_time
            if self.nchannels == 1:
                wave_data.shape = -1,1
                wave_data = wave_data.T
                pyplot.subplot(1,1,1)
                d = wave_data[0] * 1.0 / max(abs(wave_data[0]))
                pyplot.plot(t, wave_data[0], c="darkorange")
            elif self.nchannels == 2:
                wave_data.shape = -1,2
                wave_data = wave_data.T
                pyplot.subplot(2,1,1)
                d = wave_data[0] * 1.0 / max(abs(wave_data[0]))
                pyplot.plot(t, d, c="darkorange")
                pyplot.subplot(2,1,2)
                d = wave_data[1] * 1.0 / max(abs(wave_data[1]))
                pyplot.plot(t, d, c="g")
            pyplot.xlabel("time (seconds)")
    
    
    def corrcoef(xs, ys):
        return np.corrcoef(xs, ys, ddof=0)[0, 1]
    
    def serial_corr(wave, lag=1):
        n = len(wave)
        y1 = wave[lag:]
        y2 = wave[:n-lag]
        corr = corrcoef(y1, y2)
        return corr
    
    def autocorr(wave):
        lags = range(len(wave)//2)
        corrs = [serial_corr(wave, lag) for lag in lags]
        return lags, corrs
    
    # def autocorr(wave):
    #     lags = range(len(wave))
    #     corrs = np.correlate(wave, wave, mode='same')
    #     return lags, corrs
    
    def GetMidi(hz):
        for index,item in enumerate(midi_hz):
            if hz < midi_hz[0]: return 0
            if hz < item: return midi_num[index-1]
        return 0
    
    def ACFPitch(wave):
        wave_data = np.fromstring(wave.data, dtype=np.int16)
        # b, a = signal.butter(8, 0.02, 'lowpass')
        # wave_data = signal.filtfilt(b, a, wave_data)
        wave_data = signal.medfilt(wave_data, 401)
        wave_data = signal.detrend(wave_data,type='linear')
        frame_size = 4096
        frame_time = round(frame_size / 44100.0, 3)
        step_total = len(wave_data) / frame_size
    
        MyMIDI = MIDIFile(1)
        MyMIDI.addTempo(0, 0, 120)
        degrees = []
        for i in range(step_total-1):
            start = i * frame_size
            lags, corrs = autocorr(wave_data[start:start+frame_size])
            width = np.arange(10,30)
            peaks = signal.find_peaks_cwt(corrs, width)[1:]
            data = [corrs[x] for x in peaks]
            md = 0
            if data:
                index = np.argmax(data)
                hz = 1.0 / (float(lags[peaks[index]]) / 44100)
                md = GetMidi(hz)
            degrees.append(md)
    
        count = 1
        time = 0
        for i in range(len(degrees)-1):
            if degrees[i] == degrees[i+1]: count += 1
            else:
                if degrees[i] !=0:
                    MyMIDI.addNote(0, 0, degrees[i], time, count * frame_time, 100)
                count = 1
            time += frame_time
        if degrees[-1] != 0:
            MyMIDI.addNote(0, 0, degrees[-1], time, count * frame_time, 100)
    
        with open("~/test.mid", "wb") as output_file:
            MyMIDI.writeFile(output_file)
    
    if __name__ == "__main__":
        w = Wave("~/test.wav")
        w.play()
        ACFPitch(w)
        play_music("~/test.mid")
    
    

    posted in GuaiK实验室 read more
  • guluting

    0_1564880258942_box2d_logo.png


    下载文件并进入目录

    git clone -b v2.3.1 https://github.com/erincatto/Box2D.git
    cd Box2D
    

    整理下文件:

    rm -rf ./Contributions
    mv ./Box2D ./tmp
    mv ./tmp/Box2D ./Box2D
    rm -rf ./tmp
    mkdir Lib
    mkdir Include
    

    添加CMakeLists.txt,内容如下:

    cmake_minimum_required(VERSION 2.6)
    
    project(Box2D)
    
    # 若果要改成动态编译,将下面OFF 和 ON的位置对调
    set(BOX2D_BUILD_SHARED OFF)
    set(BOX2D_BUILD_STATIC ON)
    
    
    set(BOX2D_VERSION 2.3.0)
    set(LIB_INSTALL_DIR lib${LIB_SUFFIX})
    
    add_subdirectory(Box2D)
    

    编译安装

    cmake .
    make
    mv ./Box2D/libBox2D.a ./Lib/libBox2D.a
    mv ./Box2D/Box2D.h ./Include/Box2D.h
    mv ./Box2D/Collision ./Include/Collision
    mv ./Box2D/Common ./Include/Common
    mv ./Box2D/Dynamics ./Include/Dynamics
    mv ./Box2D/Rope ./Include/Rope
    rm -rf Box2D
    rm -rf ./cmake*
    rm -rf ./CMake*
    rm -rf Makefile
    

    头文件在Include目录中,静态库在Lib目录中。


    如果你懒得配置的话,这里有我配置好的,直接运行脚本就可以自己编译了:
    https://github.com/guaik/Box2DInstaller.git

    posted in GuaiK实验室 read more
  • guluting

    向量V是通过碰撞检测时计算出的圆心C距离AABB最近位置P的距离,由P-C得到。
    https://bbs.guaik.org/topic/104/碰撞检测算法-圆-aabb


    图中画出了左右方向的碰撞示意,还有上下碰撞没画出来,如果左上角顶点为(0, 0),右下角坐标为800, 600,则当圆在AABB上方的时候V的方向向量为(0,1),因为P点的Y坐标肯定大于圆心Y坐标。同理,当圆在AABB下方的时候方向向量为(0, -1)因为P点的Y坐标小于圆心Y坐标。
    定义方向向量:UP(0, 1) RIGHT(1, 0) DOWN(0, -1) LEFT(-1, 0)
    当球碰撞AABB上边的时候实际计算出的碰撞方向:
    (0, 1) · (0, 1) = 1 // 对应的是UP

    当球碰撞AABB下边的时候实际计算出的碰撞方向:
    (0, -1) · (0, -1) = 1 // 对应的是DOWN

    总结:
    撞击左边:V(1, 0),方向RIGHT
    撞击右边:V(-1, 0),方向LEFT
    撞击上边:V(0, 1),方向UP
    撞击下边:V(0, -1),方向DOWN


    0_1564583835395_WechatIMG161.jpeg

    posted in GuaiK实验室 read more
  • guluting

    先检测当前编译系统是否支持c++11,如果支持的话将"-std=c++11"加入编译参数中。


    include(CheckCXXCompilerFlag)
    CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
    CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
    if(COMPILER_SUPPORTS_CXX11)
            set(CMAKE_CXX_FLAGS "-std=c++11")
    elseif(COMPILER_SUPPORTS_CXX0X)
            set(CMAKE_CXX_FLAGS "-std=c++0x")
    else()
         message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
    endif()
    
    set(CMAKE_CXX_COMPILER "g++")
    set(CMAKE_BUILD_TYPE "Debug")
    set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb -m64 ${CMAKE_CXX_FLAGS}")
    set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall -m64 ${CMAKE_CXX_FLAGS}")
    

    这可以解决一些类似这样的问题:

    • error: no member named ‘tuple’ in namespace ‘std’
    • error: no member named ‘vector’ in namespace ‘std’

    posted in GuaiK实验室 read more
  • guluting

    0_1564473077975_1564473064137.jpg

    先简单介绍下,左边是个圆,右边是个矩形(AABB)箱。AABB-AABB和圆-AABB都是常用的碰撞检测方法,这种算法比较简单高效,但是精度不高,因为碰撞箱与被包裹物体很难完全吻合,所以会导致实际还没碰撞的时候就检测到碰撞。


    圆-AABB碰撞检测原理:

    找到矩形与圆最近的点vP,vC - vP,如果小于或等于0则发生碰撞。


    字母上方带一横的表示向量,我会在字母前用一个小写的v来表示向量。

    坐标使用左上角为原点(0.0),还有一些参数没在图中标记出。
    vec2:表示有x和y向量的分量(两个分量)。

    圆的坐标原点为:vCirclePos [vec2类型]
    矩形坐标原点:vRectanglePos [vec2类型]。
    矩形向量:vRectangle {vec2类型}


    参数介绍:

    • radius:圆的半径
    • vC:圆心,可以通过pCircle + radius计算出
    • half_width:矩形宽度的一半,vRectangle.x / 2
    • half_height:矩形高度的一半, vRectangle.y / 2
    • clamped.x:限制后的宽度
    • clamped.y: 限制后的高度
    • vB :矩形中心,vRectanglePos.x + half_width, vRectanglePos.y + half_height
    • vD:圆心与矩形中心的向量差,vD = vC - vB
    • vP:距离圆最近的点

    其中clamped.x和clamped.y(clamped向量)是通过限制函数计算出来的,限制函数可以将vD限制在了矩形的4条边上,这样可以计算出矩形边上的哪个点与当前的圆是最近的。

    常见的限制函数算法:

    float clamp(float value, float min, float max){
        return std::max(min, std::min(max, value));
    }
    

    圆-AABB碰撞检测伪代码:

    // 计算出圆心位置和矩形中心位置
    vC = pCircle + radius;
    half-width = vRectangle.x; / 2;   // 矩形半宽
    half-height = vRectangle.y; / 2; // 矩形半高
    
    
    // 计算圆心与矩形中心的向量差
    vD = vC - vB;
    // 通过限制函数计算出圆心到矩形最近点的向量差
    // 如果以矩形中心为原点,左上角的向量就是(-half_width, -half_height);
    // 同理右下角的向量就是(half_width, half_height);
    // 这样可以把vD向量控制在由矩形中心到矩形边的长度,所以vP肯定会落在矩形边上
    vD.x = clamp(vD.x,  -half_width, half_width);
    vD.y = clamp(vD.y, -half_height, half_height);
    // 使用矩形中心 + vD,得到距离最近的点vP
    vP = vRectangle + vD;
    // 最后计算出圆心到距离最近点vP的距离是否小于等于圆的半径radius
    // 如果小于等于圆的半径则发生圆-AABB发生碰撞
    difference = vP - vC;
    if (length(difference) <= radius){
        // 碰撞处理
    }
    

    posted in GuaiK实验室 read more
  • guluting

    先给服务器配置好磁盘整列,我选择了4块硬盘做的Raid1+0


    下载阵列驱动程序(B120i)
    CentOS 7.2
    http://downloads.hpe.com/pub/softlib2/software1/pubsw-linux/p1903785255/v115075/hpvsa-1.2.14-113.rhel7u2.x86_64.dd.gz
    CentOS 7.3
    http://downloads.hpe.com/pub/softlib2/software1/pubsw-linux/p1903785255/v123365/hpvsa-1.2.16-102.rhel7u3.x86_64.dd.gz
    或者在搜索页选择与CentOS版本匹配的驱动程序
    https://support.hpe.com/hpesc/public/km/search#q=b120i centos&t=All&sort=relevancy&f:@source=[cdp-km-software-pro-h9-v1]


    使用Linux系统dd指令将下载后的驱动程序写入U盘中

    • 将U盘插入Linux系统中
    • 使用fdisk -l查看磁盘信息,发现U盘是/dev/sda
    • 然后将驱动写入U盘中
    dd if=hpvsa-1.2.16-102.rhel7u3.x86_64.dd of=/dev/sda
    

    在CentOS安装选择界面按ESC,输入下列代码后回车

    linux modprobe.blacklist=ahci inst.dd
    

    启动后选择驱动盘进行安装

    • 按r刷新直到显示驱动挂在目录
    • 输入数字进行驱动选择
    • 按c继续,进行驱动安装
    • 移除驱动U盘
    • 按c继续,启动安装程序

    posted in GuaiK机房 read more
  • guluting

    很多网站有提供在线运行java程序的功能,但是在Mac下我测试了Chrome和Safari浏览器都不行。点击运行按钮后会下载一个.jnlp的文件,用javaws命令直接运行就OK了。

    /Library/Internet\ Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/javaws XXX.jnlp
    

    posted in GuaiK机房 read more