• 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
  • guluting

    固件下载地址:
    https://support.hpe.com/hpsc/swd/public/detail?swItemId=MTX_3830eb5b87574d6cb463c44994

    如果地址不可用的话可自己搜索下:
    1、进入搜索页面
    https://support.hpe.com/hpesc/public/km/search
    2、搜索关键词:
    “HPE ProLiant MicroServer Gen8 Server”
    3、内容区上方选择:
    “DRIVERS AND SOFTWARE”
    4、左边栏筛选:

    • Firmware
    • Lights-Out Management

    然后我选择了:
    “* RECOMMENDED * REMOVED Online ROM Flash Component for Linux - HPE Integrated Lights-Out 4”
    点击后进入介绍页面,在介绍页面点击“Obtain software”按钮进入下载页面。

    在下载页面有exe和rpm两个版本,随便选择一个版本下载后进行解压,在里边找到“ilo4_xxx.bin”文件,这个就是ILO的固件升级程序。

    posted in GuaiK机房 read more
  • guluting

    错误信息:

    yum update
    Loaded plugins: fastestmirror
    base                                                                                                                                                  | 3.6 kB  00:00:00
    
    
     One of the configured repositories failed (Unknown),
     and yum doesn't have enough cached data to continue. At this point the only
     safe thing yum can do is fail. There are a few ways to work "fix" this:
    
         1. Contact the upstream for the repository and get them to fix the problem.
    
         2. Reconfigure the baseurl/etc. for the repository, to point to a working
            upstream. This is most often useful if you are using a newer
            distribution release than is supported by the repository (and the
            packages for the previous distribution release still work).
    
         3. Run the command with the repository temporarily disabled
                yum --disablerepo=<repoid> ...
    
         4. Disable the repository permanently, so yum won't use it by default. Yum
            will then just ignore the repository until you permanently enable it
            again or use --enablerepo for temporary usage:
    
                yum-config-manager --disable <repoid>
            or
                subscription-manager repos --disable=<repoid>
    
         5. Configure the failing repository to be skipped, if it is unavailable.
            Note that yum will try to contact the repo. when it runs most commands,
            so will have to try and fail each time (and thus. yum will be be much
            slower). If it is a very temporary problem though, this is often a nice
            compromise:
    
                yum-config-manager --save --setopt=<repoid>.skip_if_unavailable=true
    
    Cannot retrieve metalink for repository: epel/x86_64. Please verify its path and try again
    

    解决方案

    # 1、删除epel.repo
    rm -rf /etc/yum.repos.d/epel.repo
    rm -rf /etc/yum.repos.d/epel-testing.repo
    
    # 2、检查DNS
    vi /etc/resolv.conf
    # 添加: nameserver 8.8.8.8
    # 重启网络服务
    systemctl restart network
    
    # 测试是否修复
    yum update
    

    posted in GuaiK机房 read more
  • guluting

    hostnamectl set-hostname guaik.org
    
    vi /etc/hosts
    # 在127.0.0.1后面加上[hostname]
    # 如果有外网IP的话也需要修改
    127.0.0.1      localhost.localdomain localhost
    xx.xx.xx.xx    guaik.org # 外网IP
    
    # 检查修改
    hostname -f
    cat /etc/hosts
    

    posted in GuaiK机房 read more
  • guluting

    我通常使用VSCode+CMake开发C++的程序,但是即使我在CMakeLists.txt中配置了Include的路径VSCode在#include时不但不自动补全路径还显示红色的波浪下划线。为了让VSCode能够知道Include的路径还需要针对当前工程配置.vscode/c_cpp_properties.json文件,可以通过shift+command+P然后选择C/C++: Edit Configurations(JSON)生成该文件。
    然后配置c_cpp_properties.json中的includePath字段:

    {
        "configurations": [
            {
                "name": "Mac",
                "includePath": [
                    "${workspaceFolder}/**",
                    "${workspaceFolder}/glm",
                    "${workspaceFolder}/glad",
                ],
                "defines": [],
                "macFrameworkPath": [],
                "compilerPath": "/usr/local/bin/gcc-8",
                "cStandard": "c11",
                "cppStandard": "c++17",
                "intelliSenseMode": "clang-x64"
            }
        ],
        "version": 4
    }
    

    配置后导入头文件:(例如demo.cpp在根目录下)

    // This is demo.cpp
    #include "glad/include/glad.h"
    #include "glm/glm.hpp"
    

    这时候就能够智能补全,红色波浪下划线也消失了。

    posted in GuaiK实验室 read more
  • guluting

    main.cpp

    #include <QApplication>
    #include <QDebug>
    #include "canvas.h"
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        QSurfaceFormat glFormat;
        glFormat.setVersion(3, 3);                           //  设置OpenGL版本
        glFormat.setProfile(QSurfaceFormat::CoreProfile);    // 设置使用核心模式
        QSurfaceFormat::setDefaultFormat(glFormat);
    
        Canvas *c = new Canvas();
        c->show();
    
        return a.exec();
    }
    

    Canvas.h

    #ifndef CANVAS_H
    #define CANVAS_H
    
    #include <QWidget>
    #include <QOpenGLWidget>
    #include <QOpenGLExtraFunctions>
    
    class Canvas : public QOpenGLWidget,protected QOpenGLExtraFunctions
    {
        Q_OBJECT
    public:
        explicit Canvas();
    
    signals:
    
    public slots:
    
    private:
    
    protected:
        virtual void initializeGL();
        virtual void resizeGL(int w, int h);
        virtual void paintGL();
    
    private:
        GLuint shaderProgram;
    };
    
    #endif
    

    Canvas.cpp

    #include "canvas.h"
    #include <QtDebug>
    #include <QtOpenGL>
    
    // 以下为测试代码,不推荐这么写
    // =================================
    GLuint VBO, VAO;
    const char *vertexShaderSource =
            "#version 330 core\n"
            "layout(location = 0) in vec3 aPos;\n"
            "void main(){\n"
            "  gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
            "}\n\0";
    const char *fragmentShaderSource =
            "#version 330 core\n"
            "out vec4 FragColor;\n"
            "void main(){\n"
            "   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
            "}\n\0";
    // =================================
    
    Canvas::Canvas()
    {
    
    }
    
    void Canvas::initializeGL()
    {
        //着色器部分
        this->initializeOpenGLFunctions();
        int vertexShader = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
        glCompileShader(vertexShader);
    
        int success;
        char infoLog[512];
        glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
        if (!success)
        {
            glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
            qDebug() << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << endl;
        }
    
        int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    
        glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
        glCompileShader(fragmentShader);
    
        glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
        if (!success)
        {
            glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
            qDebug() << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << endl;
        }
        shaderProgram = glCreateProgram();
        glAttachShader(shaderProgram, vertexShader);
        glAttachShader(shaderProgram, fragmentShader);
        glLinkProgram(shaderProgram);
    
        glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
        if (!success) {
            glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
            qDebug() << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << endl;
        }
        glDeleteShader(vertexShader);
        glDeleteShader(fragmentShader);
    
        GLfloat vertices[] = {
            -0.5f, -0.5f, 0.0f,
            0.5f, -0.5f, 0.0f,
            0.0f,  0.5f, 0.0f
        };
    
        glGenVertexArrays(1, &VAO);
        glGenBuffers(1, &VBO);
        glBindVertexArray(VAO);
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
    
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void*)0);
        glEnableVertexAttribArray(0);
    
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindVertexArray(0);
    }
    
    void Canvas::resizeGL(int width, int height)
    {
        glViewport(0, 0, width, height);
    }
    
    void Canvas::paintGL()
    {
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
    
        glUseProgram(shaderProgram);
        glBindVertexArray(VAO);
        glDrawArrays(GL_TRIANGLES, 0, 3);
        glUseProgram(0);
    }
    

    posted in GuaiK实验室 read more
  • guluting

    使用PlatformIO开发:

    1、Libraries中搜索LiquidCrystal,然后选择”By Arduino“的安装。
    2、修改platformio.ini文件(在lib_deps中添加库)

    [env:uno]
    platform = atmelavr
    board = uno
    framework = arduino
    lib_deps = 
        LiquidCrystal
    

    将Arduino与LCD的线接起来[ GND,VCC(5v),SDA,SCL ]

    0_1560937221828_WechatIMG146.jpeg

    • PS:上图中LCD背面有个蓝色的旋钮,是用来调整对比度的,如果LCD无法显示文字的话可以尝试调节该旋钮。

    DEMO

    #include <Arduino.h>
    #include <LiquidCrystal_I2C.h>
    
    LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
    
    void setup() {
    // 初始化LCD,每行16个字符,共两行
    lcd.begin(16, 2);
     
    // 背光闪烁三次
    for(int i = 0; i < 3; i++) {
    lcd.backlight(); 
    delay(250);
    lcd.noBacklight();
    delay(250);
    }
    lcd.backlight();
     
    lcd.setCursor(0, 0); // 设置游标:第一行第一列
    lcd.print(" Welcome Guaik ");
    delay(1000);
    lcd.setCursor(0, 1); // 设置游标:第二行第一列
    lcd.print("<bbs.guaik.org>");
    delay(3000);
    lcd.clear(); // 清除内容
    }
    void loop() {
    lcd.setCursor(0, 0); 
    lcd.print("Message:");
    lcd.setCursor(0, 1);
    lcd.print("Hello world");
    }
    

    如果无法正常工作的话,请检查I2C的设备地址,也就是LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);的第一个参数,当前的是0x3F。


    0_1560937679044_2019-06-19 171658.gif

    posted in GuaiK实验室 read more
  • guluting

    Upload错误:dyld: Library not loaded: /usr/local/opt/libftdi/lib/libftdi1.2.dylib

    解决方式:brew reinstall openocd


    设置默认项目路径:

    cd /Users/[UserName]/.platformio
    vi homestate.json
    

    找到:"projectsDir"把后面的路径设置成你的工程目录

    posted in GuaiK实验室 read more
  • guluting

    拷屁一段protobuf的简介:

    Protocol buffers是一个灵活的、高效的、自动化的用于对结构化数据进行序列化的协议,与XML相比,Protocol buffers序列化后的码流更小、速度更快、操作更简单。你只需要将要被序列化的数据结构定义一次(译注:使用.proto文件定义),便可以使用特别生成的源代码(译注:使用protobuf提供的生成工具)轻松的使用不同的数据流完成对这些结构数据的读写操作,即使你使用不同的语言(译注:protobuf的跨语言支持特性)。你甚至可以更新你的数据结构的定义(译注:就是更新.proto文件内容)而不会破坏依赖“老”格式编译出来的程序。

    示例.proto文件(api.proto):

    syntax = "proto3";
    
    package gkeng.comet;
    
    option go_package = "grpc";
    
    import "github.com/gogo/protobuf/gogoproto/gogo.proto";
    
    // protocol
    message Proto {
      int32 ver = 1 [(gogoproto.jsontag) = "ver"];
      int32 op = 2 [(gogoproto.jsontag) = "op"];
      int32 seq = 3 [(gogoproto.jsontag) = "seq"];
      int32 body = 4 [(gogoproto.jsontag) = "body"];
    }
    

    生成指令(.pb.go文件)

    protoc -I=. -I=$GOPATH/src -I=$GOPATH/src/github.com/gogo/protobuf --go_out=plugins=grpc:. ./api.proto

    • 通过-I引入了当前目录、Golang的源码目录和github.com/gogo/protobuf

    • 列表--go_out=plugins=grpc:.:在执行时添加grpc的plugin

    • 列表指定的./api.proto就是我们编写的数据结构文件


    .proto 描述文件的编写说明这里就不写了

    posted in GuaiK实验室 read more
  • guluting

    Reader分析


    数据结构

    type Reader struct {
        rd   io.Reader     // 被读取的io缓存,可以是网络的或文件的
        buf  []byte        // 缓冲区,用于给rd当缓存使用
        r, w int           // 读写游标,用来管理buf字段的
        err  error         // 存储当前Reader的异常值
    }
    

    常量分析

    const defaultBufSize = 4096   // 针对Reader中的buf字段,默认缓冲区大小(byte)
    const minReadBufferSize = 16  // 在初始化Reader结构的时候,能够设置的最小的缓冲区大小
    const maxConsecutiveEmptyReads = 100  // 从rd中读取数据无数据(fill操作)返回时(n==0)时,最多的读取次数
    

    函数分析
    func (b *Reader) fill();

    1、缓存对齐,如果读游标不在缓存的起始位置,则将可读数据对齐到起始位置copy(buf,buf[r:w])
    2、经过对齐后,如果w的游标超出了缓冲区的长度,则抛出一次异常
    3、尝试maxConsecutiveEmptyReads次从rd中读取数据到buf中,直到出现异常或者成功的读到数据到buf中了返回,如果超出了尝试次数则设置err为io.ErrNoProgress


    白色:空闲内存,可写入数据
    绿色:已写入内存,可读取数据
    灰色:已读取内存,可回收(fill函数在填充数据的同时会处理回收)
    0_1558596290334_未命名.png

    图中初始时有10个空闲块,R和W都指向下标0处。
    向内存中写入了5Byte的数据,这时候R在下标0处,W指向了下标5,这时候的可读数据为W-R=5Byte。
    读取了3Byte的数据,这时候R指向下标3,可读数据为W-R = 2,可回收空间为R。
    回收已读数据copy(buf,buf[r:w]),将R到W区间的数据平移至buf下标为0的位置。

    posted in GuaiK实验室 read more
  • guluting

    看了Go语言的书后发现它有切片和map类型,但是没有Set类型,那么这时候如果需要用到Set类型如何实现呢?
    借助map和struct就可以很轻易的实现,利用两个特点:
    1、map的key是不会重复的
    2、struct{}是占用0内存空间的


    // 先定义map类型,key为int32,value为struct{}
    var mySet map[int32]struct{}
    // 使用make为map分配内存并初始化
    mySet = make(map[int32]struct{})
    // 使用mySet
    mySet[0] = struct{}{}
    mySet[100] = struct{}{} 
    

    struct{}{}的定义

     struct{}  {}
    |  ^     | ^
      type     empty element list
    

    posted in GuaiK实验室 read more