// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Application that displays graphics using OpenGL [ES] with the intent
// of being used in functional tests.
#include <gflags/gflags.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <cmath>
#include "glinterface.h"
#include "main.h"
#include "utils.h"
GLuint GenerateAndBindTexture() {
GLuint name = ~0;
glGenTextures(1, &name);
glBindTexture(GL_TEXTURE_2D, name);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
return name;
}
unsigned char* CreateBitmap(int w, int h) {
unsigned char* bitmap = new unsigned char[4 * w * h];
unsigned char* pixel = bitmap;
float w2 = 0.5f * w;
float h2 = 0.5f * h;
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
// Fill with soft ellipse
float dx = fabs((x - w2) / w2);
float dy = fabs((y - h2) / h2);
float dist2 = dx*dx + dy*dy;
if (dist2 > 1.f)
dist2 = 1.f;
*pixel = (1.f - dist2) * 255.f;
pixel++;
*pixel = (1.f - dist2) * 255.f;
pixel++;
*pixel = (1.f - dist2) * 255.f;
pixel++;
*pixel = 0;
pixel++;
}
}
return bitmap;
}
const char kVertexShader[] =
"attribute vec4 vertices;"
"varying vec2 v1;"
"void main() {"
" gl_Position = vec4(vertices.x, vertices.y, 0.0, 1.0);"
" v1 = vec2(0.5 * vertices.x + 0.5, 0.5 * vertices.y + 0.5);"
"}";
const char kFragmentShader[] =
"uniform sampler2D tex;"
"uniform vec4 color;"
"varying vec2 v1;"
"void main() {"
" gl_FragColor = color * texture2D(tex, v1);"
"}";
// Command line flags
DEFINE_double(screenshot1_sec, 2.f, "seconds delay before screenshot1_cmd");
DEFINE_double(screenshot2_sec, 1.f, "seconds delay before screenshot2_cmd");
DEFINE_string(screenshot1_cmd, "", "system command to take a screen shot 1");
DEFINE_string(screenshot2_cmd, "", "system command to take a screen shot 2");
DEFINE_double(cooldown_sec, 1.f, "seconds delay after all screenshots");
int main(int argc, char* argv[]) {
// Configure full screen
g_width = -1;
g_height = -1;
google::ParseCommandLineFlags(&argc, &argv, true);
g_main_gl_interface.reset(GLInterface::Create());
if (!g_main_gl_interface->Init()) {
printf("# Error: Failed to initialize %s.\n", argv[0]);
return 1;
}
GLint viewport[2];
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, viewport);
printf("# MAX_VIEWPORT_DIMS=(%d, %d)\n", viewport[0], viewport[1]);
if (viewport[0] < g_width || viewport[1] < g_height) {
printf("# Error: MAX_VIEWPORT_DIMS too small\n");
return 1;
}
glViewport(0, 0, g_width, g_height);
unsigned char* bitmap = CreateBitmap(g_height, g_width);
GLuint texture = GenerateAndBindTexture();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, g_height, g_width, 0,
GL_RGBA, GL_UNSIGNED_BYTE, bitmap);
GLfloat vertices[8] = {
-1.f, -1.f,
1.f, -1.f,
-1.f, 1.f,
1.f, 1.f,
};
GLuint program = glbench::InitShaderProgram(kVertexShader, kFragmentShader);
int attribute_index = glGetAttribLocation(program, "vertices");
glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, vertices);
glEnableVertexAttribArray(attribute_index);
int texture_sampler = glGetUniformLocation(program, "tex");
glUniform1i(texture_sampler, 0);
int display_color = glGetUniformLocation(program, "color");
float white[4] = {1.0f, 1.0f, 1.0f, 1.0f};
float blue[4] = {0.5f, 0.5f, 1.0f, 1.0f};
uint64_t last_event_time = GetUTime();
enum State {
kStateScreenShot1,
kStateScreenShot2,
kStateCooldown,
kStateExit
} state = kStateScreenShot1;
float seconds_delay_for_next_state[] = {
static_cast<float>(FLAGS_screenshot1_sec),
static_cast<float>(FLAGS_screenshot2_sec),
static_cast<float>(FLAGS_cooldown_sec),
0
};
do {
// Draw
glClear(GL_COLOR_BUFFER_BIT);
if (state == kStateScreenShot1)
glUniform4fv(display_color, 1, white);
else
glUniform4fv(display_color, 1, blue);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
g_main_gl_interface->SwapBuffers();
// Loop until next event
float seconds_since_last_event =
static_cast<float>(GetUTime() - last_event_time) / 1000000ULL;
if (seconds_since_last_event < seconds_delay_for_next_state[state])
continue;
// State change. Perform action.
switch(state) {
case kStateScreenShot1:
system(FLAGS_screenshot1_cmd.c_str());
break;
case kStateScreenShot2:
system(FLAGS_screenshot2_cmd.c_str());
break;
default:
break;
}
// Advance to next state
last_event_time = GetUTime();
state = static_cast<State>(state + 1);
} while (state != kStateExit);
glDeleteTextures(1, &texture);
g_main_gl_interface->Cleanup();
return 0;
}