OpenGL ES2.0 c++ 基礎(chǔ)教程

OpenGL ES2.0 c++ 基礎(chǔ)

什么是OpenGL ES?OpenGL ES (為OpenGL for Embedded System的縮寫) 為適用于嵌入式系統(tǒng)的一個免費二維和三維圖形庫矾兜。為桌面版本OpenGL 的一個子集咱枉。OpenGL ES 定義了一個在移動平臺上能夠支持

hello world 開始吧

首先環(huán)境搭建引入必要庫窍荧。Linux windows ios android 嵌入式設(shè)備 自己的目標(biāo)設(shè)備支持什么庫。

基本庫

  • EGL
  • openGL ES2.0

以下例子程序均基于Linux平臺。

1. 保存全局變量的數(shù)據(jù)結(jié)構(gòu)

ESContext

typedef struct _escontext   
{   
   void*       userData;        // Put your user data here...   
   GLint       width;           // Window width   
   GLint       height;          // Window height   
   EGLNativeWindowType  hWnd;   // Window handle   
   EGLDisplay  eglDisplay;      // EGL display   
   EGLContext  eglContext;      // EGL context   
   EGLSurface  eglSurface;      // EGL surface   
   // Callbacks   
   void (ESCALLBACK *drawFunc) ( struct _escontext * );   
   void (ESCALLBACK *keyFunc) ( struct _escontext *, unsigned char, int, int );   
   void (ESCALLBACK *updateFunc) ( struct _escontext *, float deltaTime );   
}ESContext;  

UserData

typedef struct   
{   
   // Handle to a program object   
   GLuint programObject;   
   // Atrribute Location   
   GLint positionLoc;   
   GLint textureLoc;   
   // Uniform location   
   GLint matrixModeLoc;   
   GLint matrixViewLoc;   
   GLint matrixPerspectiveLoc;   
   // Sampler location   
   GLint samplerLoc;   
   // texture   
   GLuint texture;   
} UserData;
2. 初始化EGL渲染環(huán)境和相關(guān)元素(第一步)
  1. 獲取 EGL Display 對象:eglGetDisplay()
  2. 初始化與 EGLDisplay 之間的連接:eglInitialize()
  3. 獲取 EGLConfig 全部列表對象 :eglGetConfigs()
  4. 獲取 EGLConfig 選擇EGL對象:eglChooseConfig()
  5. 創(chuàng)建 EGLContext 實例:eglCreateContext()
  6. 創(chuàng)建 EGLSurface 實例:eglCreateWindowSurface()
  7. 設(shè)置當(dāng)前渲染API : eglBindAPI();
    1. EGL_OPENGL_API
    2. EGL_OPENGL_ES_API
    3. EGL_OPENVG_API
  8. 連接 EGLContext 和 EGLSurface:eglMakeCurrent()
