OpenGL ES:Android平臺(tái)EGL環(huán)境

前言

這篇文章簡(jiǎn)單介紹一下在Android平臺(tái)下的EGL環(huán)境的相關(guān)內(nèi)容毙沾,由于OpenGL ES并不負(fù)責(zé)窗口管理以及上下文管理柑司,該職責(zé)由各個(gè)平臺(tái)自行完成;在Android平臺(tái)下OpenGL ES的上下文環(huán)境是依賴(lài)EGL的API進(jìn)行搭建的。

對(duì)于EGL這個(gè)框架微饥,谷歌已經(jīng)提供了GLSurfaceView挡闰,是一個(gè)已經(jīng)封裝EGL相關(guān)處理的工具類(lèi)乒融,但是不夠靈活;對(duì)于更加核心的OpengGL ES的用法(例如多線程共享紋理)則需要開(kāi)發(fā)者自行搭建EGL開(kāi)發(fā)環(huán)境摄悯。

按照慣例先上一份源碼 AndroidVideo赞季。
Java相關(guān)核心實(shí)現(xiàn)在 EglBase14.javaEglBase10.java
Native相關(guān)實(shí)現(xiàn)奢驯,可以參考 egl_base.cpp申钩。


前置知識(shí)

Java層實(shí)現(xiàn)
在Java層,EGL封裝了兩套框架瘪阁,分別是:

  • 位于javax.microedition.khronos.egl包下的EGL10撒遣。
  • 位于android.opengl包下的EGL14

其主要區(qū)別是:

  • EGL14是在Android 4.2(API 17)引入的管跺,換言之API 17以下的版本不支持EGL14义黎。
  • EGL10不支持OpenGL ES 2.x,因此在EGL10中某些相關(guān)常量參數(shù)只能用手寫(xiě)硬編碼代替豁跑,例如EGL14.EGL_CONTEXT_CLIENT_VERSION以及EGL14.EGL_OPENGL_ES2_BIT等等廉涕。

PS:由于主體流程基本一致,所以本篇以EGL14的代碼進(jìn)行示例。

Native層實(shí)現(xiàn)
程序在Native層使用EGL環(huán)境時(shí)狐蜕。
需要引入EGL的so庫(kù):

Android.mk:

LOCAL_LDLIBS += -lEGL

CMake:

find_library( EGL-lib
        EGL )

需要包含頭文件:

#include <EGL/egl.h>
#include <EGL/eglext.h>

EGL環(huán)境配置整體流程

  1. 獲取默認(rèn)的EGLDisplay壶愤。
  2. 對(duì)EGLDisplay進(jìn)行初始化。
  3. 輸入預(yù)設(shè)置的參數(shù)獲取EGL支持的EGLConfig馏鹤。
  4. 通過(guò)EGLDisplayEGLConfig創(chuàng)建一個(gè)EGLContext上下文環(huán)境征椒。
  5. 創(chuàng)建一個(gè)EGLSurface來(lái)連接EGL和設(shè)備的屏幕。
  6. 在渲染線程綁定EGLSurfaceEGLContext湃累。
  7. 【進(jìn)行OpenGL ES的API渲染步驟】(與EGL無(wú)關(guān))
  8. 調(diào)用SwapBuffer進(jìn)行雙緩沖切換顯示渲染畫(huà)面勃救。
  9. 釋放EGL相關(guān)資源EGLSurfaceEGLContext治力、EGLDisplay蒙秒。

獲取顯示設(shè)備

首先,EGL是需要知道繪制內(nèi)容的目標(biāo)在哪里宵统,EGLDisplay是一個(gè)封裝了物理屏幕的數(shù)據(jù)類(lèi)型晕讲,也可以理解為繪制目標(biāo)的一個(gè)抽象。

通常通過(guò)eglGetDisplay()方法返回EGLDisplay來(lái)作為OpenGL ES的渲染目標(biāo)马澈,在該方法中瓢省,一般來(lái)說(shuō)都會(huì)將常量EGL_DEFAULT_DISPLAY傳進(jìn)方法中,而各個(gè)手機(jī)廠商則會(huì)返回默認(rèn)的顯示設(shè)備痊班。

java代碼:

