10.2/11.1:GLKit 初識和案例 (Swift)

概述

  • GLKit框架是為了簡化基于OpenGL/OpenGL ES的應(yīng)用開發(fā)诸衔。
  • 它內(nèi)置數(shù)學(xué)方法和各種功能,其中的Effect有一點點固定管線的感覺岂丘。
  • 使用體感是面向?qū)ο缶翰讓尤匀皇敲嫦蜻^程。

案例一:繪制一張圖片

繪制一張圖片

導(dǎo)頭

import UIKit

import GLKit
import OpenGLES.ES3.gl
import OpenGLES.ES3.glext

// 忽略警告
@available(iOS,deprecated:1.0)

UIViewController 改為 GLKViewController

// 使用 GLKViewController
class ViewController: GLKViewController {

View 改為 GLKView

[圖片上傳失敗...(image-de7578-1596009288359)]

定義 EAGLContext 和 GLKBaseEffect

// 上下文
var context: EAGLContext?
// 類似 OpenGL里的固定管線
var effect: GLKBaseEffect?

viewDidLoad() 3個準(zhǔn)備方法

override func viewDidLoad() {
    super.viewDidLoad()
    
    // 1. 準(zhǔn)備好 context 和 glkView
    setupConfig()
    
    // 2. 頂點數(shù)據(jù) => 頂點緩沖區(qū) => 頂點著色器
    setupVertexData()
    
    // 3. 圖片文件 => 紋理 => effect
    setupTexture()
    
    // (4.) 代理方法里 設(shè)置繪制
}

setupConfig()

func setupConfig() {
    // 1. 初始化上下文
    context = EAGLContext(api: .openGLES3)
    
    guard let _context = context else {
        print("Initial ES context Failed!!")
        return
    }
    
    // 2. 可以有多個上下文硫椰,但只能有一個當(dāng)前上下文
    EAGLContext.setCurrent(_context)
    
    // 3. 獲取 GLKView
    guard let glkView = view as? GLKView else {
        print("Convert UIView to GLKView Failed!!")
        return
    }
    
    // view 綁定上下文
    glkView.context = _context
    // 顏色緩沖區(qū)格式
    glkView.drawableColorFormat = .RGBA8888
    // 深度緩沖區(qū)格式 (可以選16位)
    glkView.drawableDepthFormat = .format24
    
    // 4. 設(shè)置背景顏色 橘色繁调,這里也能用 glkView.backgroundColor
    glClearColor(1.0, 0.4, 0.0, 1.0)
}

setupVertexData()

func setupVertexData() {
    
    // 1. 頂點數(shù)據(jù),包含 頂點坐標(biāo)(xyz) 和 紋理坐標(biāo)(st)
    // 之后載入照片用到2個三角形靶草,共6個頂點
    let vertextData: [GLfloat] = [
         0.8, -0.2,  0.0,    1.0, 0.0,
         0.8,  0.2,  0.0,    1.0, 1.0,
        -0.8,  0.2,  0.0,    0.0, 1.0,
       // x     y     z       s    t
         0.8, -0.2,  0.0,    1.0, 0.0,
        -0.8,  0.2,  0.0,    0.0, 1.0,
        -0.8, -0.2,  0.0,    0.0, 0.0,
    ]
    
    // 2. 創(chuàng)建 緩沖區(qū)(拿房間號)
    var bufferID = GLuint()
    glGenBuffers(1, &bufferID)
    
    // 3. 綁定 頂點緩沖區(qū)(指定用途蹄胰,還能指定為 深度緩沖區(qū)等)
    glBindBuffer(GLenum(GL_ARRAY_BUFFER), bufferID)
    
    // 4. copy 內(nèi)存 => 顯存(頂點緩沖區(qū))
    glBufferData(
        GLenum(GL_ARRAY_BUFFER), //copy到哪:頂點緩沖區(qū)
        MemoryLayout<GLfloat>.stride * vertextData.count, //空間大小
        vertextData, //內(nèi)容
        GLenum(GL_STATIC_DRAW)) //用途:繪制
    
    // 5.1. 打開通道 以使用緩沖區(qū)數(shù)據(jù)
    glEnableVertexAttribArray(GLuint(GLKVertexAttrib.position.rawValue))
    
    // 5.2. 頂點著色器(頂點坐標(biāo)) 讀取 <= 頂點緩沖區(qū)
    glVertexAttribPointer(
        GLuint(GLKVertexAttrib.position.rawValue), //傳給誰:頂點position
        3, //position 由 xyz 組成
        GLenum(GL_FLOAT), //數(shù)據(jù)類型
        GLboolean(GL_FALSE), //是否需要歸一化
        GLsizei(MemoryLayout<GLfloat>.stride * 5), //每次讀取的步長
        UnsafeRawPointer(bitPattern: MemoryLayout<GLfloat>.stride * 0)) //指針起始偏移
    
    // 6.1. 打開通道 以使用緩沖區(qū)數(shù)據(jù)
    glEnableVertexAttribArray(GLuint(GLKVertexAttrib.texCoord0.rawValue))
    
    // 6.2. 頂點著色器(紋理坐標(biāo)) 讀取 <= 頂點緩沖區(qū)
    glVertexAttribPointer(
        GLuint(GLKVertexAttrib.texCoord0.rawValue), //傳給誰:頂點position
        2, //tex 由 st 組成
        GLenum(GL_FLOAT), //數(shù)據(jù)類型
        GLboolean(GL_FALSE), //是否需要歸一化
        GLsizei(MemoryLayout<GLfloat>.stride * 5), //每次讀取的步長
        UnsafeRawPointer(bitPattern: MemoryLayout<GLfloat>.stride * 3)) //指針起始偏移
    
}

setupTexture()

func setupTexture() {
    
    // 1. 圖片路徑
    guard let filePath = Bundle.main.path(forResource: "pcr", ofType: "jpg") else {
        print("load image failed!!")
        return
    }
    
    // 2.1. 由于紋理坐標(biāo)原點為左下角,圖片顯示原點為左上角奕翔,需要設(shè)置 (否則是倒的)
    let options = [GLKTextureLoaderOriginBottomLeft : NSNumber(booleanLiteral: true)]
    
    // 2.2. 圖片 轉(zhuǎn) 紋理
    guard let textureInfo = try? GLKTextureLoader.texture(withContentsOfFile: filePath, options: options) else {
        print("convert image to texture failed!!")
        return
    }
    
    // 3.1. 初始化 GLKBaseEffect
    effect = GLKBaseEffect()
    guard let _effect = effect else {
        print("Initial GLKBaseEffect failed!!")
        return
    }
    
    // 3.2. 打開 effect 的紋理通道
    _effect.texture2d0.enabled = GLboolean(GL_TRUE)
    
    // 3.3. 綁定 紋理
    _effect.texture2d0.name = textureInfo.name
}

代理方法 glkView(_: , drawIn: ) 設(shè)置繪制