int InitEGL(ESContext * esContext)   
{   
     NativeWindowType eglWindow = NULL;   
     EGLDisplay display;   
     EGLContext context;   
     EGLSurface surface;   
     EGLConfig configs[2];   
     EGLBoolean eRetStatus;   
     EGLint majorVer, minorVer;   
     EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};   
     EGLint numConfigs;   
     EGLint cfg_attribs[] = {EGL_BUFFER_SIZE,    EGL_DONT_CARE,   
                             EGL_DEPTH_SIZE,     16,   
                             EGL_RED_SIZE,       5,   
                             EGL_GREEN_SIZE,     6,   
                             EGL_BLUE_SIZE,      5,   
                             EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,   
                             EGL_NONE};   
    
    //my function       
    eglWindow = my_getEglNativeWindowType();
     // Get default display connection    
     display = eglGetDisplay((EGLNativeDisplayType)EGL_DEFAULT_DISPLAY);   
     if ( display == EGL_NO_DISPLAY )   
     {   
          return EGL_FALSE;   
     }   
     // Initialize EGL display connection   
     eRetStatus = eglInitialize(display, &majorVer, &minorVer);   
     if( eRetStatus != EGL_TRUE )   
     {   
          return EGL_FALSE;   
     }   
     //Get a list of all EGL frame buffer configurations for a display   
     eRetStatus = eglGetConfigs (display, configs, 2, &numConfigs);   
     if( eRetStatus != EGL_TRUE )   
     {   
          return EGL_FALSE;   
     }   
     // Get a list of EGL frame buffer configurations that match specified attributes   
     eRetStatus = eglChooseConfig (display, cfg_attribs, configs, 2, &numConfigs);   
     if( eRetStatus != EGL_TRUE  || !numConfigs)   
     {   
          return EGL_FALSE;   
     }   
     // Create a new EGL window surface   
     surface = eglCreateWindowSurface(display, configs[0], eglWindow, NULL);   
     if (surface == EGL_NO_SURFACE)   
     {   
          return EGL_FALSE;   
     }   
     // Set the current rendering API (EGL_OPENGL_API, EGL_OPENGL_ES_API,EGL_OPENVG_API)   
     eRetStatus = eglBindAPI(EGL_OPENGL_ES_API);   
     if (eRetStatus != EGL_TRUE)   
     {   
          return EGL_FALSE;   
     }   
     // Create a new EGL rendering context   
     context = eglCreateContext (display, configs[0], EGL_NO_CONTEXT, context_attribs);   
     if (context == EGL_NO_CONTEXT)   
     {   
          return EGL_FALSE;   
     }   
     // Attach an EGL rendering context to EGL surfaces   
     eRetStatus = eglMakeCurrent (display, surface, surface, context);   
     if( eRetStatus != EGL_TRUE )   
     {   
          return EGL_FALSE;   
     }   
     //If interval is set to a value of 0, buffer swaps are not synchronized to a video frame, and the swap happens as soon as the render is complete.   
     eglSwapInterval(display,0);   
     // Return the context elements
     esContext->eglWindow = eglWindow;
     esContext->eglDisplay = display;   
     esContext->eglSurface = surface;   
     esContext->eglContext = context;   
     return EGL_TRUE;   
}   
獲取 my_getEglNativeWindowType();
  • NativeDisplayType 平臺顯示數(shù)據(jù)類型,標(biāo)識你所開發(fā)設(shè)備的物理屏幕
  • NativeWindowType 平臺窗口數(shù)據(jù)類型,標(biāo)識系統(tǒng)窗口

下面的代碼是一個 NativeWindowType 獲取的例子叉讥。這只是一個例子,不同平臺之間的實現(xiàn)千差萬別饥追。使用 native 類型的關(guān)鍵作用在于為開發(fā)者抽象化這些細(xì)節(jié)图仓。

NativeWindowType getEglNativeWindowType(){
    NativeDisplayType EGL_display = fbGetDisplayByIndex(0);
    NativeDisplayType window;
    unsigned lond physical;
    int width, height, stride, bitsPerPixel;
    fbgetDisplayInfo(egl_display, &width, &height, &physical, &stride, &bitsPerPixel);
    window = fbCreateWindow(egl_display, 0, 0, width, height);
    assert(window);
    return window;
}
3. 生成Program (第二步)
3.1 LoadShader

實現(xiàn)shader的編譯
LoadShader主要實現(xiàn)以下功能:

  1. 創(chuàng)建Shader對象
  2. 裝載Shader源碼
  3. 編譯Shader
/* type specifies the Shader type: GL_VERTEX_SHADER or GL_FRAGMENT_SHADER */   
GLuint LoadShader ( GLenum type, const char *shaderSrc )   
{   
   GLuint shader;   
   GLint compiled;   
      
   // Create an empty shader object, which maintain the source code strings that define a shader   
   shader = glCreateShader ( type );   
   if ( shader == 0 )   
    return 0;   
   // Replaces the source code in a shader object   
   glShaderSource ( shader, 1, &shaderSrc, NULL );   
      
   // Compile the shader object   
   glCompileShader ( shader );   
   // Check the shader object compile status   
   glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled );   
   if ( !compiled )    
   {   
      GLint infoLen = 0;   
      glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen );   
         
      if ( infoLen > 1 )   
      {   
         char* infoLog = malloc (sizeof(char) * infoLen );   
         glGetShaderInfoLog ( shader, infoLen, NULL, infoLog );   
         esLogMessage ( "Error compiling shader:\n%s\n", infoLog );               
            
         free ( infoLog );   
      }   
      glDeleteShader ( shader );   
      return 0;   
   }   
   return shader;   
}   
3.1.1. 創(chuàng)建Shader對象 :glCreateShader()