EGLDisplay eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
//需判斷是否成功獲取EGLDisplay
if (eglDisplay == EGL14.EGL_NO_DISPLAY) {
    throw new RuntimeException("Unable to get EGL14 display");
}

c代碼:

EGLDisplay egl_display;
egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
//需判斷是否成功獲取EGLDisplay
if (egl_display == EGL_NO_DISPLAY)
    return error;

一般來(lái)說(shuō)勤婚,我們需要驗(yàn)證eglGetDisplay()的返回值,如果是EGL_NO_DISPLAY的話涤伐,那么就是沒(méi)有獲取默認(rèn)顯示設(shè)備馒胆,需要返回給客戶(hù)端上層處理異常。

當(dāng)我們獲取到了EGLDisplay凝果,我們需要調(diào)用eglInitialize()對(duì)其進(jìn)行初始化祝迂,該方法會(huì)返回一個(gè)bool變量代表執(zhí)行是否成功。

java代碼:

int version[] = new int[2];
if (!EGL14.eglInitialize(eglDisplay, version, 0, version, 1)) {
    throw new RuntimeException("Unable to initialize EGL14");
}

c代碼:

EGLint major, minor;
if (!eglInitialize(egl_display, &major, &minor))
    return error;

方法的后面參數(shù)代表MajorMinor的版本器净,比如EGL的版本號(hào)是1.0型雳,那么Major將返回1,Minor返回0掌动。
如果不關(guān)心版本號(hào)四啰,這兩個(gè)參數(shù)可以傳入NULL


配置輸出格式

當(dāng)我們獲取到EGLDisplay后粗恢,其實(shí)已經(jīng)可以將OpenGL ES的輸出與設(shè)備的屏幕橋接起來(lái)了柑晒,但是還是需要指定一些配置項(xiàng),例如色彩格式眷射、像素格式匙赞、RGBA的表示以及SurfaceType等佛掖,實(shí)際上也就是指FrameBuffer的配置參數(shù)。

一般來(lái)說(shuō)不同平臺(tái)的EGL標(biāo)準(zhǔn)是不同的涌庭,以下是Android平臺(tái)一個(gè)比較通用的配置參數(shù)(Java的就不列舉了):

const EGLint config_attribs[] = {
        EGL_BUFFER_SIZE, 32,   //顏色緩沖區(qū)中所有組成顏色的位數(shù)
        EGL_ALPHA_SIZE, 8,     //顏色緩沖區(qū)中透明度位數(shù)
        EGL_BLUE_SIZE, 8,      //顏色緩沖區(qū)中藍(lán)色位數(shù)
        EGL_GREEN_SIZE, 8,     //顏色緩沖區(qū)中綠色位數(shù)
        EGL_RED_SIZE, 8,       //顏色緩沖區(qū)中紅色位數(shù)
        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,  //渲染窗口支持的布局組成
        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,  //EGL 窗口支持的類(lèi)型
        EGL_NONE
};

PS:EGL的參數(shù)配置一般都以 id芥被,value 依次存放,對(duì)于個(gè)別的屬性可以只有 id 沒(méi)有 value 坐榆,并以EGL_NONE標(biāo)識(shí)結(jié)尾信息拴魄。
最終可以通過(guò)調(diào)用eglChooseConfig()方法得到配置選項(xiàng)信息:

java代碼:

EGLConfig[] configs = new EGLConfig[1];
int[] numConfigs = new int[1];
//檢測(cè)返回值是否成功
if (!EGL14.eglChooseConfig(eglDisplay, configAttributes, 0, configs, 0, configs.length,
        numConfigs, 0)) {
    throw new RuntimeException("eglChooseConfig failed");
}
//如果沒(méi)有配置的Config
if (numConfigs[0] < 0) {
    throw new RuntimeException("Unable to find any matching EGL config");
}
EGLConfig eglConfig = configs[0];
//對(duì)應(yīng)的Config不存在
if (eglConfig == null) {
    throw new RuntimeException("eglChooseConfig returned null");
}

c代碼:

EGLint num_config;
EGLConfig  egl_config;
//檢測(cè)返回值是否成功
if (!eglChooseConfig(egl_display, config_attribs, &egl_config, 1, &num_config))
        return error;
