使用GLFW與GLAD創(chuàng)建窗口并畫出三角形

本文章內(nèi)容代碼可在這里找到障簿,如果此代碼對(duì)您有幫助,煩請(qǐng)動(dòng)動(dòng)您的手指栅迄,點(diǎn)個(gè)Star站故,謝謝!歡迎訪問我的個(gè)人主頁(yè)Orient毅舆。

創(chuàng)建窗口

1西篓、首先我們引入必要的頭文件:

#include "glad.h"
#include <GLFW/glfw3.h>

請(qǐng)確保GLAD頭文件的引入在GLFW之前,GLAD的頭文件包含了正確的OpenGL頭文件(例如GL/gl.h)憋活,所以需要在其他依賴于OpenGL的頭文件之前引入GLAD

2岂津、實(shí)例化GLFW窗口

int main()
{
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    // Mac必須添加此行,Windows忽略
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);

    return 0;
}

前兩行代碼指定了OpenGL的主版本和次版本號(hào)(4.1)悦即,第三行代表著使用核心模式(Core-profile)吮成,意味著我們只能使用OpenGL功能的一個(gè)子集(沒有我們不再需要的向后兼容特性)橱乱。

3、接下來(lái)創(chuàng)建一個(gè)窗口對(duì)象粱甫,它存放了所有和窗口相關(guān)的數(shù)據(jù)泳叠,而且會(huì)被GLFW的其他函數(shù)頻繁調(diào)用

GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
if(window == NULL)
{
    std::cout << "Failed to create GLFW window" << std::endl;
    glfwTerminate();
    return -1;
}
glfwMakeContexCurrent(window);

glfwCreateWindow函數(shù),前兩個(gè)參數(shù)是窗口的寬高茶宵,第三個(gè)參數(shù)是這個(gè)窗口的命名析二,后兩個(gè)暫時(shí)忽略,返回了一個(gè)GLFWwindow對(duì)象节预。glfwMakeContexCurrent函數(shù)告訴GLFW將窗口的上下文設(shè)置為當(dāng)前線程的主上下文叶摄。

4、GLAD是用來(lái)管理OpenGL的函數(shù)指針的安拟,所以調(diào)用任何OpenGL函數(shù)之前需要初始化GLAD

if(!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
    std::cout << "Failed to initialize GLAD" << std::endl;
    return -1;
}

我們給GLAD傳入了用來(lái)加載系統(tǒng)相關(guān)的OpenGL函數(shù)指針地址的函數(shù)蛤吓。GLFW給我們的是glfwGetProcAdress,它根據(jù)我們編譯的系統(tǒng)定義了正確的函數(shù)糠赦。

5会傲、視口

在開始渲染之前必須告訴OpenGL渲染窗口(Viewport)的尺寸大小,這樣OpenGL才能知道怎樣根據(jù)窗口大小顯示數(shù)據(jù)和坐標(biāo)拙泽。

// 此函數(shù)設(shè)置窗口的維度(Dimension)
glViewport(0, 0, 800, 600);

前兩個(gè)參數(shù)控制窗口左下角位置淌山,后兩個(gè)控制渲染窗口的寬高(像素)。也可將視口維度設(shè)置比GLFW窗口維度小顾瞻,這樣子之后所有的OpenGL渲染將會(huì)在一個(gè)更小的窗口中顯示泼疑,這樣子的話我們也可以將一些其它元素顯示在OpenGL視口之外。

6荷荤、對(duì)窗口注冊(cè)回調(diào)函數(shù)(CallbackFunction)

函數(shù)注冊(cè)后會(huì)在每次窗口大小改變的時(shí)候調(diào)用退渗,視口也會(huì)隨之調(diào)整

函數(shù)原型如下:

void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    glViewport(0, 0, width, height);
}

進(jìn)行注冊(cè),告訴GLFW每當(dāng)窗口調(diào)整時(shí)調(diào)用此函數(shù):

glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

7蕴纳、為了使圖像能夠持續(xù)顯示而不是一閃即逝会油,我們需要寫一個(gè)渲染循環(huán),使得GLFW在退出之前一直保持運(yùn)行

while(!glfwWindowShouldClose(window))
{
    glfwSwapBuffers(window);
    glfwPollEvents();    
}

glfwWindowShouldClose函數(shù)在每次循環(huán)開始前檢查一次GLFW是否被要求退出古毛,是的話返回true翻翩,循環(huán)結(jié)束

glfwPollEvents函數(shù)檢查是否有觸發(fā)事件,比如鍵盤稻薇、鼠標(biāo)等信號(hào)輸入嫂冻,然后更新窗口狀態(tài),調(diào)用相應(yīng)的回調(diào)函數(shù)(可通過回調(diào)方法手動(dòng)設(shè)置)颖低。

glfwSwapBuffers函數(shù)會(huì)交換顏色緩沖

8絮吵、渲染結(jié)束后釋放所有資源

glfwTerminate();
return 0;

至此弧烤,窗口創(chuàng)建完成

接下來(lái)我們進(jìn)行一些完善工作

9忱屑、接下來(lái)我們添加一個(gè)觸發(fā)時(shí)間蹬敲,當(dāng)用戶按下Esc鍵時(shí)關(guān)閉窗口。

void processInput(GLFWwindow *window)
{
    if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
}

glfwGetKey函數(shù)需要一個(gè)窗口以及一個(gè)按鍵作為輸入莺戒。這個(gè)函數(shù)將會(huì)返回這個(gè)案件是否正在被按下伴嗡,我們將其定義在processInput函數(shù)當(dāng)中

接下來(lái)在渲染循環(huán)的每一個(gè)迭代中調(diào)用processInput

while (!glfwWindowShouldClose(window))
{
    processInput(window);

    // 這里是渲染指令
    ...

    glfwSwapBuffers(window);
    glfwPollEvents();
}

10、我們使用一個(gè)自定義的顏色清空屏幕从铲,使得在每個(gè)新的渲染迭代開始后清除上一次渲染結(jié)果瘪校,并顯示我們自定義的顏色

glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);

渲染一個(gè)三角形

開始繪制之前,我們需要給OpenGL輸入一些頂點(diǎn)數(shù)據(jù)(范圍在[-1, 1]名段,需要自行進(jìn)行坐標(biāo)變換)阱扬。我們需要渲染一個(gè)三角形,因此我們需要三個(gè)頂點(diǎn)位置伸辟,將它定義為一個(gè)float數(shù)組:

// 由于我們繪制的是一個(gè)2D三角形麻惶,因此,將其頂點(diǎn)的z坐標(biāo)都設(shè)置為0
float vertices[] = {
    -0.5f, -0.5f, 0.0f,
     0.5f, -0.5f, 0.0f,
     0.0f,  0.5f, 0.0f
};

接下來(lái)使用glGenBuffers函數(shù)和一個(gè)緩沖ID生成一個(gè)VBO對(duì)象信夫,并使用glBindBuffer函數(shù)把新創(chuàng)建的緩沖綁定到GL_ARRAY_BUFFER目標(biāo)上:

unsigned int VBO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);  

從這一刻起窃蹋,我們使用的任何(在GL_ARRAY_BUFFER目標(biāo)上的)緩沖調(diào)用都會(huì)用來(lái)配置當(dāng)前綁定的緩沖(VBO)。然后我們可以調(diào)用glBufferData函數(shù)静稻,它會(huì)把之前定義的頂點(diǎn)數(shù)據(jù)復(fù)制到緩沖的內(nèi)存中:

glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

第一個(gè)參數(shù)是目標(biāo)緩沖的類型警没,頂點(diǎn)緩沖對(duì)象當(dāng)前綁定到GL_ARRAY_BUFFER目標(biāo)上。