  • 相當(dāng)于OpenGLRenderScene()
// MARK:- GLKViewDelegate
    
override func glkView(_ view: GLKView, drawIn rect: CGRect) {
    
    // 1. 清空 顏色緩沖區(qū)
    glClear(GLbitfield(GL_COLOR_BUFFER_BIT))
    
    
    guard let _effect = effect else {
        print("Initial GLKBaseEffect failed!!")
        return
    }
    
    // 2. 準(zhǔn)備繪制
    _effect.prepareToDraw()
    
    // 3. 繪制:三角形裕寨,從第0個頂點開始,共6個頂點
    glDrawArrays(GLenum(GL_TRIANGLES), 0, 6)
}

案例二:立方體旋轉(zhuǎn)

立方體旋轉(zhuǎn)
  • 導(dǎo)頭派继、改GLKViewGLKViewController與案例一是一樣的宾袜,不再贅述。

  • 關(guān)注注釋:基本上只注釋案例一里沒有的代碼驾窟。

基本的聲明定義

// 頂點數(shù)據(jù) 結(jié)構(gòu)體
struct MDVertex {
    let positionCoord: GLKVector3
    let textureCoord: GLKVector2
    let normalVec: GLKVector3
}


@available(iOS,deprecated: 12.0)
class ViewController: GLKViewController {
    