//如果沒(méi)有配置的Config
if (num_config < 0)
        return error;
//對(duì)應(yīng)的Config不存在
if (_egl_config == NULL)
        return error;

簡(jiǎn)單看一下函數(shù)原型:eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size,EGLint *num_config)可以知道:
第2個(gè)參數(shù)attrib_list指的是配置參數(shù)列表,也就是上面的config_attribs[]席镀;
第3個(gè)參數(shù)configs返回輸出的EGLConfigs數(shù)據(jù)匹中,可能有多個(gè);
第4個(gè)參數(shù)config_size則表示最多需要輸出多少個(gè)EGLConfig豪诲;
第5個(gè)參數(shù)num_config則代表滿(mǎn)足配置參數(shù)的EGLConfig的個(gè)數(shù)顶捷。

附帶一個(gè)EGLConfig屬性表格:

屬性 描述 默認(rèn)值
EGL_BUFFER_SIZE 顏色緩沖區(qū)中所有組成顏色的位數(shù) 0
EGL_RED_SIZE 顏色緩沖區(qū)中紅色位數(shù) 0
EGL_GREEN_SIZE 顏色緩沖區(qū)中綠色位數(shù) 0
EGL_BLUE_SIZE 顏色緩沖區(qū)中藍(lán)色位數(shù) 0
EGL_LUMINANCE_SIZE 顏色緩沖區(qū)中亮度位數(shù) 0
EGL_ALPHA_SIZE 顏色緩沖區(qū)中透明度位數(shù) 0
EGL_ALPHA_MASK_SIZE 遮擋緩沖區(qū)透明度掩碼位數(shù) 0
EGL_BIND_TO_TEXTURE_RGB 綁定到 RGB 貼圖使能為真 EGL_DONT_CARE
EGL_BIND_TO_TEXTURE_RGBA 綁定到 RGBA 貼圖使能為真 EGL_DONT_CARE
EGL_COLOR_BUFFER_TYPE 顏色緩沖區(qū)類(lèi)型 EGL_RGB_BUFFER, 或者EGL_LUMINANCE_BUFFER EGL_RGB_BUFFER
EGL_CONFIG_CAVEAT 配置有關(guān)的警告信息 EGL_DONT_CARE
EGL_CONFIG_ID 唯一的 EGLConfig 標(biāo)示值 EGL_DONT_CARE
EGL_CONFORMANT 使用EGLConfig 創(chuàng)建的上下文符合要求時(shí)為真
EGL_DEPTH_SIZE 深度緩沖區(qū)位數(shù) 0
EGL_LEVEL 幀緩沖區(qū)水平 0
EGL_MAX_PBUFFER_WIDTH 使用EGLConfig 創(chuàng)建的PBuffer的最大寬度
EGL_MAX_PBUFFER_HEIGHT 使用EGLConfig 創(chuàng)建的PBuffer最大高度
EGL_MAX_PBUFFER_PIXELS 使用EGLConfig 創(chuàng)建的PBuffer最大尺寸
EGL_MAX_SWAP_INTERVAL 最大緩沖區(qū)交換間隔 EGL_DONT_CARE
EGL_MIN_SWAP_INTERVAL 最小緩沖區(qū)交換間隔 EGL_DONT_CARE
EGL_NATIVE_RENDERABLE 如果操作系統(tǒng)渲染庫(kù)能夠使用EGLConfig 創(chuàng)建渲染渲染窗口 EGL_DONT_CARE
EGL_NATIVE_VISUAL_ID 與操作系統(tǒng)通訊的可視ID句柄 EGL_DONT_CARE
EGL_NATIVE_VISUAL_TYPE 與操作系統(tǒng)通訊的可視ID類(lèi)型 EGL_DONT_CARE
EGL_RENDERABLE_TYPE 渲染窗口支持的布局組成標(biāo)示符的遮擋位EGL_OPENGL_ES_BIT, EGL_OPENGL_ES2_BIT, orEGL_OPENVG_BIT that EGL_OPENGL_ES_BIT
EGL_SAMPLE_BUFFERS 可用的多重采樣緩沖區(qū)位數(shù) 0
EGL_SAMPLES 每像素多重采樣數(shù) 0
EGL_S TENCIL_SIZE 模板緩沖區(qū)位數(shù) 0
EGL_SURFACE_TYPE EGL 窗口支持的類(lèi)型EGL_WINDOW_BIT, EGL_PIXMAP_BIT,或EGL_PBUFFER_BIT EGL_WINDOW_BIT
EGL_TRANSPARENT_TYPE 支持的透明度類(lèi)型 EGL_NONE
EGL_TRANSPARENT_RED_VALUE 透明度的紅色解釋 EGL_DONT_CARE
EGL_TRANSPARENT_GRE EN_VALUE 透明度的綠色解釋 EGL_DONT_CARE
EGL_TRANSPARENT_BLUE_VALUE 透明度的蘭色解釋 EGL_DONT_CARE