第二個(gè)參數(shù)指定傳輸數(shù)據(jù)大小振湾。

第三個(gè)參數(shù)是我們實(shí)際發(fā)送的數(shù)據(jù)杀迹。

第四個(gè)參數(shù)指定了顯卡管理數(shù)據(jù)的方式,有一下三種形式:
GL_STATIC_DRAW:數(shù)據(jù)不會(huì)或幾乎不改變押搪。
GL_DYNAMIC_DRAW:數(shù)據(jù)會(huì)改變很多佛南。
GL_STREAM_DRAW:數(shù)據(jù)每次繪制都會(huì)改變。

頂點(diǎn)著色器

首先用GLSL(OoenGL Shading Language)編寫頂點(diǎn)著色器嵌言,然后編譯這個(gè)著色器嗅回。下面給出一個(gè)非常基礎(chǔ)的頂點(diǎn)著色器源代碼:

#version 410 core
layout (location = 0) in vec3 aPos;

void main()
{
    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}

首先申明OpenGL版本4.1(對(duì)應(yīng)410)摧茴。
接下來(lái)使用in關(guān)鍵字绵载,在頂點(diǎn)著色器中聲明所有的輸入頂點(diǎn)屬性(Input Vertex Attribute)。現(xiàn)在我們只關(guān)心位置(Position)數(shù)據(jù)苛白,所以我們只需要一個(gè)頂點(diǎn)屬性娃豹。GLSL有一個(gè)向量數(shù)據(jù)類型,它包含1到4個(gè)float分量购裙,包含的數(shù)量可以從它的后綴數(shù)字看出來(lái)懂版。由于每個(gè)頂點(diǎn)都有一個(gè)3D坐標(biāo),我們就創(chuàng)建一個(gè)vec3輸入變量aPos躏率。我們同樣也通過layout (location = 0)設(shè)定了輸入變量的位置值(Location)你后面會(huì)看到為什么我們會(huì)需要這個(gè)位置值躯畴。

編譯著色器

先創(chuàng)建一個(gè)著色器對(duì)象民鼓,注意還是用ID來(lái)引用。所以我們儲(chǔ)存這個(gè)頂點(diǎn)著色器為unsigned int蓬抄,然后用glCreateShader創(chuàng)建這個(gè)著色器:

unsigned int vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);

我們把需要?jiǎng)?chuàng)建的著色器類型以參數(shù)形式提供給glCreateShader丰嘉。由于我們正在創(chuàng)建一個(gè)頂點(diǎn)著色器,傳遞的參數(shù)是GL_VERTEX_SHADER嚷缭。

接下來(lái)把著色器源碼附加到著色器對(duì)象上饮亏,并編譯它:

glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);

glShaderSource函數(shù)把要編譯的著色器對(duì)象作為第一個(gè)參數(shù)。第二參數(shù)指定了傳遞的源碼字符串?dāng)?shù)量阅爽,這里只有一個(gè)路幸。第三個(gè)參數(shù)是頂點(diǎn)著色器真正的源碼,第四個(gè)參數(shù)我們先設(shè)置為NULL付翁。

片段著色器

先給出片段著色器源碼:

#version 410 core
out vec4 FragColor;

void main()
{
    FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
} 

片段著色器只需要一個(gè)輸出變量劝赔,這個(gè)變量是一個(gè)4分量向量,它表示的是最終的輸出顏色胆敞,我們應(yīng)該自己將其計(jì)算出來(lái)着帽。我們可以用out關(guān)鍵字聲明輸出變量,這里我們命名為FragColor移层。下面仍翰,我們將一個(gè)alpha值為1.0(1.0代表完全不透明)的橘黃色的vec4賦值給顏色輸出。

編譯片段著色器的過程與頂點(diǎn)著色器類似观话,只不過我們使用GL_FRAGMENT_SHADER常量作為著色器類型:

unsigned int fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);

著色器程序