    var context: EAGLContext!
    var effect: GLKBaseEffect!
    // 頂點數(shù)據(jù) 數(shù)組
    var vertexes: [MDVertex]!
    // 頂點緩沖區(qū)ID
    var vertexBufferID: GLuint!
    
    // 記錄旋轉(zhuǎn)角度
    var angle: Int = 0
    // 計時器
    var displayLink: CADisplayLink!

deinit 釋放

deinit {
    
    if EAGLContext.current() == context {
        EAGLContext.setCurrent(nil)
    }
    
    if let _ = vertexBufferID {
        glDeleteBuffers(1, &vertexBufferID)
        vertexBufferID = 0
    }
    
    displayLink.invalidate()
}

viewDidLoad() 2個準(zhǔn)備方法

override func viewDidLoad() {
    super.viewDidLoad()
    
    // 1.1. 準(zhǔn)備好 context 和 glkView
    // 1.2. 頂點數(shù)據(jù) => 頂點緩沖區(qū) => 頂點著色器
    // 1.3. 圖片文件 => 紋理 => effect
    commonInit()
    
    // 2. 計時器庆猫,做旋轉(zhuǎn)動畫:調(diào)用的 update()方法 改變effect的 MV矩陣并重繪
    addCADisplayLink()
    
    // (3.) 代理方法里 設(shè)置繪制
}

commonInit()