創(chuàng)建EGL上下文環(huán)境

當(dāng)拿到EGLDisplayEGLConfig后,就可以開(kāi)始創(chuàng)建EGL的上下文環(huán)境EGLContext了屎篱。
EGLContext的存在是因?yàn)?code>OpenGL ES所創(chuàng)建的資源對(duì)于開(kāi)發(fā)者來(lái)說(shuō)可見(jiàn)的僅僅只是一個(gè) ID 而已服赎,而其實(shí)際內(nèi)容依賴(lài)于這個(gè)上下文。
一個(gè)EGLContext只能在一個(gè)線程中使用交播,如果將EGLContext所持有的OpengGL資源在多線程間共享重虑,那么需要用到共享上下文(share context)。

簡(jiǎn)單看下EGLContext的創(chuàng)建代碼:

java代碼:

//指定OpenGL ES2版本
int[] contextAttributes = {EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE};
//創(chuàng)建EGLContext上下文
EGLContext eglContext = EGL14.eglCreateContext(eglDisplay, eglConfig, null, contextAttributes, 0);
//需要檢測(cè)Context是否存在
if (eglContext == EGL14.EGL_NO_CONTEXT) {
    throw new RuntimeException("Failed to create EGL context");
}

c代碼:

EGLContext egl_context;
//指定OpenGL ES2版本
const EGLint context_attribs[] = {
      EGL_CONTEXT_CLIENT_VERSION, 2,
      EGL_NONE
};
//創(chuàng)建EGLContext上下文
egl_context = eglCreateContext(egl_display, egl_config, NULL, context_attribs);
//需要檢測(cè)Context是否存在
if (egl_context == EGL_NO_CONTEXT)
    return error;

函數(shù)eglCreateContext()的第三個(gè)參數(shù)可以傳入一個(gè)EGLContext的變量堪侯,該變量的意義是指可以與正在創(chuàng)建的上下文環(huán)境共享OpenGL ES資源嚎尤,包括紋理、FrameBuffer以及其他的Buffer等資源伍宦。
如果傳入NULL代表不需要與其他的OpenGL ES上下文共享任何資源。


連接EGL和設(shè)備屏幕

當(dāng)我們需要將EGL跟設(shè)備的屏幕橋接起來(lái)時(shí)乏梁,我們需要用到EGLSurfaceEGL有一個(gè)“橋”的功能次洼,從而使得OpenGL ES的輸出可以渲染到設(shè)備屏幕上;
EGLSurface其實(shí)就是一個(gè)FrameBuffer遇骑,通過(guò)EGL庫(kù)提供的eglCreateWindowSurface()可以創(chuàng)建一個(gè)可實(shí)際顯示的Surface卖毁;也可以通過(guò)EGL庫(kù)提供的eglCreatePbufferSurface()方法創(chuàng)建一個(gè)OffScreenSurface

java代碼:

//創(chuàng)建可顯示的Surface
EGLSurface eglSurface;
int[] surfaceAttribs = {EGL14.EGL_NONE};
eglSurface = EGL14.eglCreateWindowSurface(eglDisplay, eglConfig, surface, surfaceAttribs, 0);
if (eglSurface == EGL14.EGL_NO_SURFACE) {
    throw new RuntimeException("Failed to create window surface");
}

這里需要強(qiáng)調(diào)一點(diǎn)的是eglCreateWindowSurface()的第三個(gè)入?yún)?code>surface雖然可以傳入Object落萎;但是在EGL14中只支持SurfaceSurfaceTexture亥啦,在EGL10中只支持SurfaceHolderSurfaceTexture