著色器程序?qū)ο?Shader Program Object)是多個(gè)著色器合并之后并最終鏈接完成的版本予借。如果要使用剛才編譯的著色器我們必須把它們鏈接(Link)為一個(gè)著色器程序?qū)ο螅缓笤阡秩緦?duì)象的時(shí)候激活這個(gè)著色器程序频蛔。已激活著色器程序的著色器將在我們發(fā)送渲染調(diào)用的時(shí)候被使用灵迫。

創(chuàng)建程序?qū)ο螅?/p>

unsigned int shaderProgram;
shaderProgram = glCreateProgram();

glCreateProgram函數(shù)創(chuàng)建一個(gè)程序,并返回新創(chuàng)建程序?qū)ο蟮腎D引用』尴現(xiàn)在我們需要把之前編譯的著色器附加到程序?qū)ο笊掀僦啵缓笥?code>glLinkProgram鏈接它們:

glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);

最后調(diào)用glUseProgram函數(shù),激活程序:

glUseProgram(shaderProgram);

著色器對(duì)象鏈接到程序?qū)ο笠院笕玻枰獎(jiǎng)h除著色器對(duì)象:

glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);

鏈接頂點(diǎn)屬性

頂點(diǎn)著色器允許我們指定任何以頂點(diǎn)屬性為形式的輸入狞换。這使其具有很強(qiáng)的靈活性的同時(shí),它還的確意味著我們必須手動(dòng)指定輸入數(shù)據(jù)的哪一個(gè)部分對(duì)應(yīng)頂點(diǎn)著色器的哪一個(gè)頂點(diǎn)屬性舟肉。所以修噪,我們必須在渲染前指定OpenGL該如何解釋頂點(diǎn)數(shù)據(jù)。

我們的頂點(diǎn)緩沖數(shù)據(jù)會(huì)被解析為下面這樣子:


image

因此使用glVertexAttribPointer函數(shù)告訴OpenGL該如何解析頂點(diǎn)數(shù)據(jù):

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);

第一個(gè)參數(shù)指定我們要配置的頂點(diǎn)屬性

第二個(gè)參數(shù)指定頂點(diǎn)屬性的大小路媚。

第三個(gè)參數(shù)指定數(shù)據(jù)的類型

第四個(gè)參數(shù)定義我們是否希望數(shù)據(jù)被標(biāo)準(zhǔn)化(Normalize)黄琼。如果我們?cè)O(shè)置為GL_TRUE,所有數(shù)據(jù)都會(huì)被映射到0(對(duì)于有符號(hào)型signed數(shù)據(jù)是-1)到1之間整慎。

第五個(gè)參數(shù)是步長(zhǎng)脏款,它告訴我們?cè)谶B續(xù)的頂點(diǎn)屬性組之間的間隔围苫。

最后一個(gè)參數(shù)表示位置數(shù)據(jù)在緩沖中起始位置的偏移量(Offset)。

接下來(lái)使用glEnableVertexAttribArray函數(shù)弛矛,以頂點(diǎn)屬性位置值作為參數(shù)够吩,啟用頂點(diǎn)屬性比然。

代碼最終大概長(zhǎng)這樣:

// 0. 復(fù)制頂點(diǎn)數(shù)組到緩沖中供OpenGL使用
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 1. 設(shè)置頂點(diǎn)屬性指針
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// 2. 當(dāng)我們渲染一個(gè)物體時(shí)要使用著色器程序
glUseProgram(shaderProgram);
// 3. 繪制物體
someOpenGLFunctionThatDrawsOurTriangle();

頂點(diǎn)數(shù)組對(duì)象

Vertex Array Object(VAO)可以像頂點(diǎn)緩沖對(duì)象那樣被綁定丈氓,任何隨后的頂點(diǎn)屬性調(diào)用都會(huì)儲(chǔ)存在這個(gè)VAO中。

