代码: 改的opengles 2.0 入门指导中的demo, 在次基础之上增加VBO 调用。
// Hello_Triangle.c
//
// This is a simple example that draws a single triangle with
// a minimal vertex/fragment shader. The purpose of this
// example is to demonstrate the basic concepts of
// OpenGL ES 2.0 rendering.
#include
#include
#include
#include "esUtil.h"
GLuint _programObject;
typedef struct
{
// Handle to a program object
GLuint programObject;
} UserData;
///
// Create a shader object, load the shader source, and
// compile the shader.
//
GLuint LoadShader ( GLenum type, const char *shaderSrc )
{
GLuint shader;
GLint compiled;
// Create the shader object
shader = glCreateShader ( type );
if ( shader == 0 )
return 0;
// Load the shader source
glShaderSource ( shader, 1, &shaderSrc, NULL );
// Compile the shader
glCompileShader ( shader );
// Check the 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 = (char *)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;
}
GLuint InitShaderProgram()
{
/*
GLbyte vShaderStr[] =
"attribute vec4 vPosition; \n"
"void main() \n"
"{ \n"
" gl_Position = vPosition; \n"
"} \n";
GLbyte fShaderStr[] =
"precision mediump float;\n"\
"void main() \n"
"{ \n"
" gl_FragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 );\n"
"} \n";
*/
GLchar vShaderStr[] =
"attribute vec3 VertexPosition; \n"
"attribute vec3 VertexColor; \n"
"varying vec3 Color; \n"
"void main() \n"
"{ \n"
" Color =VertexColor; \n"
" gl_Position = vec4(VertexPosition,1.0); \n"
"} \n";
GLchar fShaderStr[] =
"varying vec3 Color; \n"
"void main() \n"
"{ \n"
" gl_FragColor = vec4(Color,1.0); \n"
"} \n";
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;
glAttachShader ( programObject, vertexShader );
glAttachShader ( programObject, fragmentShader );
// Bind vPosition to attribute 0
glBindAttribLocation ( programObject, 0, "vPosition" );
// Link the program
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 = (char* )malloc (sizeof(char) * infoLen );
glGetProgramInfoLog ( programObject, infoLen, NULL, infoLog );
esLogMessage ( "Error linking program:\n%s\n", infoLog );
free ( infoLog );
}
glDeleteProgram ( programObject );
return GL_FALSE;
}
_programObject = programObject;
return programObject;
}
void initVBO()
{
GLfloat positionData[] = { 0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f };
GLfloat colorData[] = {1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f
};
GLuint vboHandles[2];
glGenBuffers(2, vboHandles);
GLuint positionBufferHandle = vboHandles[0];
GLuint colorBufferHandle = vboHandles[1];
glBindBuffer(GL_ARRAY_BUFFER, positionBufferHandle);
glBufferData(GL_ARRAY_BUFFER, 9*sizeof(float), positionData, GL_STATIC_DRAW);
GLuint positionLocation = glGetAttribLocation(_programObject, "VertexPosition");
glEnableVertexAttribArray(positionLocation);
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
//glBindAttribLocation(_programObject, positionLocation, "VertexPosition");
glBindBuffer(GL_ARRAY_BUFFER, colorBufferHandle);
glBufferData(GL_ARRAY_BUFFER, 9*sizeof(float), colorData, GL_STATIC_DRAW);
GLuint colorLocation = glGetAttribLocation(_programObject, "VertexColor");
glEnableVertexAttribArray(colorLocation);
glVertexAttribPointer(colorLocation, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
//glBindAttribLocation(_programObject, colorLocation, "VertexColor");
}
///
// Initialize the shader and program object
//
int Init ( ESContext *esContext )
{
esContext->userData = malloc(sizeof(UserData));
UserData *userData = (UserData*)esContext->userData;
// Store the program object
userData->programObject = InitShaderProgram();
initVBO();
glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f );
return GL_TRUE;
}
///
// Draw a triangle using the shader pair created in Init()
//
void Draw ( ESContext *esContext )
{
UserData *userData = (UserData*)esContext->userData;
// 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 );
glDrawArrays ( GL_TRIANGLES, 0, 3 );
}
int main ( int argc, char *argv[] )
{
ESContext esContext;
UserData userData;
esInitContext ( &esContext );
esContext.userData = &userData;
esCreateWindow ( &esContext, "Hello Triangle", 320, 240, ES_WINDOW_RGB );
if ( !Init ( &esContext ) )
return 0;
esRegisterDrawFunc ( &esContext, Draw );
esMainLoop ( &esContext );
}
-----------------
/// \file ESUtil.h
/// \brief A utility library for OpenGL ES. This library provides a
/// basic common framework for the example applications in the
/// OpenGL ES 2.0 Programming Guide.
//
#ifndef ESUTIL_H
#define ESUTIL_H
///
// Includes
//
//OpenGL 2.0 头文件
#include
//EGL openGL_ES 与 原生窗口之间的粘合剂
#include
//是否是c++ 文件
#ifdef __cplusplus
extern "C" {
#endif
///
// Macros
//
#define ESUTIL_API
#define ESCALLBACK
/// esCreateWindow flag - RGB color buffer
#define ES_WINDOW_RGB 0
/// esCreateWindow flag - ALPHA color buffer
#define ES_WINDOW_ALPHA 1
/// esCreateWindow flag - depth buffer
#define ES_WINDOW_DEPTH 2
/// esCreateWindow flag - stencil buffer
#define ES_WINDOW_STENCIL 4
/// esCreateWindow flat - multi-sample buffer
#define ES_WINDOW_MULTISAMPLE 8
///
// Types
//
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
//定义矩阵
typedef struct
{
GLfloat m[4][4];
} ESMatrix;
//定义上下文
typedef struct _escontext
{
/// Put your user data here...
void* userData;
/// Window width
GLint width;
/// Window height
GLint height;
/// Window handle
EGLNativeWindowType hWnd;
/// EGL display
EGLDisplay eglDisplay;
/// EGL context
EGLContext eglContext;
/// EGL surface
EGLSurface eglSurface;
/// Callbacks
void (ESCALLBACK *drawFunc) ( struct _escontext * );
void (ESCALLBACK *keyFunc) ( struct _escontext *, unsigned char, int, int );
void (ESCALLBACK *updateFunc) ( struct _escontext *, float deltaTime );
} ESContext;
///
// Public Functions
//
//
///
/// \brief Initialize ES framework context. This must be called before calling any other functions.
/// \param esContext Application context
//
void ESUTIL_API esInitContext ( ESContext *esContext );
//
/// \brief Create a window with the specified parameters
/// \param esContext Application context
/// \param title Name for title bar of window
/// \param width Width in pixels of window to create
/// \param height Height in pixels of window to create
/// \param flags Bitfield for the window creation flags
/// ES_WINDOW_RGB - specifies that the color buffer should have R,G,B channels
/// ES_WINDOW_ALPHA - specifies that the color buffer should have alpha
/// ES_WINDOW_DEPTH - specifies that a depth buffer should be created
/// ES_WINDOW_STENCIL - specifies that a stencil buffer should be created
/// ES_WINDOW_MULTISAMPLE - specifies that a multi-sample buffer should be created
/// \return GL_TRUE if window creation is succesful, GL_FALSE otherwise
GLboolean ESUTIL_API esCreateWindow ( ESContext *esContext, const char *title, GLint width, GLint height, GLuint flags );
//
/// \brief Start the main loop for the OpenGL ES application
/// \param esContext Application context
//
void ESUTIL_API esMainLoop ( ESContext *esContext );
//
/// \brief Register a draw callback function to be used to render each frame
/// \param esContext Application context
/// \param drawFunc Draw callback function that will be used to render the scene
//
void ESUTIL_API esRegisterDrawFunc ( ESContext *esContext, void (ESCALLBACK *drawFunc) ( ESContext* ) );
//
/// \brief Register an update callback function to be used to update on each time step
/// \param esContext Application context
/// \param updateFunc Update callback function that will be used to render the scene
//
void ESUTIL_API esRegisterUpdateFunc ( ESContext *esContext, void (ESCALLBACK *updateFunc) ( ESContext*, float ) );
//
/// \brief Register an keyboard input processing callback function
/// \param esContext Application context
/// \param keyFunc Key callback function for application processing of keyboard input
//
void ESUTIL_API esRegisterKeyFunc ( ESContext *esContext,
void (ESCALLBACK *drawFunc) ( ESContext*, unsigned char, int, int ) );
//
/// \brief Log a message to the debug output for the platform
/// \param formatStr Format string for error log.
//
void ESUTIL_API esLogMessage ( const char *formatStr, ... );
//
///
/// \brief Load a shader, check for compile errors, print error messages to output log
/// \param type Type of shader (GL_VERTEX_SHADER or GL_FRAGMENT_SHADER)
/// \param shaderSrc Shader source string
/// \return A new shader object on success, 0 on failure
//
GLuint ESUTIL_API esLoadShader ( GLenum type, const char *shaderSrc );
//
///
/// \brief Load a vertex and fragment shader, create a program object, link program.
/// Errors output to log.
/// \param vertShaderSrc Vertex shader source code
/// \param fragShaderSrc Fragment shader source code
/// \return A new program object linked with the vertex/fragment shader pair, 0 on failure
//
GLuint ESUTIL_API esLoadProgram ( const char *vertShaderSrc, const char *fragShaderSrc );
//
/// \brief Generates geometry for a sphere. Allocates memory for the vertex data and stores
/// the results in the arrays. Generate index list for a TRIANGLE_STRIP
/// \param numSlices The number of slices in the sphere
/// \param vertices If not NULL, will contain array of float3 positions
/// \param normals If not NULL, will contain array of float3 normals
/// \param texCoords If not NULL, will contain array of float2 texCoords
/// \param indices If not NULL, will contain the array of indices for the triangle strip
/// \return The number of indices required for rendering the buffers (the number of indices stored in the indices array
/// if it is not NULL ) as a GL_TRIANGLE_STRIP
//
int ESUTIL_API esGenSphere ( int numSlices, float radius, GLfloat **vertices, GLfloat **normals,
GLfloat **texCoords, GLuint **indices );
//
/// \brief Generates geometry for a cube. Allocates memory for the vertex data and stores
/// the results in the arrays. Generate index list for a TRIANGLES
/// \param scale The size of the cube, use 1.0 for a unit cube.
/// \param vertices If not NULL, will contain array of float3 positions
/// \param normals If not NULL, will contain array of float3 normals
/// \param texCoords If not NULL, will contain array of float2 texCoords
/// \param indices If not NULL, will contain the array of indices for the triangle strip
/// \return The number of indices required for rendering the buffers (the number of indices stored in the indices array
/// if it is not NULL ) as a GL_TRIANGLES
//
int ESUTIL_API esGenCube ( float scale, GLfloat **vertices, GLfloat **normals,
GLfloat **texCoords, GLuint **indices );
//
/// \brief Loads a 24-bit TGA image from a file
/// \param fileName Name of the file on disk
/// \param width Width of loaded image in pixels
/// \param height Height of loaded image in pixels
/// \return Pointer to loaded image. NULL on failure.
//
char* ESUTIL_API esLoadTGA ( char *fileName, int *width, int *height );
//
/// \brief multiply matrix specified by result with a scaling matrix and return new matrix in result
/// \param result Specifies the input matrix. Scaled matrix is returned in result.
/// \param sx, sy, sz Scale factors along the x, y and z axes respectively
//
void ESUTIL_API esScale(ESMatrix *result, GLfloat sx, GLfloat sy, GLfloat sz);
//
/// \brief multiply matrix specified by result with a translation matrix and return new matrix in result
/// \param result Specifies the input matrix. Translated matrix is returned in result.
/// \param tx, ty, tz Scale factors along the x, y and z axes respectively
//
void ESUTIL_API esTranslate(ESMatrix *result, GLfloat tx, GLfloat ty, GLfloat tz);
//
/// \brief multiply matrix specified by result with a rotation matrix and return new matrix in result
/// \param result Specifies the input matrix. Rotated matrix is returned in result.
/// \param angle Specifies the angle of rotation, in degrees.
/// \param x, y, z Specify the x, y and z coordinates of a vector, respectively
//
void ESUTIL_API esRotate(ESMatrix *result, GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
//
// \brief multiply matrix specified by result with a perspective matrix and return new matrix in result
/// \param result Specifies the input matrix. new matrix is returned in result.
/// \param left, right Coordinates for the left and right vertical clipping planes
/// \param bottom, top Coordinates for the bottom and top horizontal clipping planes
/// \param nearZ, farZ Distances to the near and far depth clipping planes. Both distances must be positive.
//
void ESUTIL_API esFrustum(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ);
//
/// \brief multiply matrix specified by result with a perspective matrix and return new matrix in result
/// \param result Specifies the input matrix. new matrix is returned in result.
/// \param fovy Field of view y angle in degrees
/// \param aspect Aspect ratio of screen
/// \param nearZ Near plane distance
/// \param farZ Far plane distance
//
void ESUTIL_API esPerspective(ESMatrix *result, float fovy, float aspect, float nearZ, float farZ);
//
/// \brief multiply matrix specified by result with a perspective matrix and return new matrix in result
/// \param result Specifies the input matrix. new matrix is returned in result.
/// \param left, right Coordinates for the left and right vertical clipping planes
/// \param bottom, top Coordinates for the bottom and top horizontal clipping planes
/// \param nearZ, farZ Distances to the near and far depth clipping planes. These values are negative if plane is behind the viewer
//
void ESUTIL_API esOrtho(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ);
//
/// \brief perform the following operation - result matrix = srcA matrix * srcB matrix
/// \param result Returns multiplied matrix
/// \param srcA, srcB Input matrices to be multiplied
//
void ESUTIL_API esMatrixMultiply(ESMatrix *result, ESMatrix *srcA, ESMatrix *srcB);
//
\brief return an indentity matrix
\param result returns identity matrix
//
void ESUTIL_API esMatrixLoadIdentity(ESMatrix *result);
#ifdef __cplusplus
}
#endif
#endif // ESUTIL_H
-----------------------
#include
#include
#include
//接收可变参数头文件
#include
#include
#include
#include
#include "esUtil.h"
#include
#include
#include
// X11 related local variables
static Display *x_display = NULL;
///
// CreateEGLContext()
//
// Creates an EGL rendering context and all associated elements
//
EGLBoolean CreateEGLContext ( EGLNativeWindowType hWnd, EGLDisplay* eglDisplay,
EGLContext* eglContext, EGLSurface* eglSurface,
EGLint attribList[])
{
EGLint numConfigs;
EGLint majorVersion;
EGLint minorVersion;
EGLDisplay display;
EGLContext context;
EGLSurface surface;
EGLConfig config;
EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE };
// Get Display 链接本地窗口系统,参数窗口类型
display = eglGetDisplay((EGLNativeDisplayType)x_display);
if ( display == EGL_NO_DISPLAY )
{
return EGL_FALSE;
}
// Initialize EGL 初始化EGL
if ( !eglInitialize(display, &majorVersion, &minorVersion) )
{
return EGL_FALSE;
}
// Get configs 获取surface 配置
if ( !eglGetConfigs(display, NULL, 0, &numConfigs) )
{
return EGL_FALSE;
}
// Choose config
if ( !eglChooseConfig(display, attribList, &config, 1, &numConfigs) )
{
return EGL_FALSE;
}
// Create a surface //创建一块区域
surface = eglCreateWindowSurface(display, config, (EGLNativeWindowType)hWnd, NULL);
if ( surface == EGL_NO_SURFACE )
{
return EGL_FALSE;
}
// Create a GL context //创建一个渲染上下文数据结构,保存渲染状态和相关操作
context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs );
if ( context == EGL_NO_CONTEXT )
{
return EGL_FALSE;
}
// Make the context current
if ( !eglMakeCurrent(display, surface, surface, context) )
{
return EGL_FALSE;
}
*eglDisplay = display;
*eglSurface = surface;
*eglContext = context;
return EGL_TRUE;
}
///
// WinCreate()
//
// This function initialized the native X11 display and window for EGL
//
EGLBoolean WinCreate(ESContext *esContext, const char *title)
{
Window root;
XSetWindowAttributes swa;
XSetWindowAttributes xattr;
Atom wm_state;
XWMHints hints;
XEvent xev;
EGLConfig ecfg;
EGLint num_config;
Window win;
/*
* X11 native display initialization
*/
x_display = XOpenDisplay(NULL);
if ( x_display == NULL )
{
return EGL_FALSE;
}
root = DefaultRootWindow(x_display);
swa.event_mask = ExposureMask | PointerMotionMask | KeyPressMask;
win = XCreateWindow(
x_display, root,
0, 0, esContext->width, esContext->height, 0,
CopyFromParent, InputOutput,
CopyFromParent, CWEventMask,
&swa );
xattr.override_redirect = FALSE;
XChangeWindowAttributes ( x_display, win, CWOverrideRedirect, &xattr );
hints.input = TRUE;
hints.flags = InputHint;
XSetWMHints(x_display, win, &hints);
// make the window visible on the screen
XMapWindow (x_display, win);
XStoreName (x_display, win, title);
// get identifiers for the provided atom name strings
wm_state = XInternAtom (x_display, "_NET_WM_STATE", FALSE);
memset ( &xev, 0, sizeof(xev) );
xev.type = ClientMessage;
xev.xclient.window = win;
xev.xclient.message_type = wm_state;
xev.xclient.format = 32;
xev.xclient.data.l[0] = 1;
xev.xclient.data.l[1] = FALSE;
XSendEvent (
x_display,
DefaultRootWindow ( x_display ),
FALSE,
SubstructureNotifyMask,
&xev );
esContext->hWnd = (EGLNativeWindowType) win;
return EGL_TRUE;
}
///
// userInterrupt()
//
// Reads from X11 event loop and interrupt program if there is a keypress, or
// window close action.
//
GLboolean userInterrupt(ESContext *esContext)
{
XEvent xev;
KeySym key;
GLboolean userinterrupt = GL_FALSE;
char text;
// Pump all messages from X server. Keypresses are directed to keyfunc (if defined)
while ( XPending ( x_display ) )
{
XNextEvent( x_display, &xev );
if ( xev.type == KeyPress )
{
if (XLookupString(&xev.xkey,&text,1,&key,0)==1)
{
if (esContext->keyFunc != NULL)
esContext->keyFunc(esContext, text, 0, 0);
}
}
if ( xev.type == DestroyNotify )
userinterrupt = GL_TRUE;
}
return userinterrupt;
}
//
//
// Public Functions
//
//
///
// esInitContext()
//
// Initialize ES utility context. This must be called before calling any other
// functions.
//
void ESUTIL_API esInitContext ( ESContext *esContext )
{
if ( esContext != NULL )
{
memset( esContext, 0, sizeof( ESContext) );
}
}
///
// esCreateWindow()
//
// title - name for title bar of window
// width - width of window to create
// height - height of window to create
// flags - bitwise or of window creation flags
// ES_WINDOW_ALPHA - specifies that the framebuffer should have alpha
// ES_WINDOW_DEPTH - specifies that a depth buffer should be created
// ES_WINDOW_STENCIL - specifies that a stencil buffer should be created
// ES_WINDOW_MULTISAMPLE - specifies that a multi-sample buffer should be created
//
GLboolean ESUTIL_API esCreateWindow ( ESContext *esContext, const char* title, GLint width, GLint height, GLuint flags )
{
EGLint attribList[] =
{
EGL_RED_SIZE, 5,
EGL_GREEN_SIZE, 6,
EGL_BLUE_SIZE, 5,
EGL_ALPHA_SIZE, (flags & ES_WINDOW_ALPHA) ? 8 : EGL_DONT_CARE,
EGL_DEPTH_SIZE, (flags & ES_WINDOW_DEPTH) ? 8 : EGL_DONT_CARE,
EGL_STENCIL_SIZE, (flags & ES_WINDOW_STENCIL) ? 8 : EGL_DONT_CARE,
EGL_SAMPLE_BUFFERS, (flags & ES_WINDOW_MULTISAMPLE) ? 1 : 0,
EGL_NONE
};
if ( esContext == NULL )
{
return GL_FALSE;
}
esContext->width = width;
esContext->height = height;
if ( !WinCreate ( esContext, title) )
{
return GL_FALSE;
}
if ( !CreateEGLContext ( esContext->hWnd,
&esContext->eglDisplay,
&esContext->eglContext,
&esContext->eglSurface,
attribList) )
{
return GL_FALSE;
}
return GL_TRUE;
}
///
// esMainLoop()
//
// Start the main loop for the OpenGL ES application
//
void ESUTIL_API esMainLoop ( ESContext *esContext )
{
struct timeval t1, t2;
struct timezone tz;
float deltatime;
float totaltime = 0.0f;
unsigned int frames = 0;
gettimeofday ( &t1 , &tz );
while(userInterrupt(esContext) == GL_FALSE)
{
gettimeofday(&t2, &tz);
deltatime = (float)(t2.tv_sec - t1.tv_sec + (t2.tv_usec - t1.tv_usec) * 1e-6);
t1 = t2;
if (esContext->updateFunc != NULL)
esContext->updateFunc(esContext, deltatime);
if (esContext->drawFunc != NULL)
esContext->drawFunc(esContext);
eglSwapBuffers(esContext->eglDisplay, esContext->eglSurface);
totaltime += deltatime;
frames++;
if (totaltime > 2.0f)
{
printf("%4d frames rendered in %1.4f seconds -> FPS=%3.4f\n", frames, totaltime, frames/totaltime);
totaltime -= 2.0f;
frames = 0;
}
}
}
///
// esRegisterDrawFunc()
//
void ESUTIL_API esRegisterDrawFunc ( ESContext *esContext, void (ESCALLBACK *drawFunc) (ESContext* ) )
{
esContext->drawFunc = drawFunc;
}
///
// esRegisterUpdateFunc()
//
void ESUTIL_API esRegisterUpdateFunc ( ESContext *esContext, void (ESCALLBACK *updateFunc) ( ESContext*, float ) )
{
esContext->updateFunc = updateFunc;
}
///
// esRegisterKeyFunc()
//
void ESUTIL_API esRegisterKeyFunc ( ESContext *esContext,
void (ESCALLBACK *keyFunc) (ESContext*, unsigned char, int, int ) )
{
esContext->keyFunc = keyFunc;
}
///
// esLogMessage()
//
// Log an error message to the debug output for the platform
//
void ESUTIL_API esLogMessage ( const char *formatStr, ... )
{
va_list params;
char buf[BUFSIZ];
va_start ( params, formatStr );
vsprintf ( buf, formatStr, params );
printf ( "%s", buf );
va_end ( params );
}
///
// esLoadTGA()
//
// Loads a 24-bit TGA image from a file. This is probably the simplest TGA loader ever.
// Does not support loading of compressed TGAs nor TGAa with alpha channel. But for the
// sake of the examples, this is sufficient.
//
char* ESUTIL_API esLoadTGA ( char *fileName, int *width, int *height )
{
char *buffer = NULL;
FILE *f;
unsigned char tgaheader[12];
unsigned char attributes[6];
unsigned int imagesize;
f = fopen(fileName, "rb");
if(f == NULL) return NULL;
if(fread(&tgaheader, sizeof(tgaheader), 1, f) == 0)
{
fclose(f);
return NULL;
}
if(fread(attributes, sizeof(attributes), 1, f) == 0)
{
fclose(f);
return 0;
}
*width = attributes[1] * 256 + attributes[0];
*height = attributes[3] * 256 + attributes[2];
imagesize = attributes[4] / 8 * *width * *height;
buffer = malloc(imagesize);
if (buffer == NULL)
{
fclose(f);
return 0;
}
if(fread(buffer, 1, imagesize, f) != imagesize)
{
free(buffer);
return NULL;
}
fclose(f);
return buffer;
}
-------------
------------
VBO 调用步骤:
GLuint vboHandles[1];
glGenBuffers(1, vboHandles); //生成VBO对象
GLuint positionBufferHandle = vboHandles[0];
glBindBuffer(GL_ARRAY_BUFFER, positionBufferHandle); //绑定VBO,在GPU内存中分配内存空间
glBufferData(GL_ARRAY_BUFFER, 9*sizeof(float), positionData, GL_STATIC_DRAW); //绑定具体数据
GLuint positionLocation = glGetAttribLocation(_programObject, "VertexPosition");
glEnableVertexAttribArray(positionLocation); //绑定shader 中 attribute
glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); //告诉数据启示位置
glDrawArrays ( GL_TRIANGLES, 0, 3 ); //渲染