c代碼:

//創(chuàng)建可顯示的Surface
EGLSurface egl_surface;
const EGLint attribs[] = { EGL_NONE };
egl_surface = eglCreateWindowSurface(egl_display, egl_config, window, attribs);
if (egl_surface == EGL_NO_SURFACE)
    return error;

在Native層练链,eglCreateWindowSurface()的第三個(gè)入?yún)?code>window是需要傳入一個(gè)ANativeWindow對(duì)象翔脱,也就是本地設(shè)備屏幕的表示。

我們可以通過(guò)Surface(由SurfaceView或者TextureView獲得或者構(gòu)建出來(lái)的Surface對(duì)象)來(lái)構(gòu)建ANativeWindow媒鼓。
需要引入頭文件:

#include <android/native_window.h>
#include <android/native_window_jni.h>

獲取ANativeWindow的代碼如下:

//surface也就是一個(gè)jobject届吁,對(duì)應(yīng)java層的Surface错妖。
ANativeWindow *window = ANativeWindow_fromSurface(env, surface);

如果我們要做離屏渲染的話,就需要用到離屏處理的Surface疚沐,也就是創(chuàng)建一個(gè)PBufferSurface暂氯,PBufferSurface的保存位置是在顯存中的幀,具體代碼可以參考亮蛔。

java代碼:

//創(chuàng)建離屏Surface
EGLSurface eglSurface;
int[] surfaceAttribs = {
        EGL14.EGL_WIDTH, width,
        EGL14.EGL_HEIGHT, height,
        EGL14.EGL_NONE
};
eglSurface = EGL14.eglCreatePbufferSurface(eglDisplay, eglConfig, surfaceAttribs, 0);
if (eglSurface == EGL14.EGL_NO_SURFACE) {
    throw new RuntimeException("Failed to create pixel buffer surface");
}

c代碼:

//創(chuàng)建離屏Surface
EGLSurface egl_surface;
const EGLint attribs[] = {
    EGL_WIDTH, width,
    EGL_HEIGHT, height,
    EGL_NONE
};
egl_surface = eglCreatePbufferSurface(egl_display, egl_config, attribs);
if (egl_surface == EGL_NO_SURFACE)
    return error;

另外說(shuō)一點(diǎn)痴施,EGLSurface還支持參數(shù)的查詢(xún)與設(shè)置,例如我們想知道新創(chuàng)建的Surface的寬高究流,那么可以用到下面的方法晾剖。

java代碼:

//查詢(xún)Surface的width
int[] array = new int[1];
EGL14.eglQuerySurface(eglDisplay, eglSurface, EGL14.EGL_WIDTH, array, 0);
//設(shè)置Surface的width
if (!EGL14.eglSurfaceAttrib(eglDisplay, eglSurface, EGL14.EGL_WIDTH, 600))
    throw new RuntimeException("eglSurfaceAttrib fail");

c代碼:

//查詢(xún)Surface的width
EGLint value;
eglQuerySurface(_egl_display, _egl_surface, EGL_WIDTH, &value);
//設(shè)置Surface的width
if (!eglSurfaceAttrib(_egl_display, _egl_surface, EGL_WIDTH, 600))
    return error;

EGL變量與線程的綁定

一般來(lái)說(shuō),開(kāi)發(fā)者需要為OpenGL ES開(kāi)辟一個(gè)新的線程梯嗽,來(lái)執(zhí)行渲染操作齿尽,并且需要為該線程綁定顯示設(shè)備EGLSurface和上下文環(huán)境EGLContext

每個(gè)線程都需要綁定一個(gè)上下文灯节,才可以開(kāi)始執(zhí)行OpenGL ES指令循头,我們可以通過(guò)eglMakeCurrent來(lái)為該線程綁定SurfaceContext,值得注意一點(diǎn)的是一個(gè)EGLContext只能綁定到一個(gè)線程上面炎疆。

java代碼:

if (!EGL14.eglMakeCurrent(eglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT)) {
    throw new RuntimeException("detachCurrent failed");
}

c代碼:

if (!eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context))
    return error;

可以通過(guò)返回值來(lái)判斷eglMakeCurrent()是否成功卡骂,這個(gè)也是必要的。


