1/*
2* Copyright 2011 The Android Open Source Project
3*
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at
7*
8* http://www.apache.org/licenses/LICENSE-2.0
9*
10* Unless required by applicable law or agreed to in writing, software
11* distributed under the License is distributed on an "AS IS" BASIS,
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13* See the License for the specific language governing permissions and
14* limitations under the License.
15*/
16
17#include <stdio.h>
18#include <string.h>
19#include <stdlib.h>
20#include <unistd.h>
21
22//#define GL_API
23//#define GL_APIENTRY
24
25#undef ANDROID
26#include <EGL/egl.h>
27#include <GLES2/gl2.h>
28
29#ifdef __APPLE__
30extern "C" void * createGLView(void *nsWindowPtr, int x, int y, int width, int height);
31#endif
32
33#undef HAVE_MALLOC_H
34#include <SDL.h>
35#include <SDL_syswm.h>
36
37
38#define WINDOW_WIDTH    500
39#define WINDOW_HEIGHT   500
40
41#define TEX_WIDTH 256
42#define TEX_HEIGHT 256
43
44
45#define F_to_X(d) ((d) > 32767.65535 ? 32767 * 65536 + 65535 :  \
46               (d) < -32768.65535 ? -32768 * 65536 + 65535 : \
47               ((GLfixed) ((d) * 65536)))
48#define X_to_F(x)  ((float)(x))/65536.0f
49
50//#define __FIXED__
51
52const char *def_vShaderStr =
53       "attribute vec4 vPosition;   \n"
54       "void main()                 \n"
55       "{                           \n"
56       "   gl_Position = vPosition; \n"
57       "}                           \n";
58
59const char *def_fShaderStr =
60       "precision mediump float;                   \n"
61       "void main()                                \n"
62       "{                                          \n"
63#ifndef __FIXED__
64       " gl_FragColor = vec4(0.2, 0.5, 0.1, 1.0); \n"
65#else
66       " gl_FragColor = vec4(0.4, 0.3, 0.7, 1.0); \n"
67#endif
68       "}                                          \n";
69
70static EGLint const attribute_list[] = {
71    EGL_RED_SIZE, 1,
72    EGL_GREEN_SIZE, 1,
73    EGL_BLUE_SIZE, 1,
74    EGL_NONE
75};
76
77unsigned char *genTexture(int width, int height, int comp)
78{
79    unsigned char *img = new unsigned char[width * height * comp];
80    unsigned char *ptr = img;
81    for (int i = 0; i < height; i++) {
82        for (int j = 0; j < width; j++) {
83            unsigned char col = ((i / 8 + j / 8) % 2) * 255 ;
84            for (int c = 0; c < comp; c++) {
85                *ptr = col; ptr++;
86            }
87        }
88    }
89    return img;
90}
91
92unsigned char *genRedTexture(int width, int height, int comp)
93{
94    unsigned char *img = new unsigned char[width * height * comp];
95        memset(img,0,width*height*comp);
96    unsigned char *ptr = img;
97    for (int i = 0; i < height; i++) {
98        for (int j = 0; j < width; j++) {
99            unsigned char col = ((i / 8 + j / 8) % 2) * 255 ;
100                        *ptr = col;
101                         ptr+=comp;
102        }
103    }
104    return img;
105}
106
107
108void printUsage(const char *progname)
109{
110    fprintf(stderr, "usage: %s [options]\n", progname);
111    fprintf(stderr, "\t-vs <filename>  - vertex shader to use\n");
112    fprintf(stderr, "\t-fs <filename>  - fragment shader to use\n");
113}
114
115
116
117GLuint LoadShader(GLenum type,const char *shaderSrc)
118{
119   GLuint shader;
120   GLint compiled;
121   // Create the shader object
122    shader = glCreateShader(type);
123   if(shader == 0)
124       return 0;
125   // Load the shader source
126   glShaderSource(shader, 1, &shaderSrc, NULL);
127    // Compile the shader
128   glCompileShader(shader);
129    // Check the compile status
130   glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
131   if(!compiled)
132   {
133       GLint infoLen = 0;
134       glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
135       if(infoLen > 1)
136       {
137          char* infoLog = (char*)malloc(sizeof(char) * infoLen);
138          glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
139          printf("Error compiling shader:\n%s\n", infoLog);
140          free(infoLog);
141       }
142       glDeleteShader(shader);
143       return 0;
144   }
145   return shader;
146}
147
148const char *readShader(const char *fileName)
149{
150    FILE *fp = fopen(fileName, "rb");
151    if (!fp) return NULL;
152
153    int bSize = 1024;
154    int nBufs = 1;
155    char *buf = (char *)malloc(bSize);
156    int n;
157    int len = 0;
158    n = fread(&buf[0], 1, bSize, fp);
159    while( n == bSize ) {
160        len += n;
161        nBufs++;
162        buf = (char *)realloc(buf, bSize * nBufs);
163        n = fread(&buf[len], 1, bSize, fp);
164    }
165    len += n;
166
167    buf[len] = '\0';
168    return (const char *)buf;
169}
170
171void dumpUniforms(GLuint program)
172{
173    GLint numU;
174    glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &numU);
175    printf("==== Program %d has %d active uniforms ===\n", program, numU);
176    char name[512];
177    GLsizei len;
178    GLint size;
179    GLenum type;
180    for (int i=0; i<numU; i++) {
181        glGetActiveUniform(program, i,
182                           512, &len, &size, &type, name);
183        printf("\t%s : type=0x%x size=%d\n", name, type, size);
184    }
185}
186
187///
188// Initialize the shader and program object
189//
190int Init(const char *vShaderStr, const char *fShaderStr)
191{
192   GLuint vertexShader;
193   GLuint fragmentShader;
194   GLuint programObject;
195   GLint linked;
196  // Load the vertex/fragment shaders
197  vertexShader = LoadShader(GL_VERTEX_SHADER, vShaderStr);
198  fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fShaderStr);
199  // Create the program object
200  programObject = glCreateProgram();
201  if(programObject == 0)
202     return -1;
203  glAttachShader(programObject, vertexShader);
204  glAttachShader(programObject, fragmentShader);
205  // Bind vPosition to attribute 0
206  glBindAttribLocation(programObject, 0, "vPosition");
207  // Link the program
208  glLinkProgram(programObject);
209  // Check the link status
210  glGetProgramiv(programObject, GL_LINK_STATUS, &linked);
211  if(!linked)
212  {
213     GLint infoLen = 0;
214     glGetProgramiv(programObject, GL_INFO_LOG_LENGTH, &infoLen);
215     if(infoLen > 1)
216     {
217        char* infoLog = (char*)malloc(sizeof(char) * infoLen);
218        glGetProgramInfoLog(programObject, infoLen, NULL, infoLog);
219        printf("Error linking program:\n%s\n", infoLog);
220        free(infoLog);
221     }
222     glDeleteProgram(programObject);
223     return -1;
224  }
225
226  // dump active uniforms
227  dumpUniforms(programObject);
228
229  // Store the program object
230#ifndef __FIXED__
231  glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
232#else
233  glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
234#endif
235  return programObject;
236}
237
238
239///
240// Draw a triangle using the shader pair created in Init()
241//
242void Draw(EGLDisplay display,EGLSurface surface,int width,int height,GLuint program)
243{
244#ifndef __FIXED__
245   GLfloat vVertices[] = {0.0f, 0.5f, 0.0f,
246                           -0.5f, -0.5f, 0.0f,
247                           0.5f, -0.5f, 0.0f};
248#else
249
250   GLfixed vVertices[] = {F_to_X(0.0f), F_to_X(0.5f),F_to_X(0.0f),
251                           F_to_X(-0.5f),F_to_X(-0.5f), F_to_X(0.0f),
252                           F_to_X(0.5f),F_to_X(-0.5f),F_to_X(0.0f)};
253#endif
254
255    // Set the viewport
256   glViewport(0, 0,width,height);
257    // Clear the color buffer
258   glClear(GL_COLOR_BUFFER_BIT);
259    // Use the program object
260   glUseProgram(program);
261   // Load the vertex data
262#ifndef __FIXED__
263   glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vVertices);
264#else
265   glVertexAttribPointer(0, 3, GL_FIXED, GL_FALSE, 0, vVertices);
266#endif
267   glEnableVertexAttribArray(0);
268   glDrawArrays(GL_TRIANGLES, 0, 3);
269   eglSwapBuffers(display,surface);
270}
271
272#ifdef _WIN32
273char **parseCmdLine(char *cmdLine, int *argc)
274{
275    int argvSize = 10;
276    char **argv = (char **)malloc(argvSize * sizeof(char *));
277    *argc = 0;
278    int i=0;
279    bool prevIsSpace = true;
280    int argStart = 0;
281
282    argv[(*argc)++] = strdup("playdump");
283
284    while(cmdLine[i] != '\0') {
285        bool isSpace = (cmdLine[i] == ' ' || cmdLine[i] == '\t');
286        if ( !isSpace && prevIsSpace ) {
287            argStart = i;
288        }
289        else if (isSpace && !prevIsSpace) {
290            cmdLine[i] = '\0';
291            if (*argc >= argvSize) {
292                argvSize *= 2;
293                argv = (char **)realloc(argv, argvSize * sizeof(char *));
294            }
295            argv[(*argc)++] = &cmdLine[argStart];
296            argStart = i+1;
297        }
298
299        prevIsSpace = isSpace;
300        i++;
301    }
302
303    if (i > argStart) {
304        argv[(*argc)++] = &cmdLine[argStart];
305    }
306    return argv;
307}
308#endif
309
310#ifdef _WIN32
311int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
312#else
313int main(int argc, char **argv)
314#endif
315{
316#ifdef _WIN32
317    int argc;
318    char **argv = parseCmdLine(lpCmdLine, &argc);
319#endif
320    const char *vShader = def_vShaderStr;
321    const char *fShader = def_fShaderStr;
322
323    for (int i=1; i<argc; i++) {
324        if (!strcmp(argv[i],"-vs")) {
325            if (++i >= argc) {
326                printUsage(argv[0]);
327                return -1;
328            }
329            vShader = readShader(argv[i]);
330            if (!vShader) {
331                vShader = def_vShaderStr;
332                printf("Failed to load vshader %s, using defualt\n", argv[i]);
333            }
334            else {
335                printf("Using vshader %s\n", argv[i]);
336            }
337        }
338        else if (!strcmp(argv[i],"-fs")) {
339            if (++i >= argc) {
340                printUsage(argv[0]);
341                return -1;
342            }
343            fShader = readShader(argv[i]);
344            if (!fShader) {
345                fShader = def_fShaderStr;
346                printf("Failed to load fshader %s, using defualt\n", argv[i]);
347            }
348            else {
349                printf("Using fshader %s\n", argv[i]);
350            }
351        }
352        else {
353            printUsage(argv[0]);
354            return -1;
355        }
356    }
357
358    #ifdef _WIN32
359        HWND   windowId = NULL;
360    #elif __linux__
361        Window windowId = 0;
362    #elif __APPLE__
363        void* windowId  = NULL;
364    #endif
365
366        //      // Inialize SDL window
367        //
368        if (SDL_Init(SDL_INIT_NOPARACHUTE | SDL_INIT_VIDEO)) {
369            fprintf(stderr,"SDL init failed: %s\n", SDL_GetError());
370            return -1;
371        }
372
373        SDL_Surface *surface = SDL_SetVideoMode(WINDOW_WIDTH,WINDOW_HEIGHT, 32, SDL_HWSURFACE);
374        if (surface == NULL) {
375            fprintf(stderr,"Failed to set video mode: %s\n", SDL_GetError());
376            return -1;
377        }
378
379        SDL_SysWMinfo  wminfo;
380        memset(&wminfo, 0, sizeof(wminfo));
381        SDL_GetWMInfo(&wminfo);
382    #ifdef _WIN32
383        windowId = wminfo.window;
384    #elif __linux__
385        windowId = wminfo.info.x11.window;
386    #elif __APPLE__
387        windowId = createGLView(wminfo.nsWindowPtr,0,0,WINDOW_WIDTH,WINDOW_HEIGHT);
388    #endif
389
390        int major,minor,num_config;
391        int attrib_list[] ={
392                                EGL_CONTEXT_CLIENT_VERSION, 2,
393                                EGL_NONE
394                           };
395        EGLConfig configs[150];
396        EGLSurface egl_surface;
397        EGLContext ctx;
398        EGLDisplay d = eglGetDisplay(EGL_DEFAULT_DISPLAY);
399        eglInitialize(d,&major,&minor);
400        printf("DISPLAY == %p major =%d minor = %d\n",d,major,minor);
401        eglChooseConfig(d, attribute_list, configs, 150, &num_config);
402        printf("config returned %d\n",num_config);
403        egl_surface = eglCreateWindowSurface(d,configs[0],windowId,NULL);
404        ctx = eglCreateContext(d,configs[0],EGL_NO_CONTEXT,attrib_list);
405        printf("SURFACE == %p CONTEXT == %p\n",egl_surface,ctx);
406        if(eglMakeCurrent(d,egl_surface,egl_surface,ctx)!= EGL_TRUE){
407            printf("make current failed\n");
408            return false;
409        }
410        printf("after make current\n");
411
412        GLenum err = glGetError();
413        if(err != GL_NO_ERROR) {
414        printf("error before drawing ->>> %d  \n",err);
415        } else {
416        printf("no error before drawing\n");
417        }
418
419        int program = Init(vShader, fShader);
420        if(program  < 0){
421            printf("failed init shaders\n");
422            return false;
423        }
424
425        Draw(d,egl_surface,WINDOW_WIDTH,WINDOW_HEIGHT,program);
426
427                err = glGetError();
428                if(err != GL_NO_ERROR)
429            printf("error ->>> %d  \n",err);
430        eglDestroySurface(d,egl_surface);
431        eglDestroyContext(d,ctx);
432
433// Just wait until the window is closed
434        SDL_Event ev;
435        while( SDL_WaitEvent(&ev) ) {
436            if (ev.type == SDL_QUIT) {
437                break;
438            }
439        }
440    return 0;
441}
442
443
444