它創(chuàng)建一個空的shader對象,它用于維護用來定義shader的源碼字符串但绕。支持以下兩種

  1. GL_VERTEX_SHADER:它運行在可編程的“頂點處理器”上救崔,用于代替固定功能的頂點處理
  2. GL_FRAGMENT_SHADER:它運行在可編程的“片斷處理器”上,用于代替固定功能的片段處理
3.1.2. 裝載Shader源碼:glShaderSource()

shader對象中原來的源碼全部被新的源碼所代替捏顺。

3.1.3. 編譯Shader:glCompileShader()

編譯存儲在shader對象中的源碼字符串六孵,編譯結(jié)果被當(dāng)作shader對象狀態(tài)的一部分被保存起來,可通過glGetShaderiv函數(shù)獲取編譯狀態(tài)幅骄。

3.1.4. 獲取shader對象參數(shù):glGetShaderiv()

獲取shader對象參數(shù)劫窒,參數(shù)包括:GL_SHADER_TYPE, GL_DELETE_STATUS, GL_COMPILE_STATUS, GL_INFO_LOG_LENGTH, GL_SHADER_SOURCE_LENGTH.

3.2 LoadProgram

實現(xiàn)了Program的鏈接

GLuint LoadProgram ( const char *vShaderStr, const char *fShaderStr )   
{   
   GLuint vertexShader;   
   GLuint fragmentShader;   
   GLuint programObject;   
   GLint linked;   
   // Load the vertex/fragment shaders   
   vertexShader = LoadShader ( GL_VERTEX_SHADER, vShaderStr );   
   fragmentShader = LoadShader ( GL_FRAGMENT_SHADER, fShaderStr );   
   // Create the program object   
   programObject = glCreateProgram ( );   
   if ( programObject == 0 )   
      return 0;   
   // Attaches a shader object to a program object   
   glAttachShader ( programObject, vertexShader );   
   glAttachShader ( programObject, fragmentShader );   
   // Bind vPosition to attribute 0      
   glBindAttribLocation ( programObject, 0, "vPosition" );   
   // Link the program object   
   glLinkProgram ( programObject );   
   // Check the link status   
   glGetProgramiv ( programObject, GL_LINK_STATUS, &linked );   
   if ( !linked )    
   {   
      GLint infoLen = 0;   
      glGetProgramiv ( programObject, GL_INFO_LOG_LENGTH, &infoLen );   
         
      if ( infoLen > 1 )   
      {   
         char* infoLog = malloc (sizeof(char) * infoLen );   
         glGetProgramInfoLog ( programObject, infoLen, NULL, infoLog );   
         esLogMessage ( "Error linking program:\n%s\n", infoLog );               
            
         free ( infoLog );   
      }   
      glDeleteProgram ( programObject );   
      return GL_FALSE;   
   }   
    
   // Free no longer needed shader resources   
   glDeleteShader ( vertexShader );   
   glDeleteShader ( fragmentShader );   
   return programObject;   
}   
3.2.1 創(chuàng)建Program對象 :glCreateProgram()

建立一個空的program對象,shader對象可以被連接到program對像

3.2.2 glAttachShader

program對象提供了把需要做的事連接在一起的機制拆座。在一個program中主巍,在shader對象被連接在一起之前,必須先把shader連接到program上挪凑。

3.2.3 glBindAttribLocation

把program的頂點屬性索引與頂點shader中的變量名進行綁定孕索。

3.2.4 glLinkProgram