OpenGL的渲染

涉及到OpenGl ES的繪圖API和紋理相關(guān)方面的知識(shí)形入,本篇這里不做介紹全跨,請(qǐng)關(guān)注后續(xù)相關(guān)文章。


雙緩沖機(jī)制

EGL在初始化的時(shí)候默認(rèn)設(shè)置的是雙緩沖模式亿遂,也就是兩份FrameBuffer;
即一份緩沖用于繪制圖像浓若,一份緩沖用于顯示圖像,每次顯示時(shí)需要交換兩份緩沖蛇数。
我們需要在OpenGL ES繪制完畢后挪钓,調(diào)用

eglSwapBuffers(egl_display, egl_surface);

將前臺(tái)的FrameBuffer和后臺(tái)FrameBuffer進(jìn)行交換。


EGL的資源釋放

當(dāng)然耳舅,EGL在我們不需要的時(shí)候也是需要進(jìn)行釋放的碌上。
我們需要將線程跟EGL環(huán)境解除綁定:

eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);

然后要銷(xiāo)毀EGLSurface:

eglDestroySurface(egl_display, egl_surface);

接著清理掉上下文環(huán)境:

eglDestroyContext(egl_display, egl_context);

最終關(guān)閉掉顯示設(shè)備:

eglTerminate(egl_display);

通過(guò)上面也就是完成了一個(gè)EGL的資源釋放工作。


最后說(shuō)一些

在Android平臺(tái)上面浦徊,當(dāng)程序切到后臺(tái)的時(shí)候馏予,需要釋放EGL環(huán)境,在應(yīng)用挪回前臺(tái)時(shí)盔性,重新初始化相關(guān)環(huán)境霞丧。
不過(guò)谷歌提供了一個(gè)已經(jīng)封裝完善的GLSurfaceView提供OpenGL ES的繪制環(huán)境,普通需求下采用GLSurfaceView進(jìn)行繪制也是一個(gè)不錯(cuò)的選擇纯出。
有興趣可以讀讀這篇文章:源碼解析:Android源碼GLSurfaceView源碼解析蚯妇。
最后放一個(gè)EGL的官方文檔地址敷燎。


結(jié)語(yǔ)

這篇文章簡(jiǎn)單介紹了一下Android平臺(tái)下的EGL環(huán)境的相關(guān)內(nèi)容,并提供了基于java層EGL14和native層的EGL相關(guān)API的使用示例箩言。
后續(xù)文章將介紹怎么在EGL環(huán)境下進(jìn)行OpenGL ES相關(guān) API的一些使用硬贯。

本文同步發(fā)布于簡(jiǎn)書(shū)CSDN陨收。

End!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末饭豹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子务漩,更是在濱河造成了極大的恐慌拄衰,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件饵骨,死亡現(xiàn)場(chǎng)離奇詭異翘悉,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)居触,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén)妖混,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人轮洋,你說(shuō)我怎么就攤上這事制市。” “怎么了弊予?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵祥楣,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我汉柒,道長(zhǎng)误褪,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任竭翠,我火速辦了婚禮振坚,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘斋扰。我一直安慰自己,他們只是感情好啃洋,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布传货。 她就那樣靜靜地躺著,像睡著了一般宏娄。 火紅的嫁衣襯著肌膚如雪问裕。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,760評(píng)論 1 289
  • 那天孵坚,我揣著相機(jī)與錄音粮宛,去河邊找鬼窥淆。 笑死,一個(gè)胖子當(dāng)著我的面吹牛巍杈,可吹牛的內(nèi)容都是我干的忧饭。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼筷畦,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼词裤!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起鳖宾,我...
    開(kāi)封第一講書(shū)人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤吼砂,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后鼎文,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體渔肩,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年拇惋,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了周偎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蚤假,死狀恐怖栏饮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情磷仰,我是刑警寧澤袍嬉,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站灶平,受9級(jí)特大地震影響伺通,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜逢享,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一罐监、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瞒爬,春花似錦弓柱、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至禀横,卻和暖如春屁药,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背柏锄。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工酿箭, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留复亏,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓缭嫡,卻偏偏與公主長(zhǎng)得像缔御,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子械巡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

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