OpenGL的核心模式要求我們使用VAO强法,所以它知道該如何處理我們的頂點(diǎn)輸入万俗。如果我們綁定VAO失敗,OpenGL會(huì)拒絕繪制任何東西饮怯。

一個(gè)頂點(diǎn)數(shù)組對(duì)象會(huì)儲(chǔ)存以下這些內(nèi)容:

glEnableVertexAttribArrayglDisableVertexAttribArray的調(diào)用闰歪。
通過glVertexAttribPointer設(shè)置的頂點(diǎn)屬性配置。
通過glVertexAttribPointer調(diào)用與頂點(diǎn)屬性關(guān)聯(lián)的頂點(diǎn)緩沖對(duì)象蓖墅。

VAO的創(chuàng)建類似VBO:

unsigned int VAO;
glGenVertexArrays(1, &VAO);

要使用VAO库倘,只需使用glBindVertexArray綁定VAO。從綁定之后起论矾,我們應(yīng)該綁定和配置對(duì)應(yīng)的VBO和屬性指針教翩,之后解綁VAO供之后使用。當(dāng)我們打算繪制一個(gè)物體的時(shí)候贪壳,我們只要在繪制物體前簡(jiǎn)單地把VAO綁定到希望使用的設(shè)定上就行了饱亿。

代碼大概是這樣的:

// ..:: 初始化代碼(只運(yùn)行一次 (除非你的物體頻繁改變)) :: ..
// 1. 綁定VAO
glBindVertexArray(VAO);
// 2. 把頂點(diǎn)數(shù)組復(fù)制到緩沖中供OpenGL使用
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 3. 設(shè)置頂點(diǎn)屬性指針
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);

[...]

// ..:: 繪制代(渲染循環(huán)中) :: ..
// 4. 繪制物體
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
someOpenGLFunctionThatDrawsOurTriangle();

繪制三角形

glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);

glDrawArrays函數(shù)第一個(gè)參數(shù)是打算繪制的圖元的類型。第二個(gè)參數(shù)制訂了頂點(diǎn)數(shù)組的起始索引闰靴,第三個(gè)參數(shù)指定我們打算繪制的頂點(diǎn)個(gè)數(shù)彪笼。

最終三角形是長(zhǎng)這樣的:

triangle.png

你可以在這里找到源碼:三角形矩形蚂且。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末配猫,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子杏死,更是在濱河造成了極大的恐慌章姓,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件识埋,死亡現(xiàn)場(chǎng)離奇詭異凡伊,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)窒舟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門系忙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人惠豺,你說(shuō)我怎么就攤上這事银还》缒” “怎么了?”我有些...
    開封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵蛹疯,是天一觀的道長(zhǎng)戒财。 經(jīng)常有香客問我,道長(zhǎng)捺弦,這世上最難降的妖魔是什么饮寞? 我笑而不...
    開封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮列吼,結(jié)果婚禮上幽崩,老公的妹妹穿的比我還像新娘。我一直安慰自己寞钥,他們只是感情好慌申,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著理郑,像睡著了一般蹄溉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上您炉,一...
    開封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天柒爵,我揣著相機(jī)與錄音,去河邊找鬼邻吭。 笑死餐弱,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的囱晴。 我是一名探鬼主播膏蚓,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼畸写!你這毒婦竟也來(lái)了驮瞧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤枯芬,失蹤者是張志新(化名)和其女友劉穎论笔,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體千所,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡狂魔,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了淫痰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片最楷。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出籽孙,到底是詐尸還是另有隱情烈评,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布犯建,位于F島的核電站讲冠,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏适瓦。R本人自食惡果不足惜竿开,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望犹菇。 院中可真熱鬧德迹,春花似錦芽卿、人聲如沸揭芍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)称杨。三九已至,卻和暖如春筷转,著一層夾襖步出監(jiān)牢的瞬間姑原,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工呜舒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留锭汛,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓袭蝗,卻偏偏與公主長(zhǎng)得像唤殴,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子到腥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容