連接程序?qū)ο蟆H绻魏晤愋蜑镚L_VERTEX_SHADER的shader對象連接到program,它將產(chǎn)生在“可編程頂點處理器”上可執(zhí)行的程 序躏碳;如果任何類型為GL_FRAGMENT_SHADER的shader對象連接到program,它將

產(chǎn)生在“可編程片斷處理器”上可執(zhí)行的程序搞旭。

3.2.5 glGetProgramiv

獲取program對象的參數(shù)值,參數(shù)有:GL_DELETE_STATUS, GL_LINK_STATUS, GL_VALIDATE_STATUS, GL_INFO_LOG_LENGTH, GL_ATTACHED_SHADERS, GL_ACTIVE_ATTRIBUTES, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH,

GL_ACTIVE_UNIFORMS, GL_ACTIVE_UNIFORM_MAX_LENGTH.

3.3 CreateProgram

實現(xiàn)了Program的源碼加載
在3.1中只實現(xiàn)了Shader的編譯菇绵,在3.2中只實現(xiàn)了Program的鏈接肄渗,現(xiàn)在還缺少真正供進行編譯和鏈接源碼

int CreateProgram(ESContext * esContext)   
{   
     GLuint programObject;   
     GLbyte vShaderStr[] =     
      "attribute vec4 vPosition;"   
      "void main()"   
      "{"   
      " gl_Position = vPosition;"   
      "}";   
      
     GLbyte fShaderStr[] =     
      "precision mediump float;"
      "void main()"   
      "{"   
      " gl_FragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 );"   
      "}";   
       
    // Create user data    
    esContext->userData = malloc(sizeof(UserData));   
    UserData *userData = esContext->userData;   
    // Load the shaders and get a linked program object   
    programObject = LoadProgram ( (const char*)vShaderStr, (const char*)fShaderStr );   
    if(programObject == 0)   
    {   
    return GL_FALSE;   
    }   
    // Store the program object   
    userData->programObject = programObject;   
    // Get the attribute locations   
    userData->positionLoc = glGetAttribLocation ( g_programObject, "v_position" );   
    glClearColor ( 0.0f, 0.0f, 0.0f, 1.0f );   
    return ELG_TRUE;   
}   

4. 安裝并執(zhí)行Program(第三步)

void Render ( ESContext *esContext )   
{   
   UserData *userData = esContext->userData;   
   GLfloat vVertices[] = {  0.0f,  0.5f, 0.0f,    
                           -0.5f, -0.5f, 0.0f,   
                            0.5f, -0.5f, 0.0f };   
         
   // Set the viewport   
   glViewport ( 0, 0, esContext->width, esContext->height );   
      
   // Clear the color buffer   
   glClear ( GL_COLOR_BUFFER_BIT );   
   // Use the program object   
   glUseProgram ( userData->programObject );   
   // Load the vertex data   
   glVertexAttribPointer ( 0, 3, GL_FLOAT, GL_FALSE, 0, vVertices );   
   glEnableVertexAttribArray ( 0 );   
   glDrawArrays ( GL_TRIANGLES, 0, 3 );   
   eglSwapBuffers(esContext->eglDisplay, esContext->eglSurface); 
4.1 glClear

清除指定的buffer到預(yù)設(shè)值×掣剩可清除以下四類buffer:

  • GL_COLOR_BUFFER_BIT
  • GL_DEPTH_BUFFER_BIT
  • GL_ACCUM_BUFFER_BIT
  • GL_STENCIL_BUFFER_BIT

預(yù)設(shè)值通過glClearColor, glClearIndex, glClearDepth, glClearStencil, 和glClearAccum來設(shè)置恳啥。

1)glClearColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)

指定color buffer的清除值偏灿,當(dāng)調(diào)用glClear(GL_COLOR_BUFFER_BIT)時才真正用設(shè)定的顏色值清除color buffer丹诀。參數(shù)值的范圍為:0~1。

2)glClearIndex(GLfloat c)

指定color index buffer清除值。

3)glClearDepth(GLclampd depth)

指定depth buffer的清除值铆遭,取值范圍為:0~1硝桩,默認(rèn)值為1。

4)glClearStencil(GLint s)

