I am trying to apply a texture to a quad, but I only get a black box instead of the texture. I am using DevIL to load images from files and OpenGL does the rest.
Here is what I am doing so far:
The following class abstracts the DevIL representation for an image.
#include "Image.h"
Image::Image()
{
ilGenImages(1, &this->imageId);
}
Image::~Image()
{
ilDeleteImages(1, &this->imageId);
}
ILint Image::getWidth()
{
return this->width;
}
ILint Image::getHeight()
{
return this->height;
}
ILint Image::getDepth()
{
return this->depth;
}
ILint Image::getBpp()
{
return this->bpp;
}
ILint Image::getFormat()
{
return this->format;
}
ILubyte* Image::getData()
{
return ilGetData();
}
bool Image::loadFromFile(wchar_t *filename)
{
// Load the image from file.
ILboolean retval = ilLoadImage(filename);
if (!retval) {
ILenum error;
while ((error = ilGetError()) != IL_NO_ERROR) {
wcout << error << L" " << iluErrorString(error);
}
return false;
}
this->width = ilGetInteger(IL_IMAGE_WIDTH);
this->height = ilGetInteger(IL_IMAGE_HEIGHT);
this->depth = ilGetInteger(IL_IMAGE_DEPTH);
this->bpp = ilGetInteger(IL_IMAGE_BPP);
this->format = ilGetInteger(IL_IMAGE_FORMAT);
return true;
}
bool Image::convert()
{
ILboolean retval = ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE);
if (!retval) {
ILenum error;
while ((error = ilGetError()) != IL_NO_ERROR) {
wcout << error << L" " << iluErrorString(error);
}
return false;
}
return true;
}
bool Image::scale(ILint width, ILint height, ILint depth)
{
ILboolean retval = iluScale(width, height, depth);
if (!retval) {
ILenum error;
while ((error = ilGetError()) != IL_NO_ERROR) {
wcout << error << L" " << iluErrorString(error);
}
return false;
}
return true;
}
void Image::bind()
{
ilBindImage(this->imageId);
}
This class abstracts the texture representation for OpenGL.
#include "Texture.h"
Texture::Texture(int width, int height)
{
glGenTextures(1, &this->textureId);
this->width = width;
this->height = height;
}
int Texture::getWidth()
{
return this->width;
}
int Texture::getHeight()
{
return this->height;
}
void Texture::initFilter()
{
// We will use linear interpolation for magnification filter.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// We will use linear interpolation for minifying filter.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
void Texture::unpack()
{
glPixelStoref(GL_UNPACK_ALIGNMENT, 1);
}
void Texture::bind()
{
glBindTexture(GL_TEXTURE_2D, this->textureId);
}
Texture::~Texture()
{
glDeleteTextures(1, &this->textureId);
}
The following class contains the texture loading process.
#include "TextureLoader.h"
void TextureLoader::initialize()
{
if (ilGetInteger(IL_VERSION_NUM) < IL_VERSION) {
debug("Wrong DevIL version detected.");
return;
}
ilInit();
ilutRenderer(ILUT_OPENGL);
}
Texture* TextureLoader::createTexture(wchar_t *filename, Color *color)
{
// Generate some space for an image and bind it.
Image *image = new Image();
image->bind();
bool retval = image->loadFromFile(filename);
if (!retval) {
debug("Could not load image from file.");
return 0;
}
retval = image->convert();
if (!retval) {
debug("Could not convert image from RGBA to unsigned byte");
}
int pWidth = getNextPowerOfTwo(image->getWidth());
int pHeight = getNextPowerOfTwo(image->getHeight());
int size = pWidth * pHeight;
retval = image->scale(pWidth, pHeight, image->getDepth());
if (!retval) {
debug("Could not scale image from (w: %i, h: %i) to (w: %i, h: %i) with depth %i.", image->getWidth(), image->getHeight(), pWidth, pHeight, image->getDepth());
return 0;
}
// Generate some space for a texture and bind it.
Texture *texture = new Texture(image->getWidth(), image->getHeight());
texture->bind();
// Set the interpolation filters.
texture->initFilter();
// Unpack pixels.
texture->unpack();
ILubyte *imageData = image->getData();
TextureLoader::setColorKey(imageData, size, new Color(0, 0, 0));
TextureLoader::colorize(imageData, size, new Color(255, 0, 0));
debug("bpp: %i", image->getBpp());
debug("width: %i", image->getWidth());
debug("height: %i", image->getHeight());
debug("format: %i", image->getFormat());
// Map image data to texture data.
glTexImage2D(GL_TEXTURE_2D, 0, image->getBpp(), image->getWidth(), image->getHeight(), 0, image->getFormat(), GL_UNSIGNED_BYTE, imageData);
delete image;
return texture;
}
void TextureLoader::setColorKey(ILubyte *imageData, int size, Color *color)
{
for (int i = 0; i < size * 4; i += 4)
{
if (imageData[i] == color->r && imageData[i + 1] == color->g && imageData[i + 2] == color->b)
{
imageData[i + 3] = 0;
}
}
}
void TextureLoader::colorize(ILubyte *imageData, int size, Color *color)
{
for (int i = 0; i < size * 4; i += 4)
{
int rr = (int(imageData[i]) * int(color->r)) >> 8;
int rg = (int(imageData[i + 1]) * int(color->g)) >> 8;
int rb = (int(imageData[i + 2]) * int(color->b)) >> 8;
int fak = int(imageData[i]) * 5 - 4 * 256 - 138;
if (fak > 0)
{
rr += fak;
rg += fak;
rb += fak;
}
rr = rr < 255 ? rr : 255;
rg = rg < 255 ? rg : 255;
rb = rb < 255 ? rb : 255;
imageData[i] = rr > 0 ? (GLubyte) rr : 1;
imageData[i + 1] = rg > 0 ? (GLubyte) rg : 1;
imageData[i + 2] = rb > 0 ? (GLubyte) rb : 1;
}
}
The last class does the drawing.
#include "Texturizer.h"
void Texturizer::draw(Texture *texture, float x, float y, float angle)
{
// Enable texturing.
glEnable(GL_TEXTURE_2D);
// Bind the texture for drawing.
texture->bind();
// Enable alpha blending.
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
int width = texture->getWidth();
int height = texture->getHeight();
// Create centered dimension vectors.
b2Vec2 vertices[4];
vertices[0] = 0.5f * b2Vec2(- width, - height);
vertices[1] = 0.5f * b2Vec2(+ width, - height);
vertices[2] = 0.5f * b2Vec2(+ width, + height);
vertices[3] = 0.5f * b2Vec2(- width, + height);
b2Mat22 matrix = b2Mat22();
matrix.Set(angle);
glBegin(GL_QUADS);
for (int i = 0; i < 4; i++) {
float texCoordX = i == 0 || i == 3 ? 0.0f : 1.0f;
float texCoordY = i < 2 ? 0.0f : 1.0f;
glTexCoord2f(texCoordX, texCoordY);
// Rotate and move vectors.
b2Vec2 vector = b2Mul(matrix, vertices[i]) + meter2pixel(b2Vec2(x, y));
glVertex2f(vector.x, vector.y);
}
glEnd();
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
}
Last but not least, the following method initializes OpenGL (and triggers the initialization of DevIL):
void GraphicsEngine::initialize(int argc, char **argv)
{
// Initialize the window.
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutInitWindowSize(WIDTH, HEIGHT);
// Set shading model.
glShadeModel(GL_SMOOTH);
// Create the window.
this->mainWindow = glutCreateWindow(TITLE);
// Set keyboard methods.
glutKeyboardFunc(&onKeyDownCallback);
glutKeyboardUpFunc(&onKeyUpCallback);
glutSpecialFunc(&onSpecialKeyDownCallback);
glutSpecialUpFunc(&onSpecialKeyUpCallback);
// Set mouse callbacks.
glutMouseFunc(&onMouseButtonCallback);
#ifdef FREEGLUT
glutMouseWheelFunc(&onMouseWheelCallback);
#endif
glutMotionFunc(&onMouseMotionCallback);
glutPassiveMotionFunc(&onMousePassiveMotionCallback);
// Set display callbacks.
glutDisplayFunc(&onDrawCallback);
glutReshapeFunc(&onReshapeCallback);
// Set a timer to control the frame rate.
glutTimerFunc(FRAME_PERIOD, onTimerTickCallback, 0);
// Set clear color.
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
Camera::getInstance()->subscribe(this);
// Initialize texture loader.
TextureLoader::initialize();
}
The image I am using already worked for another OpenGL/DevIL project, so it cannot be the source of the problem.
The texture is created inside of every class which represents a world object (it's a game...). The character is called Blobby and here are the most important parts of its implementation:
#include "Blobby.h"
Blobby::Blobby()
{
this->isJumping = false;
this->isRotating = false;
this->isWalking = false;
this->isDucking = false;
this->isStandingUp = false;
this->isOnGround = false;
this->isTouchingWall = false;
this->angle = 0;
this->direction = DIRECTION_UNKNOWN;
this->wallDirection = DIRECTION_UNKNOWN;
// Create a red blobby texture.
this->texture = TextureLoader::createTexture(L"D:/01.bmp", new Color(255, 0, 0));
ContactListener::getInstance()->subscribe(this);
}
void Blobby::draw()
{
GraphicsEngine::drawString(35, 40, "isOnGround = %s", this->isOnGround ? "true" : "false");
GraphicsEngine::drawString(35, 55, "inJumping = %s", this->isJumping ? "true" : "false");
GraphicsEngine::drawString(35, 70, "isRotating = %s", this->isRotating ? "true" : "false");
GraphicsEngine::drawString(35, 85, "isTouchingWall = %s (%i)", this->isTouchingWall ? "true" : "false", this->wallDirection);
Texturizer::draw(this->texture, this->getBody(0)->GetPosition().x, this->getBody(0)->GetPosition().y, this->getBody(0)->GetAngle());
AbstractEntity::draw(); // draws debug information... not important
}
The OpenGL timer callback calls a step method which ends here:
void Simulator::step()
{
// Update physics.
this->gameWorld->step();
b2Vec2 p = Camera::convertWorldToScreen(meter2pixel(this->cameraBlobby->getBody(0)->GetPosition().x), 300.0f);
if (p.x < 300) {
Camera::getInstance()->setViewCenter(Camera::convertScreenToWorld(400 - (300 - int(p.x)), 300));
} else if (p.x > 500) {
Camera::getInstance()->setViewCenter(Camera::convertScreenToWorld(400 + (int(p.x) - 500), 300));
}
for (unsigned int i = 0; i < this->gameWorld->getEntityCount(); i++) {
IEntity *entity = this->gameWorld->getEntity(i);
entity->draw();
}
}
IEntity is a pure virtual class (i.e. interface), AbstractEntity implements this interface and adds global methods. Blobby inherits from AbstractEntity and adds routines which are special for this world object.
EDIT:
I have uploaded a more recent version of the code (the whole project incl. dependencies) here:
http://upload.visusnet.de/uploads/BlobbyWarriors-rev19.zip (~9.5 MB)
I'm not familiar with DevIL, but... are you providing the right diffuse color for your vertices? If lighting is enabled, are there some lights pointing on the quad? Does the camera look at the front side of the quad?
EDIT:
You got a bug in the code, but not the one you posted here, but in the version in the archive you linked.
You call glColor3i(255, 255, 255), and it sets the diffuse color to (very nearly) black as expected. glColor3i does not accept the color values in the target (calculation or framebuffer) range. The possible values are scaled to the entire range of the int type. This means the maximum value (1.0 in float) is represented by MAX_INT (2,147,483,647)
, 0 is 0, and -1.0 is MIN_INT (-2,147,483,648). The 255 value you provided represents about 0.000000118, which is very nearly zero.
I believe you intended one of the following (completely equivalent) forms:
glColor3f(1.0, 1.0, 1.0), glColor3ub(255, 255, 255),
glColor3i(2147483647, 2147483647, 2147483647).
What is in the b2Mat22 matrix? Could it be that multiplying by this matrix is causing your vertices to be drawn in a clockwise order, because I think in that case your square's back would be facing you, and the texture might be on the other (invisible) side.
I had an issue like this a long time ago, I think back then it was a problem with the texture dimensions not being an exponent of 2 (128x128, 512x512, etc.). I'm sure they've fixed that by now, but it might be something to try.
Related
I am having a problem with Opengl and Opengl ES. I want to make squares with png image textures and render text in front of these squares.
I can make squares with textures from png images, and I can render text from ttf like in this example, but it works only if not executing at the same time. I will try to explain better (The example code is too dirty because the code I'm getting from one software is more structured and bigger, and this code is only for an example):
I have one GLProgram with one Vertex Shader and one Fragment Shader for texture squares. I have another GLProgram with another Vertex Shader and another Fragment Shader to make Renderer text.
If I load all the GL programs and only draw each frame only the texture square, I can see it perfectly.
If I draw the renderer text (using his GLprogram) before or after the texture square (doing his glUseProgram before drawing the square) I can only see the texture text on screen and the background color that's created with (glClearColor(x.xf, x.xf, x.xf, x.xf)) and I can't see the texture square.
Does anyone know where the error is in the code?
Now I will post the shaders and the example source code:
back.v.glsl:
attribute vec4 g_vPosition;
attribute vec3 g_vColor;
attribute vec2 g_vTexCoord;
varying vec3 g_vVSColor;
varying vec2 g_vVSTexCoord;
void main()
{
gl_Position = g_vPosition;
g_vVSColor = g_vColor;
g_vVSTexCoord = g_vTexCoord;
}
back.f.glsl:
uniform sampler2D s_texture;
varying vec3 g_vVSColor;
varying vec2 g_vVSTexCoord;
void main()
{
gl_FragColor = texture2D(s_texture,g_vVSTexCoord);
}
text.v.glsl:
attribute vec4 coord;
varying vec2 texpos;
void main(void) {
gl_Position = vec4(coord.xy, 0, 1);
texpos = coord.zw;
}
text.f.glsl:
varying vec2 texpos;
uniform sampler2D tex;
uniform vec4 color;
void main(void) {
//gl_FragColor = vec4(1, 1, 1, texture2D(tex, texpos).a) * color;
gl_FragColor = vec4(color.rgb, texture2D(tex, texpos).a);
}
Source Code:
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <assert.h>
#include <math.h>
#include <signal.h>
#include <GLES2/gl2.h>
#include <EGL/egl.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <unistd.h>
#include <sys/time.h>
#include <png.h>
EGLDisplay egldisplay;
EGLConfig eglconfig;
EGLSurface eglsurface;
EGLContext eglcontext;
EGLNativeWindowType eglNativeWindow;
EGLNativeDisplayType eglNativeDisplayType;
#include <ft2build.h>
#include FT_FREETYPE_H
GLuint program;
GLint attribute_coord;
GLint uniform_tex;
GLint uniform_color;
GLuint programBack;
GLint coordBack = 0;
GLint texBack = 2;
GLint colorBack = 1;
struct point {
GLfloat x;
GLfloat y;
GLfloat s;
GLfloat t;
};
GLuint vbo;
FT_Library ft;
FT_Face face;
// Maximum texture width
#define MAXWIDTH 800
const char *fontfilename;
float VertexColors[] = {
/* Red */
1.0f, 0.0f, 0.0f, 1.0f,
/* Red */
1.0f, 0.0f, 0.0f, 1.0f,
/* Green */
0.0f, 1.0f, 0.0f, 1.0f,
/* Green */
0.0f, 1.0f, 0.0f, 1.0f,
};
float VertexTexCoords[] = {
/* Front Face */
0.0f,0.0f,
1.0f,0.0f,
0.0f,1.0f,
1.0f,1.0f,
};
float fBackgroundPosition[12] = {
/* Bottom Left Of The Quad (Front) */
-1.0f,-1.0f,1.0f,
/* Bottom Right Of The Quad (Front) */
1.0f,-1.0f,1.0f,
/* Top Left Of The Quad (Front) */
-1.0f,1.0f,1.0f,
/* Top Right Of The Quad (Front) */
1.0f,1.0f,1.0f,
};
GLuint glTextures[4];
/**
* The atlas struct holds a texture that contains the visible US-ASCII characters
* of a certain font rendered with a certain character height.
* It also contains an array that contains all the information necessary to
* generate the appropriate vertex and texture coordinates for each character.
*
* After the constructor is run, you don't need to use any FreeType functions anymore.
*/
struct atlas {
GLuint tex; // texture object
unsigned int w; // width of texture in pixels
unsigned int h; // height of texture in pixels
struct {
float ax; // advance.x
float ay; // advance.y
float bw; // bitmap.width;
float bh; // bitmap.height;
float bl; // bitmap_left;
float bt; // bitmap_top;
float tx; // x offset of glyph in texture coordinates
float ty; // y offset of glyph in texture coordinates
} c[256]; // character information
atlas(FT_Face face, int height) {
FT_Set_Pixel_Sizes(face, 0, height);
FT_GlyphSlot g = face->glyph;
unsigned int roww = 0;
unsigned int rowh = 0;
w = 0;
h = 0;
memset(c, 0, sizeof c);
/* Find minimum size for a texture holding all visible ASCII characters */
//for (int i = 32; i < 128; i++) {
for (int i = 32; i < 254; i++) {
if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
fprintf(stderr, "Loading character %c failed!\n", i);
continue;
}
if (roww + g->bitmap.width + 1 >= MAXWIDTH) {
w = std::max(w, roww);
h += rowh;
roww = 0;
rowh = 0;
}
roww += g->bitmap.width + 1;
rowh = std::max(rowh, g->bitmap.rows);
}
w = std::max(w, roww);
h += rowh;
/* Create a texture that will be used to hold all ASCII glyphs */
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glUniform1i(uniform_tex, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0);
/* We require 1 byte alignment when uploading texture data */
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
/* Clamping to edges is important to prevent artifacts when scaling */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
/* Linear filtering usually looks best for text */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
/* Paste all glyph bitmaps into the texture, remembering the offset */
int ox = 0;
int oy = 0;
rowh = 0;
//for (int i = 32; i < 128; i++) {
for (int i = 32; i < 254; i++) {
if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
fprintf(stderr, "Loading character %c failed!\n", i);
continue;
}
if (ox + g->bitmap.width + 1 >= MAXWIDTH) {
oy += rowh;
rowh = 0;
ox = 0;
}
glTexSubImage2D(GL_TEXTURE_2D, 0, ox, oy, g->bitmap.width, g->bitmap.rows, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer);
c[i].ax = g->advance.x >> 6;
c[i].ay = g->advance.y >> 6;
c[i].bw = g->bitmap.width;
c[i].bh = g->bitmap.rows;
c[i].bl = g->bitmap_left;
c[i].bt = g->bitmap_top;
c[i].tx = ox / (float)w;
c[i].ty = oy / (float)h;
rowh = std::max(rowh, g->bitmap.rows);
ox += g->bitmap.width + 1;
}
fprintf(stderr, "Generated a %d x %d (%d kb) texture atlas\n", w, h, w * h / 1024);
}
~atlas() {
glDeleteTextures(1, &tex);
}
};
atlas *a48;
atlas *a24;
atlas *a12;
//#define GL_ES_VERSION_2_0
/**
* Store all the file's contents in memory, useful to pass shaders
* source code to OpenGL
*/
char* file_read(const char* filename)
{
FILE* in = fopen(filename, "rb");
if (in == NULL) return NULL;
int res_size = BUFSIZ;
char* res = (char*)malloc(res_size);
int nb_read_total = 0;
while (!feof(in) && !ferror(in)) {
if (nb_read_total + BUFSIZ > res_size) {
if (res_size > 10 * 1024 * 1024) break;
res_size = res_size * 2;
res = (char*)realloc(res, res_size);
}
char* p_res = res + nb_read_total;
nb_read_total += fread(p_res, 1, BUFSIZ, in);
}
fclose(in);
res = (char*)realloc(res, nb_read_total + 1);
res[nb_read_total] = '\0';
return res;
}
/**
* Compile the shader from file 'filename', with error handling
*/
GLuint create_shader(const char* filename, GLenum type)
{
const GLchar* source = file_read(filename);
if (source == NULL) {
fprintf(stderr, "Error opening %s: ", filename); perror("");
return 0;
}
else {
printf("Load shader correctly %s\n", filename);
}
GLuint res = glCreateShader(type);
const GLchar* sources[] = {
// Define GLSL version
#ifdef GL_ES_VERSION_2_0
"#version 100\n" // OpenGL ES 2.0
#else
"#version 120\n" // OpenGL 2.1
#endif
,
// GLES2 precision specifiers
#ifdef GL_ES_VERSION_2_0
// Define default float precision for fragment shaders:
(type == GL_FRAGMENT_SHADER) ?
"#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
"precision highp float; \n"
"#else \n"
"precision mediump float; \n"
"#endif \n"
: ""
// Note: OpenGL ES automatically defines this:
// #define GL_ES
#else
// Ignore GLES 2 precision specifiers:
"#define lowp \n"
"#define mediump\n"
"#define highp \n"
#endif
,
source };
glShaderSource(res, 3, sources, NULL);
free((void*)source);
glCompileShader(res);
GLint compile_ok = GL_FALSE;
glGetShaderiv(res, GL_COMPILE_STATUS, &compile_ok);
if (compile_ok == GL_FALSE) {
fprintf(stderr, "%s:", filename);
//print_log(res);
glDeleteShader(res);
return 0;
}
return res;
}
GLuint create_program(const char *vertexfile, const char *fragmentfile) {
printf("Creating program\n");
GLuint program = glCreateProgram();
GLuint shader;
printf("Loading program\n");
if (vertexfile) {
shader = create_shader(vertexfile, GL_VERTEX_SHADER);
if (!shader)
return 0;
glAttachShader(program, shader);
}
if (fragmentfile) {
shader = create_shader(fragmentfile, GL_FRAGMENT_SHADER);
if (!shader)
return 0;
glAttachShader(program, shader);
}
glLinkProgram(program);
GLint link_ok = GL_FALSE;
glGetProgramiv(program, GL_LINK_STATUS, &link_ok);
if (!link_ok) {
fprintf(stderr, "glLinkProgram:");
//print_log(program);
glDeleteProgram(program);
return 0;
}
return program;
}
GLint get_attrib(GLuint program, const char *name) {
GLint attribute = glGetAttribLocation(program, name);
if (attribute == -1)
fprintf(stderr, "Could not bind attribute %s\n", name);
return attribute;
}
GLint get_uniform(GLuint program, const char *name) {
GLint uniform = glGetUniformLocation(program, name);
if (uniform == -1)
fprintf(stderr, "Could not bind uniform %s\n", name);
return uniform;
}
bool bLoadPngImage(char *name, int &outWidth, int &outHeight, bool &outHasAlpha, GLubyte **outData) {
png_structp png_ptr;
png_infop info_ptr;
unsigned int sig_read = 0;
int color_type, interlace_type;
FILE *fp;
if ((fp = fopen(name, "rb")) == NULL)
return false;
/* Create and initialize the png_struct
* with the desired error handler
* functions. If you want to use the
* default stderr and longjump method,
* you can supply NULL for the last
* three parameters. We also supply the
* the compiler header file version, so
* that we know if the application
* was compiled with a compatible version
* of the library. REQUIRED
*/
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
NULL, NULL, NULL);
if (png_ptr == NULL) {
fclose(fp);
return false;
}
/* Allocate/initialize the memory
* for image information. REQUIRED. */
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
fclose(fp);
png_destroy_read_struct(&png_ptr, NULL, NULL);
return false;
}
/* Set error handling if you are
* using the setjmp/longjmp method
* (this is the normal method of
* doing things with libpng).
* REQUIRED unless you set up
* your own error handlers in
* the png_create_read_struct()
* earlier.
*/
if (setjmp(png_jmpbuf(png_ptr))) {
/* Free all of the memory associated
* with the png_ptr and info_ptr */
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(fp);
/* If we get here, we had a
* problem reading the file */
return false;
}
/* Set up the output control if
* you are using standard C streams */
png_init_io(png_ptr, fp);
/* If we have already
* read some of the signature */
png_set_sig_bytes(png_ptr, sig_read);
/*
* If you have enough memory to read
* in the entire image at once, and
* you need to specify only
* transforms that can be controlled
* with one of the PNG_TRANSFORM_*
* bits (this presently excludes
* dithering, filling, setting
* background, and doing gamma
* adjustment), then you can read the
* entire image (including pixels)
* into the info structure with this
* call
*
* PNG_TRANSFORM_STRIP_16 |
* PNG_TRANSFORM_PACKING forces 8 bit
* PNG_TRANSFORM_EXPAND forces to
* expand a palette into RGB
*/
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, NULL);
png_uint_32 width, height;
int bit_depth;
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
&interlace_type, NULL, NULL);
outWidth = width;
outHeight = height;
unsigned int row_bytes = png_get_rowbytes(png_ptr, info_ptr);
*outData = (unsigned char*)malloc(row_bytes * outHeight);
png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr);
for (int i = 0; i < outHeight; i++) {
// note that png is ordered top to
// bottom, but OpenGL expect it bottom to top
// so the order or swapped
memcpy(*outData + (row_bytes * (outHeight - 1 - i)), row_pointers[i], row_bytes);
}
/* Clean up after the read,
* and free any memory allocated */
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
/* Close the file */
fclose(fp);
/* That's it */
return true;
}
void vLoadPngToTexture(std::string sFilename, int iTexture) {
GLubyte *glTextureImage;
int iWidth, iHeight;
bool bHasAlpha;
//char filename[] = "/home/root/res/drawable/disclaimerantamina.png";
//bool success = bLoadPngImage((char *)sFilename.c_str(), iWidth, iHeight, bHasAlpha, &glTextureImage);
//if (!success) {
if (!bLoadPngImage((char *)sFilename.c_str(), iWidth, iHeight, bHasAlpha, &glTextureImage)) {
std::cout << "Unable to load png file" << std::endl;
exit(0);
}
std::cout << "Image loaded " << sFilename << " " << iWidth << " " << iHeight << " alpha " << bHasAlpha << std::endl;
glBindTexture(GL_TEXTURE_2D, glTextures[iTexture]);
/* Generate The Texture */
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, iWidth,
iHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
glTextureImage);
/* Linear Filtering */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
std::cout << "Texture loaded " << iTexture << " - " << sFilename << std::endl;
}
int init_resources() {
/* Initialize the FreeType2 library */
if (FT_Init_FreeType(&ft)) {
fprintf(stderr, "Could not init freetype library\n");
return 0;
}
/* Load a font */
if (FT_New_Face(ft, fontfilename, 0, &face)) {
fprintf(stderr, "Could not open font %s\n", fontfilename);
return 0;
}
printf("Load Font Correctly\n");
program = create_program("text.v.glsl", "text.f.glsl");
if (program == 0)
return 0;
printf("Create program Correctly\n");
attribute_coord = get_attrib(program, "coord");
uniform_tex = get_uniform(program, "tex");
uniform_color = get_uniform(program, "color");
if (attribute_coord == -1 || uniform_tex == -1 || uniform_color == -1)
return 0;
printf("Create attributes Correctly\n");
programBack = create_program("back.v.glsl", "back.f.glsl");
printf("Create program Background Correctly\n");
coordBack = get_attrib(programBack, "g_vPosition");
//colorBack = get_attrib(programBack, "g_vColor");
texBack = get_attrib(programBack, "g_vTexCoord");
if (coordBack == -1 || colorBack == -1 || texBack == -1)
return 0;
// Create the vertex buffer object
glGenBuffers(1, &vbo);
///* Create texture atlasses for several font sizes */
a48 = new atlas(face, 48);
a24 = new atlas(face, 24);
a12 = new atlas(face, 12);
return 1;
}
/**
* Render text using the currently loaded font and currently set font size.
* Rendering starts at coordinates (x, y), z is always 0.
* The pixel coordinates that the FreeType2 library uses are scaled by (sx, sy).
*/
void render_text(const char *text, atlas * a, float x, float y, float sx, float sy) {
const uint8_t *p;
/* Use the texture containing the atlas */
glBindTexture(GL_TEXTURE_2D, a->tex);
glUniform1i(uniform_tex, 0);
/* Set up the VBO for our vertex data */
glEnableVertexAttribArray(attribute_coord);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(attribute_coord, 4, GL_FLOAT, GL_FALSE, 0, 0);
point coords[6 * strlen(text)];
int c = 0;
/* Loop through all characters */
for (p = (const uint8_t *)text; *p; p++) {
/* Calculate the vertex and texture coordinates */
float x2 = x + a->c[*p].bl * sx;
float y2 = -y - a->c[*p].bt * sy;
float w = a->c[*p].bw * sx;
float h = a->c[*p].bh * sy;
/* Advance the cursor to the start of the next character */
x += a->c[*p].ax * sx;
y += a->c[*p].ay * sy;
/* Skip glyphs that have no pixels */
if (!w || !h)
continue;
coords[c++] = (point) {
x2, -y2, a->c[*p].tx, a->c[*p].ty
};
coords[c++] = (point) {
x2 + w, -y2, a->c[*p].tx + a->c[*p].bw / a->w, a->c[*p].ty
};
coords[c++] = (point) {
x2, -y2 - h, a->c[*p].tx, a->c[*p].ty + a->c[*p].bh / a->h
};
coords[c++] = (point) {
x2 + w, -y2, a->c[*p].tx + a->c[*p].bw / a->w, a->c[*p].ty
};
coords[c++] = (point) {
x2, -y2 - h, a->c[*p].tx, a->c[*p].ty + a->c[*p].bh / a->h
};
coords[c++] = (point) {
x2 + w, -y2 - h, a->c[*p].tx + a->c[*p].bw / a->w, a->c[*p].ty + a->c[*p].bh / a->h
};
}
/* Draw all the character on the screen in one go */
glBufferData(GL_ARRAY_BUFFER, sizeof coords, coords, GL_DYNAMIC_DRAW);
glDrawArrays(GL_TRIANGLES, 0, c);
glDisableVertexAttribArray(attribute_coord);
}
void display() {
//float sx = 2.0 / glutGet(GLUT_WINDOW_WIDTH);
//float sy = 2.0 / glutGet(GLUT_WINDOW_HEIGHT);
float sx = 2.0 / 800;
float sy = 2.0 / 480;
glViewport(0, 0, 800, 480);
glUseProgram(programBack);
/* White background */
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* Enable blending, necessary for our alpha texture */
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glVertexAttribPointer(coordBack, 3, GL_FLOAT, 0, 0, fBackgroundPosition);
glEnableVertexAttribArray(coordBack);
//glVertexAttribPointer(colorBack, 4, GL_FLOAT, 0, 0, VertexColors);
//glEnableVertexAttribArray(colorBack);
glVertexAttribPointer(texBack, 2, GL_FLOAT, 0, 0, VertexTexCoords);
glEnableVertexAttribArray(texBack);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, glTextures[0]);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// Cleanup
glDisableVertexAttribArray(coordBack);
glDisableVertexAttribArray(colorBack);
glDisableVertexAttribArray(texBack);
glUseProgram(program);
GLfloat black[4] = { 0, 0, 0, 1 };
GLfloat red[4] = { 1, 0, 0, 1 };
GLfloat transparent_green[4] = { 0, 1, 0, 0.5 };
/* Set color to black */
//glUniform4fv(uniform_color, 1, black);
/* Effects of alignment */
render_text("The ñ Ñ Quick Brown Fox Jumps Over The Lazy Dog", a48, -1 + 8 * sx, 1 - 50 * sy, sx, sy);
//render_text("The , . - + { } & % Misaligned Fox Jumps Over The Lazy Dog", a48, -1 + 8.5 * sx, 1 - 100.5 * sy, sx, sy);
///* Scaling the texture versus changing the font size */
//render_text("The ç ó Small Texture Scaled Fox Jumps Over The Lazy Dog", a48, -1 + 8 * sx, 1 - 175 * sy, sx * 0.5, sy * 0.5);
//render_text("The Small Font Sized Fox Jumps Over The Lazy Dog", a24, -1 + 8 * sx, 1 - 200 * sy, sx, sy);
//render_text("The Tiny Texture Scaled Fox Jumps Over The Lazy Dog", a48, -1 + 8 * sx, 1 - 235 * sy, sx * 0.25, sy * 0.25);
//render_text("The Tiny Font Sized Fox Jumps Over The Lazy Dog", a12, -1 + 8 * sx, 1 - 250 * sy, sx, sy);
///* Colors and transparency */
//render_text("The Solid Black Fox Jumps Over The Lazy Dog", a48, -1 + 8 * sx, 1 - 430 * sy, sx, sy);
//glUniform4fv(uniform_color, 1, red);
//render_text("The Solid Red Fox Jumps Over The Lazy Dog", a48, -1 + 8 * sx, 1 - 330 * sy, sx, sy);
//render_text("The Solid Red Fox Jumps Over The Lazy Dog", a48, -1 + 28 * sx, 1 - 450 * sy, sx, sy);
//glUniform4fv(uniform_color, 1, transparent_green);
//render_text("The Transparent Green Fox Jumps Over The Lazy Dog", a48, -1 + 8 * sx, 1 - 380 * sy, sx, sy);
//render_text("The Transparent Green Fox Jumps Over The Lazy Dog", a48, -1 + 18 * sx, 1 - 440 * sy, sx, sy);
eglSwapBuffers(egldisplay, eglsurface);
}
void free_resources() {
glDeleteProgram(program);
}
int init(void)
{
Display *x_display;
Window win;
x_display = XOpenDisplay(":0"); // open the standard display (the primary screen)
if (x_display == NULL) {
std::cout << "cannot connect to X server" << std::endl;
return 1;
}
Window root = DefaultRootWindow(x_display); // get the root window (usually the whole screen)
XSetWindowAttributes swa;
swa.event_mask = ExposureMask | PointerMotionMask | KeyPressMask;
win = XCreateWindow( // create a window with the provided parameters
x_display, root,
0, 0, 800, 480, 0,
CopyFromParent, InputOutput,
CopyFromParent, CWEventMask,
&swa);
XMapWindow(x_display, win); // make the window visible on the screen
XStoreName(x_display, win, "GL test"); // give the window a name
static const EGLint s_configAttribs[] =
{
EGL_RENDERABLE_TYPE, 4,
EGL_RED_SIZE, 5,
EGL_GREEN_SIZE, 6,
EGL_BLUE_SIZE, 5,
EGL_ALPHA_SIZE, 0,
EGL_SAMPLES, 0,
EGL_SAMPLE_BUFFERS, 1,
EGL_SAMPLES, 4, // This is for 4x MSAA.
EGL_NONE
};
EGLint numconfigs;
egldisplay = eglGetDisplay((EGLNativeDisplayType)x_display);
eglInitialize(egldisplay, NULL, NULL);
assert(eglGetError() == EGL_SUCCESS);
eglBindAPI(EGL_OPENGL_ES_API);
eglChooseConfig(egldisplay, s_configAttribs, &eglconfig, 1, &numconfigs);
assert(eglGetError() == EGL_SUCCESS);
assert(numconfigs == 1);
eglsurface = eglCreateWindowSurface(egldisplay, eglconfig, win, NULL);
assert(eglGetError() == EGL_SUCCESS);
EGLint ContextAttribList[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
eglcontext = eglCreateContext(egldisplay, eglconfig, EGL_NO_CONTEXT, ContextAttribList);
assert(eglGetError() == EGL_SUCCESS);
eglMakeCurrent(egldisplay, eglsurface, eglsurface, eglcontext);
assert(eglGetError() == EGL_SUCCESS);
printf("VENDOR = %s\n", glGetString(GL_VENDOR));
printf("RENDERER = %s\n", glGetString(GL_RENDERER));
printf("VERSION = %s\n", glGetString(GL_VERSION));
}
int main(int argc, char *argv[]) {
if (argc > 1)
fontfilename = argv[1];
else
fontfilename = "FreeSans.ttf";
init();
init_resources();
std::string sBackground = "back2.png";
vLoadPngToTexture(sBackground, 0);
//// this is needed for time measuring --> frames per second
struct timezone tz;
timeval t1, t2;
gettimeofday(&t1, &tz);
int num_frames = 0;
while (1) {
display();
if (++num_frames % 30 == 0) {
//if (++num_frames % 100 == 0) {
gettimeofday(&t2, &tz);
float dt = t2.tv_sec - t1.tv_sec + (t2.tv_usec - t1.tv_usec) * 1e-6;
std::cout << "fps: " << num_frames / dt << std::endl;
num_frames = 0;
t1 = t2;
}
usleep(32000);
}
return 0;
}
If I comment the line render_text("The ñ Ñ Quick Brown Fox Jumps Over The Lazy Dog", a48, -1 + 8 * sx, 1 - 50 * sy, sx, sy);, I can see the textured square perfectly.
glUniform operates on the program object that was made part of current state by calling glUseProgram.
Because of that the call of glUniform1i in the function atlas is useless, because at this point there is no current program at all. You can delete this call, because you set the uniform later.
The texture glTextures[iTexture], which you bind in the function vLoadPngToTexture is not generated.
Change your code somehow like this:
glGenTextures(1, glTextures+iTexture);
glBindTexture(GL_TEXTURE_2D, glTextures[iTexture]);
You do not use an array buffer when you draw the background, but you use an array buffer when you draw the text. In the function render_text you bind glBindBuffer(GL_ARRAY_BUFFER, vbo); but you never release it. This causes that the array buffer vbois still bound when the background should be drawn in the next cycle. Becauseof that, glVertexAttribPointer, in the function display, does not do what you expect it to do.
You can fix this by adding
glBindBuffer(GL_ARRAY_BUFFER, 0)
to the end of the function render_text.
I want to rotate my triangle in OpenGL, and running program on Raspberry Pi.
I can draw triangle and move it.
But I have no idea to rotate it..
Nothing rotates.
#include <cstdio>
#include <ctime>
#include <cmath>
#include <string>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
#include <GLES/gl.h>
#include <bcm_host.h>
EGLDisplay Disp;
EGLSurface Surface;
EGLContext Context;
int ScrWidth, ScrHeight;
float MVPMatrix[16];
float ProjectionMatrix[16];
float ViewMatrix[16];
using namespace std;
class Shader
{
private:
string VertexShaderFile;
string FragmentShaderFile;
GLuint Load(GLenum type, string FileName)
{
(Compile shader)
}
GLuint Program;
bool Linked;
public:
Shader(string FileNameV, string FileNameF)
{
Linked = false;
VertexShaderFile = FileNameV;
FragmentShaderFile = FileNameF;
}
bool Load()
{
(Link vertex/fragment shader)
}
void Use()
{
glUseProgram(Program);
}
int GetAttrLoc(const char *Name)
{
glGetAttribLocation(Program, Name);
}
int GetUniformLoc(const char *Name)
{
return glGetUniformLocation(Program, Name);
}
~Shader()
{
if(Linked)
{
Linked = false;
glDeleteProgram(Program);
}
}
};
class Triangle
{
private:
const int COORDS_PER_VERTEX = 3;
const int vertexCount = 9 / COORDS_PER_VERTEX; //9: Length of triangleCoords
const int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
static float TriangleCoords [];
float Color[4];
float XOff;
float YOff;
float ZOff;
Shader *S;
public:
Triangle()
{
XOff = YOff = ZOff = 0;
S = new Shader("Shaders/test.vsh", "Shaders/test.fsh");
if (!S->Load())
{
delete S;
S = NULL;
}
}
void SetColor(int R, int G, int B, int A)
{
Color[0] = R / 255.0;
Color[1] = G / 255.0;
Color[2] = B / 255.0;
Color[3] = A / 255.0;
}
void SetXYZ(int X, int Y, int Z)
{
(Sets position)
}
bool Draw()
{
float TriangleCoords[] = { // in counterclockwise order:
-0.0 + XOff, 0.622008459 + YOff, 0.0 + ZOff, // top
-0.5 + XOff, -0.311004243 + YOff, 0.0 + ZOff, // bottom left
0.5 + XOff, -0.311004243 + YOff, 0.0 + ZOff // bottom right
};
printf("%f\n", TriangleCoords[1]);
//glMatrixMode(GL_PROJECTION);
if (S == NULL)
return false;
S->Use();
// Load the vertex data
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, TriangleCoords);
// get handle to shape's transformation matrix
// Pass the projection and view transformation to the shader
//UniformMatrix4fv(S->GetUniformLoc("uMVPMatrix"), 1, false, MVPMatrix);
glUniform4fv(S->GetUniformLoc("vColor"), 1, Color);
glEnableVertexAttribArray(0);
//glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
float X = LocalTime->tm_hour / 23.0;
float Y = LocalTime->tm_min / 59.0;
float Z = LocalTime->tm_sec / 59.0;
glTranslatef(0, 0, 1);
glRotatef(60, 1.f, 0.f, 0.f);
glRotatef(30, 0.f, 1.f, 0.f);
glRotatef(30, 0.f, 0.f, 1.f);
glDrawArrays(GL_TRIANGLES, 0, 3);
//glPopMatrix();
return true;
}
};
bool InitDisplay()
{
bcm_host_init();
Disp = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if(eglInitialize(Disp, NULL, NULL) != EGL_TRUE)
{
printf("Display initialize error.\n");
return false;
}
printf("Display initialized.\n");
static const EGLint AttrList[] =
{
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_NONE
};
EGLConfig Config;
int ConfigCount;
if(eglChooseConfig(Disp, AttrList, &Config, 1, &ConfigCount) != EGL_TRUE)
{
printf("Display choose config error.\n");
return false;
}
printf("Display config chosen. %d configs.\n", ConfigCount);
//if(eglBindAPI(EGL_OPENGL_ES_API) != EGL_TRUE)
//{
// printf("Bind API error.\n");
// return false;
//}
//printf("API bound.\n");
static const EGLint ContextAttr[] =
{
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
if((Context = eglCreateContext(Disp, Config, EGL_NO_CONTEXT, ContextAttr)) == EGL_NO_CONTEXT)
{
printf("Create context error.\n");
return false;
}
printf("Context created.\n");
if(graphics_get_display_size(0 /* LCD */, &ScrWidth, &ScrHeight) < 0)
{
printf("Get screen size error.\n");
return false;
}
printf("Got screen size. %dx%d\n", ScrWidth, ScrHeight);
DISPMANX_DISPLAY_HANDLE_T DispmanDisp;
DispmanDisp = vc_dispmanx_display_open(0 /* LCD */);
printf("Dispmanx - Display opened.\n");
DISPMANX_UPDATE_HANDLE_T DispmanUpdate;
DispmanUpdate = vc_dispmanx_update_start(0);
printf("Dispmanx - Update started.\n");
DISPMANX_ELEMENT_HANDLE_T DispmanElement;
VC_RECT_T DestRect;
VC_RECT_T SrcRect;
DestRect.x = 0;
DestRect.y = 0;
DestRect.width = ScrWidth;
DestRect.height = ScrHeight;
SrcRect.x = 0;
SrcRect.y = 0;
SrcRect.width = ScrWidth << 16;
SrcRect.height = ScrHeight << 16;
DispmanElement= vc_dispmanx_element_add(
DispmanUpdate,
DispmanDisp,
0/*layer*/,
&DestRect,
0/*src*/,
&SrcRect,
DISPMANX_PROTECTION_NONE,
0 /*alpha*/,
0/*clamp*/,
0/*transform*/
);
printf("Dispmanx - Element added.\n");
static EGL_DISPMANX_WINDOW_T NativeWindow;
NativeWindow.element = DispmanElement;
NativeWindow.width = ScrWidth;
NativeWindow.height = ScrHeight;
vc_dispmanx_update_submit_sync(DispmanUpdate);
printf("Dispmanx - Sync submited.\n");
if((Surface = eglCreateWindowSurface(Disp, Config, &NativeWindow, NULL)) == EGL_NO_SURFACE)
{
printf("Create surface error.\n");
return false;
}
printf("Surface created\n");
if(eglMakeCurrent(Disp, Surface, Surface, Context) != EGL_TRUE)
{
printf("Make onnection between context and surface error.\n");
return false;
}
printf("Connection made between context and surface.\n");
glEnable(GL_CULL_FACE);
glMatrixMode(GL_MODELVIEW);
printf("Graphics system ready.\n");
return true;
}
void makeFrustum(float fovY, float aspectRatio, float front, float back)
{
const float DEG2RAD = 3.14159265 / 180;
float tangent = tan(fovY / 2 * DEG2RAD); // tangent of half fovY
float height = front * tangent; // half height of near plane
float width = height * aspectRatio; // half width of near plane
// params: left, right, bottom, top, near, far
glFrustumf(-width, width, -height, height, front, back);
}
void DrawLoop()
{
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glViewport(0, 0, ScrWidth, ScrHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
makeFrustum(45.0, ScrWidth / (float)ScrHeight, 1, 500);
glEnableClientState(GL_VERTEX_ARRAY);
Triangle T1;
Triangle T2;
Triangle T3;
Triangle T4;
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.f, 0.f, -50.f);
while (1)
{
time_t Time;
time(&Time);
tm *LocalTime = localtime(&Time);
printf("%d:%d:%d\n", LocalTime->tm_hour, LocalTime->tm_min, LocalTime->tm_sec);
float R = LocalTime->tm_hour / 23.0;
float G = LocalTime->tm_min / 59.0;
float B = LocalTime->tm_sec / 59.0;
T1.SetColor(255, 0, 0, 255);
T1.SetXYZ(B * ScrWidth, B * ScrHeight, 0);
//glClearColor(0, 0, 0, 1.0);
//glClear(GL_COLOR_BUFFER_BIT);
if (!T1.Draw() || !T2.Draw() || !T3.Draw() || !T4.Draw())
{
return;
}
glFlush();
eglSwapBuffers(Disp, Surface);
}
}
int main()
{
if(!InitDisplay())
{
printf("Display initialize error.\n");
return false;
}
DrawLoop();
return 0;
}
What should I do to rotate triangle?
I referenced working code, but it still doesn't rotates.
You're trying to use OpenGL ES 1.1 functions (glLoadIdentity, glMatrixMode, glTranslatef, glRotatef, etc) in an OpenGL ES 2.0 context - this won't work. You can use either OpenGL ES 1.1 OR OpenGL ES 2.0, but you can't use both at the same time from the same context.
I would suggest sticking with OpenGL ES 2.0 using shaders, and learning the OpenGL ES 2.0 way of doing things, as this is how all of the newer APIs work.
To do translation and rotation you need to encode it into an MVP matrix and pass this as a uniform to the vertex shader which you use when calculating gl_Position. Some examples here:
https://open.gl/transformations
I have a scene that I load from a obj file using the assimp library. I followed a tutorial in order to do it. It works but textures have different colors compared to the original and they all seem to be flipped top-bottom. The images are all tga (I would also like to get rid of all the aliasing)
here is the result
and the curtain should be red
I load the textures this way using freeImage
bool Texture::Load(){
FIBITMAP* bitmap = FreeImage_Load(
FreeImage_GetFileType(m_fileName.c_str(), 0),
m_fileName.c_str());
FIBITMAP *pImage = FreeImage_ConvertTo32Bits(bitmap);
int nWidth = FreeImage_GetWidth(pImage);
int nHeight = FreeImage_GetHeight(pImage);
glGenTextures(1, &m_textureObj);
glBindTexture(m_textureTarget, m_textureObj);
glTexImage2D(m_textureTarget, 0, GL_RGBA, nWidth, nHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, (void*)FreeImage_GetBits(pImage));
glTexParameterf(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
FreeImage_Unload(pImage);
return true;
}
while the scene is loaded using assimp and processed this way
void Mesh::InitMesh(const aiMesh* paiMesh,
vector<Vector3f>& Positions,
vector<Vector3f>& Normals,
vector<Vector2f>& TexCoords,
vector<unsigned int>& Indices){
const aiVector3D Zero3D(0.0f, 0.0f, 0.0f);
aiMatrix4x4 Scale(0.3f, 0.0f, 0.0f, 0.0f,
0.0f, 0.3f, 0.0f, 0.0f,
0.0f, 0.0f, 0.3f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
// Populate the vertex attribute vectors
for (unsigned int i = 0; i < paiMesh->mNumVertices; i++) {
if (paiMesh->mVertices[i].x < lowX) lowX = paiMesh->mVertices[i].x;
if (paiMesh->mVertices[i].x > highX) highX = paiMesh->mVertices[i].x;
if (paiMesh->mVertices[i].y < lowY) lowY = paiMesh->mVertices[i].y;
if (paiMesh->mVertices[i].y > highY) highY = paiMesh->mVertices[i].y;
if (paiMesh->mVertices[i].z < lowZ) lowZ = paiMesh->mVertices[i].z;
if (paiMesh->mVertices[i].z > highZ) highZ = paiMesh->mVertices[i].z;
//paiMesh->mVertices[i] = Scale*paiMesh->mVertices[i];
const aiVector3D* pPos = &(paiMesh->mVertices[i]);
const aiVector3D* pNormal = &(paiMesh->mNormals[i]);
const aiVector3D* pTexCoord = paiMesh->HasTextureCoords(0) ? &(paiMesh->mTextureCoords[0][i]) : &Zero3D;
Positions.push_back(Vector3f(pPos->x, pPos->y, pPos->z));
Normals.push_back(Vector3f(pNormal->x, pNormal->y, pNormal->z));
TexCoords.push_back(Vector2f(pTexCoord->x, pTexCoord->y));
}
bbox[0] = Vector3f(abs(lowX), abs(lowY), abs(lowZ));
bbox[1] = Vector3f(abs(highX), abs(highY), abs(highZ));
// Populate the index buffer
for (unsigned int i = 0; i < paiMesh->mNumFaces; i++) {
const aiFace& Face = paiMesh->mFaces[i];
assert(Face.mNumIndices == 3);
Indices.push_back(Face.mIndices[0]);
Indices.push_back(Face.mIndices[1]);
Indices.push_back(Face.mIndices[2]);
}
}
and this is how I initialise textures
bool Mesh::InitMaterials(const aiScene* pScene, const string& Filename){
// Extract the directory part from the file name
string::size_type SlashIndex = Filename.find_last_of("/");
string Dir;
if (SlashIndex == string::npos) {
Dir = ".";
}
else if (SlashIndex == 0) {
Dir = "/";
}
else {
Dir = Filename.substr(0, SlashIndex);
}
bool Ret = true;
// Initialize the materials
for (unsigned int i = 0; i < pScene->mNumMaterials; i++) {
const aiMaterial* pMaterial = pScene->mMaterials[i];
m_Textures[i] = NULL;
if (true || pMaterial->GetTextureCount(aiTextureType_DIFFUSE) > 0) {
aiString Path;
if (pMaterial->GetTexture(aiTextureType_DIFFUSE, 0, &Path, NULL, NULL, NULL, NULL, NULL) == AI_SUCCESS) {
string FullPath = Dir + "/" + Path.data;
m_Textures[i] = new Texture(GL_TEXTURE_2D, FullPath.c_str());
if (!m_Textures[i]->Load()) {
printf("Error loading texture '%s'\n", FullPath.c_str());
delete m_Textures[i];
m_Textures[i] = NULL;
Ret = false;
}
else {
printf("%d - loaded texture '%s'\n", i, FullPath.c_str());
}
}
}
}
return Ret;
}
In the end I render everything in this way
void Mesh::Render()
{
glBindVertexArray(m_VAO);
glActiveTexture(GL_TEXTURE0);
GLenum oldObj = 0;
if (m_Textures[m_Entries[0].MaterialIndex]){
m_Textures[m_Entries[0].MaterialIndex]->Bind(GL_TEXTURE0);
oldObj = m_Textures[m_Entries[0].MaterialIndex]->m_textureObj;
}
vector<GLsizei> numIdx;
vector<GLint> baseVc;
vector<void*> idx;
unsigned int drawCount = 0;
for (unsigned int i = 0; i < m_Entries.size(); i++) {
const unsigned int MaterialIndex = m_Entries[i].MaterialIndex;
assert(MaterialIndex < m_Textures.size());
drawCount++;
numIdx.push_back(m_Entries[i].NumIndices);
baseVc.push_back(m_Entries[i].BaseVertex);
idx.push_back((void*)(sizeof(unsigned int) * m_Entries[i].BaseIndex));
if (i == m_Entries.size() - 1){
glDrawElementsBaseVertex(GL_TRIANGLES,
m_Entries[i].NumIndices,
GL_UNSIGNED_INT,
(void*)(sizeof(unsigned int) * m_Entries[i].BaseIndex),
m_Entries[i].BaseVertex);
}else
if (m_Textures[m_Entries[i + 1].MaterialIndex] && m_Textures[m_Entries[i+1].MaterialIndex]->m_textureObj != oldObj) {
glMultiDrawElementsBaseVertex(GL_TRIANGLES,
&numIdx[0],
GL_UNSIGNED_INT,
&idx[0],
drawCount,
&baseVc[0]);
numIdx.clear();
baseVc.clear();
idx.clear();
m_Textures[m_Entries[i + 1].MaterialIndex]->Bind(GL_TEXTURE0);
oldObj = m_Textures[m_Entries[i + 1].MaterialIndex]->m_textureObj;
drawCount = 0;
}else if (!m_Textures[m_Entries[i].MaterialIndex]){
glMultiDrawElementsBaseVertex(GL_TRIANGLES,
&numIdx[0],
GL_UNSIGNED_INT,
&idx[0],
drawCount,
&baseVc[0]);
}
}
// Make sure the VAO is not changed from the outside
glBindVertexArray(0);
}
Sorry for the large amount of code but since I don't know where is the error I posted the entire thing. It's all commented
I had that kind of issue while trying to reduce the size of the textures, i was puting RGBA in the wrong position. You do use Bitmap textures, which means they dont store an alpha channel, try to put them in GL_RGB mode (you are sending them in GL_RGBA).
So it turns out that I had to remove flippedUV and i had to use RGBA as internal format and BGRA for the other format
I am making changes in the code from this article, to acomplish the same result without need the methods specific for Windows and be able to run the programa in other platforms. I can compile and run the program without errors (with the Main and Render functions listed below), but the result is a blank screen. Someone can find some reason in the code for this issue happen?
Main:
int main(int argc, char **argv)
{
// temp var's
int width = 800;
int height = 600;
int bits = 32;
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(width,height);
glutInit(&argc, argv);
glutCreateWindow("Terrain");
glutDisplayFunc(Render);
glutReshapeFunc(AlteraTamanhoJanela);
glutKeyboardFunc(GerenciaTeclado);
glutMouseFunc(GerenciaMouse);
Initialize();
glutMainLoop();
}
Render:
void Render()
{
radians = float(PI*(angle-90.0f)/180.0f);
// calculate the camera's position
cameraX = lookX + sin(radians)*mouseY; // multiplying by mouseY makes the
cameraZ = lookZ + cos(radians)*mouseY; // camera get closer/farther away with mouseY
cameraY = lookY + mouseY / 2.0f;
// calculate the camera look-at coordinates as the center of the terrain map
lookX = (MAP_X*MAP_SCALE)/2.0f;
lookY = 150.0f;
lookZ = -(MAP_Z*MAP_SCALE)/2.0f;
// clear screen and depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
// set the camera position
gluLookAt(cameraX, cameraY, cameraZ, lookX, lookY, lookZ, 0.0, 1.0, 0.0);
// set the current texture to the land texture
glBindTexture(GL_TEXTURE_2D, land);
// we are going to loop through all of our terrain's data points,
// but we only want to draw one triangle strip for each set along the x-axis.
for (int z = 0; z < MAP_Z-1; z++)
{
//printf("%s %d\n","Loop FOR para Z = ",z);
glBegin(GL_TRIANGLE_STRIP);
for (int x = 0; x < MAP_X-1; x++)
{
//printf("%s %d\n","Loop FOR para X = ",x);
// for each vertex, we calculate the grayscale shade color,
// we set the texture coordinate, and we draw the vertex.
/*
the vertices are drawn in this order:
0 ---> 1
/
/
|/
2 ---> 3
*/
// draw vertex 0
//printf("%s\n","Primeiro");
glColor3f(terrain[x][z][1]/255.0f, terrain[x][z][1]/255.0f, terrain[x][z][1]/255.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(terrain[x][z][0], terrain[x][z][1], terrain[x][z][2]);
// draw vertex 1
//printf("%s\n","Segundo");
glTexCoord2f(1.0f, 0.0f);
glColor3f(terrain[x+1][z][1]/255.0f, terrain[x+1][z][1]/255.0f, terrain[x+1][z][1]/255.0f);
glVertex3f(terrain[x+1][z][0], terrain[x+1][z][1], terrain[x+1][z][2]);
// draw vertex 2
//printf("%s\n","Terceiro");
glTexCoord2f(0.0f, 1.0f);
glColor3f(terrain[x][z+1][1]/255.0f, terrain[x][z+1][1]/255.0f, terrain[x][z+1][1]/255.0f);
glVertex3f(terrain[x][z+1][0], terrain[x][z+1][1], terrain[x][z+1][2]);
// draw vertex 3
//printf("%s\n","Quarto");
glColor3f(terrain[x+1][z+1][1]/255.0f, terrain[x+1][z+1][1]/255.0f, terrain[x+1][z+1][1]/255.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(terrain[x+1][z+1][0], terrain[x+1][z+1][1], terrain[x+1][z+1][2]);
}
glEnd();
}
// enable blending
glEnable(GL_BLEND);
// enable read-only depth buffer
glDepthMask(GL_FALSE);
// set the blend function to what we use for transparency
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
// set back to normal depth buffer mode (writable)
glDepthMask(GL_TRUE);
// disable blending
glDisable(GL_BLEND);
glFlush();
//SwapBuffers(g_HDC); // bring backbuffer to foreground
}
Update: As requested, here is the other functions from my code.
void InitializeTerrain()
{
// loop through all of the heightfield points, calculating
// the coordinates for each point
for (int z = 0; z < MAP_Z; z++)
{
for (int x = 0; x < MAP_X; x++)
{
terrain[x][z][0] = float(x)*MAP_SCALE;
terrain[x][z][1] = (float)imageData[(z*MAP_Z+x)*3];
terrain[x][z][2] = -float(z)*MAP_SCALE;
}
}
}
void CleanUp()
{
free(imageData);
free(landTexture);
}
// Initialize
// desc: initializes OpenGL
void Initialize()
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // clear to black
glShadeModel(GL_SMOOTH); // use smooth shading
glEnable(GL_DEPTH_TEST); // hidden surface removal
glEnable(GL_CULL_FACE); // do not calculate inside of poly's
glFrontFace(GL_CCW); // counter clock-wise polygons are out
glEnable(GL_TEXTURE_2D); // enable 2D texturing
imageData = LoadBitmapFile("terrain2.bmp", &bitmapInfoHeader);
// initialize the terrain data and load the textures
InitializeTerrain();
LoadTextures();
}
// Função callback chamada quando o tamanho da janela é alterado
void AlteraTamanhoJanela(GLsizei w, GLsizei h)
{
int width, height;
height = h; // retrieve width and height
width = w;
if (height==0) // don't want a divide by zero
{
height=1;
}
glViewport(0, 0, width, height); // reset the viewport to new dimensions
glMatrixMode(GL_PROJECTION); // set projection matrix current matrix
glLoadIdentity(); // reset projection matrix
// calculate aspect ratio of window
gluPerspective(54.0f,(GLfloat)width/(GLfloat)height,1.0f,1000.0f);
glMatrixMode(GL_MODELVIEW); // set modelview matrix
glLoadIdentity(); // reset modelview matrix
}
// Função callback chamada para gerenciar eventos do mouse
void GerenciaMouse(int button, int state, int x, int y)
{
int oldMouseX, oldMouseY;
// save old mouse coordinates
oldMouseX = mouseX;
oldMouseY = mouseY;
// get mouse coordinates from Windows
mouseX = x;
mouseY = y;
// these lines limit the camera's range
if (mouseY < 200)
mouseY = 200;
if (mouseY > 450)
mouseY = 450;
if ((mouseX - oldMouseX) > 0) // mouse moved to the right
angle += 3.0f;
else if ((mouseX - oldMouseX) < 0) // mouse moved to the left
angle -= 3.0f;
glutPostRedisplay();
}
/* Key press processing */
void GerenciaTeclado(unsigned char c, int x, int y)
{
if(c == 27) exit(0);
}
And, finally, the content from file vkgllib.h, included by source code file above:
#include <iostream>
#include <fstream>
#include <math.h>
#include <stdlib.h>
using namespace std;
#define WINDOW_WIDTH 640 // Window Width Default
#define WINDOW_HEIGHT 480 // Window Height Default
// definition of PI
#define PI 3.14159265
// Used to defien the title of the window
#define WINDOW_TITLE "OpenGL Terrain Generation"
// A simple structure to define a point whose coordinates are integers
/*typedef struct { GLint x, y; } GLintPoint;
// This structure is used to store the vertices of a polyline
typedef struct { int num; GLintPoint pt[100]; } GLintPointArray;
// Data for an Icosahedron
#define ICO_X 0.525731112119133606
#define ICO_Z 0.850650808352039932*/
/*static GLfloat vdataICO[12][3] =
{
{ -ICO_X, 0.0, ICO_Z }, { ICO_X, 0.0, ICO_Z }, { -ICO_X, 0.0, -ICO_Z }, { ICO_X, 0.0, -ICO_Z },
{ 0.0, ICO_Z, ICO_X }, { 0.0, ICO_Z, -ICO_X }, { 0.0, -ICO_Z, ICO_X }, { 0.0, -ICO_Z, -ICO_X },
{ ICO_Z, ICO_X, 0.0 }, { -ICO_Z, ICO_X, 0.0 }, { ICO_Z, -ICO_X, 0.0 }, { -ICO_Z, -ICO_X, 0.0 }
};
static GLuint tindicesICO[20][3] =
{
{ 1, 4, 0 }, { 4, 9, 0 }, { 4, 5, 9 }, { 8, 5, 4 }, { 1, 8, 4 },
{ 1, 10, 8 }, { 10, 3, 8 }, { 8, 3, 5 }, { 3, 2, 5 }, { 3, 7, 2 },
{ 3, 10, 7 }, { 10, 6, 7 }, { 6, 11, 7 }, { 6, 0, 11 }, {6, 1, 0 },
{ 10, 1, 6 }, { 11, 0, 9 }, { 2, 11, 9 }, { 5, 2, 9 }, { 11, 2, 7 }
};*/
// Data for Tetrahedron
static GLfloat P1T[3] = { -2, 3, 0 };
static GLfloat P2T[3] = { -3, 0, 0 };
static GLfloat P3T[3] = { -1, 0, 3 };
static GLfloat P4T[3] = { -4, 0, 0 };
// Calculating the Normalized Cross Product of Two Vectors
void normalize( float v[3] )
{
GLfloat d = sqrt( float(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]) );
if( d==0.0 )
{
cerr<<"zero length vector"<<endl;
return;
}
v[0] /= d;
v[1] /= d;
v[2] /= d;
}
void normcrossprod( float v1[3], float v2[3], float out[3] )
{
out[0] = v1[1]*v2[2] - v1[2]*v2[1];
out[1] = v1[2]*v2[0] - v1[0]*v2[2];
out[2] = v1[0]*v2[1] - v1[1]*v2[0];
normalize( out );
}
////// Defines
#define BITMAP_ID 0x4D42 // the universal bitmap ID
#define MAP_X 32 // size of map along x-axis
#define MAP_Z 32 // size of map along z-axis
#define MAP_SCALE 20.0f // the scale of the terrain map
////// Texture Information
BITMAPINFOHEADER bitmapInfoHeader; // temp bitmap info header
BITMAPINFOHEADER landInfo; // land texture info header
BITMAPINFOHEADER waterInfo; // water texture info header
//AUX_RGBImageRec
unsigned char* imageData; // the map image data
unsigned char* landTexture; // land texture data
unsigned int land; // the land texture object
////// Terrain Data
float terrain[MAP_X][MAP_Z][3]; // heightfield terrain data (0-255); 256x256
// LoadBitmapFile
// desc: Returns a pointer to the bitmap image of the bitmap specified
// by filename. Also returns the bitmap header information.
// No support for 8-bit bitmaps.
unsigned char *LoadBitmapFile(char *filename, BITMAPINFOHEADER *bitmapInfoHeader)
{
FILE *filePtr; // the file pointer
BITMAPFILEHEADER bitmapFileHeader; // bitmap file header
unsigned char *bitmapImage; // bitmap image data
int imageIdx = 0; // image index counter
unsigned char tempRGB; // swap variable
// open filename in "read binary" mode
filePtr = fopen(filename, "rb");
if (filePtr == NULL)
return NULL;
// read the bitmap file header
fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);
// verify that this is a bitmap by checking for the universal bitmap id
if (bitmapFileHeader.bfType != BITMAP_ID)
{
fclose(filePtr);
return NULL;
}
// read the bitmap information header
fread(bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr);
// move file pointer to beginning of bitmap data
fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET);
// allocate enough memory for the bitmap image data
bitmapImage = (unsigned char*)malloc(bitmapInfoHeader->biSizeImage);
// verify memory allocation
if (!bitmapImage)
{
free(bitmapImage);
fclose(filePtr);
return NULL;
}
// read in the bitmap image data
fread(bitmapImage, 1, bitmapInfoHeader->biSizeImage, filePtr);
// make sure bitmap image data was read
if (bitmapImage == NULL)
{
fclose(filePtr);
return NULL;
}
// swap the R and B values to get RGB since the bitmap color format is in BGR
for (imageIdx = 0; imageIdx < bitmapInfoHeader->biSizeImage; imageIdx+=3)
{
tempRGB = bitmapImage[imageIdx];
bitmapImage[imageIdx] = bitmapImage[imageIdx + 2];
bitmapImage[imageIdx + 2] = tempRGB;
}
// close the file and return the bitmap image data
fclose(filePtr);
return bitmapImage;
}
bool LoadTextures()
{
// load the land texture data
landTexture = LoadBitmapFile("green.bmp", &landInfo);
if (!landTexture)
return false;
// generate the land texture as a mipmap
glGenTextures(1, &land);
glBindTexture(GL_TEXTURE_2D, land);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, landInfo.biHeight, landInfo.biWidth, GL_RGB, GL_UNSIGNED_BYTE, landTexture);
return true;
}
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
^^^^^^^^^^^
You've asked for double-buffering.
And yet your Render() function seems to assume you're using single-buffering:
void Render()
{
...
glFlush();
}
Either switch to GLUT_SINGLE or use glutSwapBuffers() instead of glFlush().
Why does a 800x600 rectangle in OpenGL take so much longer time than many small rectangles? In my head I would have thought drawing 1 would be better than many.
public class LWJGLtest {
int screenwidth = 1024;
int screenheight = 768;
private Texture texture;
int[][] Star1 = new int[100][2];
public void start() {
try {
Display.setDisplayMode(new DisplayMode(screenwidth, screenheight));
Display.create();
} catch (LWJGLException e) {
e.printStackTrace();
System.exit(0);
}
for (int r = 0; r < Star1.length; r++) {
Star1[r][0] = (int) (screenwidth * Math.random());
Star1[r][1] = (int) (screenheight * Math.random());
for (int c = 0; c < Star1[r].length; c++) {
System.out.print(" " + Star1[r][c]);
}
System.out.println("");
}
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, screenwidth, screenheight, 0, 1, -1);
try {
texture = TextureLoader.getTexture("PNG", ResourceLoader.getResourceAsStream("fighter.png"));
} catch (IOException ex) {
Logger.getLogger(LWJGLtest.class.getName()).log(Level.SEVERE, null, ex);
}
//////////////////
boolean bsmall = false;
////////////////////
while (!Display.isCloseRequested()) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1f, 0f, 0f);
if (bsmall) {
for (int i = 0; i < 100; i++) {
int x = (int) (screenwidth * Math.random());
int y = (int) (screenheight * Math.random());
DrawImage(texture, x, y, 30, 30);
//DrawRect(x, y, screenwidth, screenheight);
}
} else {
for (int i = 0; i < 1; i++) {
int x = 0;//(int) (screenwidth * Math.random());
int y = 0;//(int) (screenheight * Math.random());
DrawImage(texture, x, y, screenwidth, screenheight);
//DrawRect(x, y, screenwidth, screenheight);
}
}
Display.update();
}
Display.destroy();
}
void DrawImage(Texture tex, int x, int y, int w, int h) {
if (tex == null) {
return;
}
tex.bind();
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
glVertex2f(x, y);
glTexCoord2f(1, 0);
glVertex2f(x + w, y);
glTexCoord2f(1, 1);
glVertex2f(x + w, y + h);
glTexCoord2f(0, 1);
glVertex2f(x, y + h);
glEnd();
}
public static void main(String[] argv) {
LWJGLtest displayExample = new LWJGLtest();
displayExample.start();
}
}
When bsmall == true I get 1000 better fps than when false?
This is a very deep question and very hardware dependent. However, notice that in your case the texture coordinates are fixed. That means your smaller rectangles draw smaller versions of the texture. Likely your textures use mipmapping. Mipmapping has smaller versions of a texture for when you display the texture as smaller like you are here.
Therefore, the smaller your rectangles, the less data you'll actually end up accessing. This is called texture fetching, and often its overhead is far greater than vertex processing. So yes, you are processing more vertices, you're drawing about the same number of pixels, and you're doing the same amount of texture fetching -- but your texture fetching is most likely entirely in texture cache, so it's very much faster to access.
You need to compare apples and apples -- make the output look exactly the same and then see which technique is faster.
Another example -- On PS3 graphics hardware there's a certain pattern of tiling full screen drawing that causes the shader quad distributor to do a better job distributing work to the fragment shading units. Likewise it could be with your graphics card. It's hard to know and hard to understand, especially when manufacturers don't like giving away all of their secrets.