  • 相當(dāng)于案例一的3個準(zhǔn)備方法。
func commonInit() {
    
    // context / glkView 的一系列操作
    context = EAGLContext(api: .openGLES3)
    assert(context != nil, "Initialize context failed!!")
    
    EAGLContext.setCurrent(context)
    
    guard let glkView = view as? GLKView else { return }
    
    glkView.context = context
    glkView.drawableColorFormat = .RGBA8888
    // 啟用 深度緩沖區(qū)
    glkView.drawableDepthFormat = .format24
    glkView.backgroundColor = .clear
    
    // 深度緩沖區(qū) 默認(rèn)(0, 1)绅络,這里相當(dāng)于翻轉(zhuǎn)Z軸月培,使正方形朝屏幕外
    glDepthRangef(1, 0)
    
    // 加載紋理的一系列操作
    guard let filePath = Bundle.main.path(forResource: "pcr", ofType: "jpg") else { return }
    
    guard let cgImage = UIImage(contentsOfFile: filePath)?.cgImage else { return }
    
    let options = [GLKTextureLoaderOriginBottomLeft : NSNumber(booleanLiteral: true)]
    guard let textureInfo = try? GLKTextureLoader.texture(with: cgImage, options: options) else { return }
    
    // effect
    effect = GLKBaseEffect()
    // effect 設(shè)置紋理
    effect.texture2d0.name = textureInfo.name
    // effect 設(shè)置光照
    effect.light0.enabled = GLboolean(GL_TRUE)
    effect.light0.diffuseColor = GLKVector4Make(1, 1, 1, 1)
    effect.light0.position = GLKVector4Make(0.5, 0, 5, 1)
    
    // 頂點坐標(biāo)
    let ver1 = GLKVector3Make(-0.5,  0.5,  0.5)
    let ver2 = GLKVector3Make(-0.5, -0.5,  0.5)
    let ver3 = GLKVector3Make( 0.5,  0.5,  0.5)
    let ver4 = GLKVector3Make( 0.5, -0.5,  0.5)
    let ver5 = GLKVector3Make( 0.5,  0.5, -0.5)
    let ver6 = GLKVector3Make(-0.5,  0.5, -0.5)
    let ver7 = GLKVector3Make( 0.5, -0.5, -0.5)
    let ver8 = GLKVector3Make(-0.5, -0.5, -0.5)
    
    // 紋理坐標(biāo)
    let tex1 = GLKVector2Make(0, 1)
    let tex2 = GLKVector2Make(0, 0)
    let tex3 = GLKVector2Make(1, 1)
    let tex4 = GLKVector2Make(1, 0)
    
    // 法線向量
    let normal1 = GLKVector3Make( 0, 0, 1)
    let normal2 = GLKVector3Make( 0, 1, 0)
    let normal3 = GLKVector3Make( 0,-1, 0)
    let normal4 = GLKVector3Make(-1, 0, 0)
    let normal5 = GLKVector3Make( 1, 0, 0)
    let normal6 = GLKVector3Make( 0, 0,-1)
    
    // 用于初始化的隨便取值的頂點數(shù)據(jù)
    let meanlessVertex =
        MDVertex(positionCoord: ver1, textureCoord: tex1, normalVec: normal1)
    
    // 先用初始化來開辟內(nèi)存空間
    vertexes = [MDVertex].init(repeating: meanlessVertex, count: 36)
    
    // 初始化36個頂點數(shù)據(jù):每個三角形3個頂點嘁字,每個面2個三角形,一個立方體6個面杉畜,3x2x6 = 36
    
    vertexes[00] = MDVertex(positionCoord: ver1, textureCoord: tex1, normalVec: normal1)
    vertexes[01] = MDVertex(positionCoord: ver2, textureCoord: tex2, normalVec: normal1)
    vertexes[02] = MDVertex(positionCoord: ver3, textureCoord: tex3, normalVec: normal1)
    vertexes[03] = MDVertex(positionCoord: ver2, textureCoord: tex2, normalVec: normal1)
    vertexes[04] = MDVertex(positionCoord: ver3, textureCoord: tex3, normalVec: normal1)
    vertexes[05] = MDVertex(positionCoord: ver4, textureCoord: tex4, normalVec: normal1)
    
    vertexes[06] = MDVertex(positionCoord: ver3, textureCoord: tex3, normalVec: normal2)
    vertexes[07] = MDVertex(positionCoord: ver1, textureCoord: tex1, normalVec: normal2)
    vertexes[08] = MDVertex(positionCoord: ver5, textureCoord: tex4, normalVec: normal2)
    vertexes[09] = MDVertex(positionCoord: ver1, textureCoord: tex1, normalVec: normal2)
    vertexes[10] = MDVertex(positionCoord: ver5, textureCoord: tex4, normalVec: normal2)
    vertexes[11] = MDVertex(positionCoord: ver6, textureCoord: tex2, normalVec: normal2)

    vertexes[12] = MDVertex(positionCoord: ver4, textureCoord: tex3, normalVec: normal3)
    vertexes[13] = MDVertex(positionCoord: ver2, textureCoord: tex1, normalVec: normal3)
    vertexes[14] = MDVertex(positionCoord: ver7, textureCoord: tex4, normalVec: normal3)
    vertexes[15] = MDVertex(positionCoord: ver2, textureCoord: tex1, normalVec: normal3)
    vertexes[16] = MDVertex(positionCoord: ver7, textureCoord: tex4, normalVec: normal3)
    vertexes[17] = MDVertex(positionCoord: ver8, textureCoord: tex2, normalVec: normal3)

    vertexes[18] = MDVertex(positionCoord: ver1, textureCoord: tex3, normalVec: normal4)
    vertexes[19] = MDVertex(positionCoord: ver2, textureCoord: tex1, normalVec: normal4)
    vertexes[20] = MDVertex(positionCoord: ver6, textureCoord: tex4, normalVec: normal4)
    vertexes[21] = MDVertex(positionCoord: ver2, textureCoord: tex1, normalVec: normal4)
    vertexes[22] = MDVertex(positionCoord: ver6, textureCoord: tex4, normalVec: normal4)
    vertexes[23] = MDVertex(positionCoord: ver8, textureCoord: tex2, normalVec: normal4)
    
    vertexes[24] = MDVertex(positionCoord: ver3, textureCoord: tex3, normalVec: normal5)
    vertexes[25] = MDVertex(positionCoord: ver4, textureCoord: tex1, normalVec: normal5)
    vertexes[26] = MDVertex(positionCoord: ver5, textureCoord: tex4, normalVec: normal5)
    vertexes[27] = MDVertex(positionCoord: ver4, textureCoord: tex1, normalVec: normal5)
    vertexes[28] = MDVertex(positionCoord: ver5, textureCoord: tex4, normalVec: normal5)
    vertexes[29] = MDVertex(positionCoord: ver7, textureCoord: tex2, normalVec: normal5)
    
    vertexes[30] = MDVertex(positionCoord: ver6, textureCoord: tex1, normalVec: normal6)
    vertexes[31] = MDVertex(positionCoord: ver8, textureCoord: tex2, normalVec: normal6)
    vertexes[32] = MDVertex(positionCoord: ver5, textureCoord: tex3, normalVec: normal6)
    vertexes[33] = MDVertex(positionCoord: ver8, textureCoord: tex2, normalVec: normal6)
    vertexes[34] = MDVertex(positionCoord: ver5, textureCoord: tex3, normalVec: normal6)
    vertexes[35] = MDVertex(positionCoord: ver7, textureCoord: tex4, normalVec: normal6)
    
    // 頂點緩沖區(qū)的一系列操作
    vertexBufferID = GLuint()
    glGenBuffers(1, &vertexBufferID)
    glBindBuffer(GLenum(GL_ARRAY_BUFFER), vertexBufferID)
    
    // 頂點數(shù)據(jù)數(shù)組的大小 = 40x36 = 1440
    let bufferSize: GLsizeiptr = MemoryLayout<MDVertex>.stride * vertexes.count
    // copy頂點數(shù)組 內(nèi)存 => 顯存
    glBufferData(
        GLenum(GL_ARRAY_BUFFER),
        bufferSize,
        vertexes,
        GLenum(GL_STATIC_DRAW))
    
    /*
     glVertexAttribPointer函數(shù)的最后一個參數(shù)纪蜒,偏移值,要注意下此叠!
     MDVertex結(jié)構(gòu)體 內(nèi)含 GLKVector3,GLKVector2,GLKVector3
     獨立使用時:內(nèi)存占用大小 GLKVector3 = 12纯续,GLKVector2 = 8
     但在結(jié)構(gòu)體:內(nèi)存占用大小 GLKVector3 = 16,GLKVector2 = 8
     詳情查閱 "字節(jié)對齊"
     所以 MDVertex結(jié)構(gòu)體 內(nèi)存占用大小 = 16+8+16 = 40
     */
    
    // 頂點
    glEnableVertexAttribArray(GLuint(GLKVertexAttrib.position.rawValue))
    glVertexAttribPointer(
        GLuint(GLKVertexAttrib.position.rawValue),
        3,
        GLenum(GL_FLOAT),
        GLboolean(GL_FALSE),
        GLsizei(MemoryLayout<MDVertex>.stride),
        UnsafeRawPointer(bitPattern: 0))
    
    // 紋理
    glEnableVertexAttribArray(GLuint(GLKVertexAttrib.texCoord0.rawValue))
    glVertexAttribPointer(
        GLuint(GLKVertexAttrib.texCoord0.rawValue),
        2,
        GLenum(GL_FLOAT),
        GLboolean(GL_FALSE),
        GLsizei(MemoryLayout<MDVertex>.stride),
        UnsafeRawPointer(bitPattern: 16))
    
    // 法線
    glEnableVertexAttribArray(GLuint(GLKVertexAttrib.normal.rawValue))
    glVertexAttribPointer(
        GLuint(GLKVertexAttrib.normal.rawValue),
        3,
        GLenum(GL_FLOAT),
        GLboolean(GL_FALSE),
        GLsizei(MemoryLayout<MDVertex>.stride),
        UnsafeRawPointer(bitPattern: 16 + 8))
}

addCADisplayLink()

func addCADisplayLink() {
    
    // 記錄旋轉(zhuǎn)角度
    angle = 0
    // 定時器調(diào)用方法 update
    displayLink = CADisplayLink(target: self, selector: #selector(update))
    // 加入到 Runloop
    displayLink.add(to: RunLoop.main, forMode: RunLoop.Mode.common)
     
    //CADisplayLink 類似定時器,提供一個周期性調(diào)用.屬于QuartzCore.framework中.
    //具體可以參考該博客 https://www.cnblogs.com/panyangjun/p/4421904.html
}

update()

@objc
func update() {
    // 1. 改變旋轉(zhuǎn)角度
    angle = (angle + 2) % 360
    
    // 2. MV矩陣 = 繞 (0.3, 1, 0.7)軸線 旋轉(zhuǎn) angle角度(轉(zhuǎn)弧度)
    effect.transform.modelviewMatrix = GLKMatrix4MakeRotation(
        GLKMathDegreesToRadians(Float(angle)),
        0.3,
        1,
        0.7)
    
    // 3. 重新渲染
    if let glkView = view as? GLKView {
        glkView.display()
    }
    
}

代理方法 glkView(_: , drawIn: ) 設(shè)置繪制

// MARK:- GLKViewDelegate

override func glkView(_ view: GLKView, drawIn rect: CGRect) {
    
    glEnable(GLenum(GL_DEPTH_TEST))
    glClear(GLbitfield(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT))
    
    effect.prepareToDraw()
    glClearColor(0.8, 0.8, 0.8, 1.0)
    glDrawArrays(GLenum(GL_TRIANGLES), 0, GLsizei(vertexes.count))
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末拌蜘,一起剝皮案震驚了整個濱河市杆烁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌简卧,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件烤芦,死亡現(xiàn)場離奇詭異举娩,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)构罗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門铜涉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人遂唧,你說我怎么就攤上這事芙代。” “怎么了盖彭?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵纹烹,是天一觀的道長。 經(jīng)常有香客問我召边,道長铺呵,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任隧熙,我火速辦了婚禮片挂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘贞盯。我一直安慰自己音念,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布躏敢。 她就那樣靜靜地躺著闷愤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪父丰。 梳的紋絲不亂的頭發(fā)上肝谭,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天掘宪,我揣著相機(jī)與錄音,去河邊找鬼攘烛。 笑死魏滚,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的坟漱。 我是一名探鬼主播鼠次,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼芋齿!你這毒婦竟也來了腥寇?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤觅捆,失蹤者是張志新(化名)和其女友劉穎赦役,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體栅炒,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡掂摔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了赢赊。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乙漓。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖释移,靈堂內(nèi)的尸體忽然破棺而出叭披,到底是詐尸還是另有隱情,我是刑警寧澤玩讳,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布涩蜘,位于F島的核電站,受9級特大地震影響锋边,放射性物質(zhì)發(fā)生泄漏皱坛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一豆巨、第九天 我趴在偏房一處隱蔽的房頂上張望剩辟。 院中可真熱鬧,春花似錦往扔、人聲如沸贩猎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吭服。三九已至,卻和暖如春蝗罗,著一層夾襖步出監(jiān)牢的瞬間艇棕,已是汗流浹背蝌戒。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留沼琉,地道東北人北苟。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像打瘪,于是被迫代替她去往敵國和親友鼻。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,044評論 2 355