指定stencil buffer清除值的索引枚荣,初始值為0碗脊。

5)glClearAccum( GLfloat red,GLfloat green,GLfloat blue,GLfloat alpha)

指定accumulation buffer的清除值,初始值為0橄妆,取值范圍為:-1~1

4.2 glUseProgram

安裝一個program object衙伶,并把它作為當(dāng)前rendering state的一部分。

1) 當(dāng)一個可執(zhí)行程序被安裝到vertex processor害碾,下列OpenGL固定功能將被disable:
  • The modelview matrix is not applied to vertex coordinates.
  • The projection matrix is not applied to vertex coordinates.
  • The texture matrices are not applied to texture coordinates.
  • Normals are not transformed to eye coordinates.
  • Normals are not rescaled or normalized.
  • Normalization of GL_AUTO_NORMAL evaluated normals is not performed.
  • Texture coordinates are not generated automatically.
  • Per-vertex lighting is not performed.
  • Color material computations are not performed.
  • Color index lighting is not performed.
  • This list also applies when setting the current raster position.
2)當(dāng)一個可執(zhí)行程序被安裝到fragment processor矢劲,下列OpenGL固定功能將被disable:
  • Texture environment and texture functions are not applied.
  • Texture application is not applied.
  • Color sum is not applied.
  • Fog is not applied.
4.3 glVertexAttribPointer

定義一個通用頂點屬性數(shù)組。當(dāng)渲染時慌随,它指定了通用頂點屬性數(shù)組從索引index處開始的位置和數(shù)據(jù)格式芬沉。其定義如下:

void glVertexAttribPointer(   
    GLuint   index,           // 指示將被修改的通用頂點屬性的索引   
    GLint   size,             // 指點每個頂點元素個數(shù)(1~4)   
    GLenum   type,            // 數(shù)組中每個元素的數(shù)據(jù)類型   
    GLboolean   normalized,   //指示定點數(shù)據(jù)值是否被歸一化(歸一化<[-1,1]或[0,1]>:GL_TRUE,直接使用:GL_FALSE)   
    GLsizei   stride,         // 連續(xù)頂點屬性間的偏移量,如果為0阁猜,相鄰頂點屬性間緊緊相鄰   
    const GLvoid *   pointer);//頂點數(shù)組:其index應(yīng)該小于#define GL_MAX_VERTEX_ATTRIBS 0x8869
    )
4.4glEnableVertexAttribArray

Enable由索引index指定的通用頂點屬性數(shù)組丸逸。

void glEnableVertexAttribArray(GLuint index); 
void glDisableVertexAttribArray(GLuint index); 

默認(rèn)狀態(tài)下,所有客戶端的能力被disabled剃袍,包括所有通用頂點屬性數(shù)組黄刚。如果被Enable,通用頂點屬性數(shù)組中的值將被訪問并被用于rendering笛园,通過調(diào)用頂點數(shù)組命令:glDrawArrays, glDrawElements,

glDrawRangeElements, glArrayElement, glMultiDrawElements, or glMultiDrawArrays.

4.5 glDrawArrays
void glDrawArrays(GLenum mode, GLint first, GLsizei count);
  1. mode:指明render原語隘击,如:GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_TRIANGLES, GL_QUAD_STRIP, GL_QUADS, 和 GL_POLYGON。
  2. first: 指明Enable數(shù)組中起始索引研铆。
  3. count: 指明被render的原語個數(shù)埋同。

可以預(yù)先使用單獨的數(shù)據(jù)定義vertex、normal和color棵红,然后通過一個簡單的glDrawArrays構(gòu)造一系列原語凶赁。當(dāng)調(diào)用 glDrawArrays時,它使用每個enable的數(shù)組中的count個連續(xù)的元素逆甜,來構(gòu)造一系列幾何原

語虱肄,從第first個元素開始。

4.6 eglSwapBuffers

把EGL surface中的color buffer提交到native window進行顯示交煞。

EGLBoolean eglSwapBuffers(EGLDisplay display,EGLSurface surface)

5. 協(xié)調(diào)組織

在前面的描述中咏窿,三步曲已經(jīng)完成了:

  1. 初始化EGL環(huán)境,為繪圖做好準(zhǔn)備
  2. 生成Program
  3. 安裝并執(zhí)行Program

只有這三個關(guān)鍵人物素征,還不能運行集嵌,還需要一個協(xié)調(diào)組織者萝挤。

int main(int argc, char** argv)   
{   
    ESContext esContext;   
    UserData  userData;   
    int iFrames;    
    unsigned long iStartTime,iEndTime;   
    int iDeltaTime;   
    memset( &esContext, 0, sizeof( ESContext) );   
    esContext.userData = &userData;   
    esContext.width = 1280;   
    esContext.height = 720;   
    // Init EGL display, surface and context   
    if(!InitEGL(&esContext))   
    {   
        printf("Init EGL fail\n");   
        return GL_FALSE;   
    }   
    // compile shader, link program    
    if(!CreateProgram(&esContext))   
    {   
        printf("Create Program fail\n");   
        return GL_FALSE;   
    }   
    iStartTime = GetCurTime();   
    iFrames = 0;   
    while(1) {    // render a frame   
         Render();   
       iFrames++;   
           
       iEndTime = GetCurTime();   
      iDeltaTime  = iEndTime - iStartTime;   
    if(iDeltaTime >= 5000)   
    {   
        iStartTime = iEndTime;   
        float fFrame = iFrames * 1000.0 / iDeltaTime;   
        iFrames = 0;   
        printf("Frame.: %f\n", fFrame);   
    }   
    }   
    glDeleteProgram (esContext.userData->programObject);   
    return GL_TRUE;   
}  

[TOC]

總結(jié)

  1. 初始化EGL渲染環(huán)境和相關(guān)元素 (第一步)
  2. 生成Program (第二步)
    1. shader的編譯
    2. Program的鏈接
    3. CreateProgram 程序創(chuàng)建 vertex(頂點)fragment(片元)shader(著色器)源碼加載
  3. 安裝并執(zhí)行Program (第三步)
    1. 使用 OpenGL ES API 繪制圖形:gl_*()
  4. 協(xié)調(diào)組織
  5. EGL釋放資源
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市根欧,隨后出現(xiàn)的幾起案子怜珍,更是在濱河造成了極大的恐慌,老刑警劉巖凤粗,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件酥泛,死亡現(xiàn)場離奇詭異,居然都是意外死亡嫌拣,警方通過查閱死者的電腦和手機柔袁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來异逐,“玉大人瘦馍,你說我怎么就攤上這事∮σ郏” “怎么了情组?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長箩祥。 經(jīng)常有香客問我院崇,道長,這世上最難降的妖魔是什么袍祖? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任底瓣,我火速辦了婚禮,結(jié)果婚禮上蕉陋,老公的妹妹穿的比我還像新娘捐凭。我一直安慰自己,他們只是感情好凳鬓,可當(dāng)我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布茁肠。 她就那樣靜靜地躺著,像睡著了一般缩举。 火紅的嫁衣襯著肌膚如雪垦梆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天仅孩,我揣著相機與錄音托猩,去河邊找鬼。 笑死辽慕,一個胖子當(dāng)著我的面吹牛京腥,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播溅蛉,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼公浪,長吁一口氣:“原來是場噩夢啊……” “哼摆尝!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起因悲,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎勺爱,沒想到半個月后晃琳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡琐鲁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年卫旱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片围段。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡顾翼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出奈泪,到底是詐尸還是另有隱情适贸,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布涝桅,位于F島的核電站拜姿,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏冯遂。R本人自食惡果不足惜蕊肥,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蛤肌。 院中可真熱鬧壁却,春花似錦、人聲如沸裸准。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽炒俱。三九已至琅锻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間向胡,已是汗流浹背恼蓬。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留僵芹,地道東北人处硬。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像拇派,于是被迫代替她去往敵國和親荷辕。 傳聞我的和親對象是個殘疾皇子凿跳,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,612評論 2 350