Related
How can i fix ridicilous amounts of collision when i increase mass or speed?
#include "raylib.h"
#include <cstdio>
#define screenWidth 800
#define screenHeight 450
Vector2 GetNewSpeeds(float mass1, float speed1, float mass2, float speed2)
{
Vector2 newSpeeds;
newSpeeds.x = (speed1 * (mass1 - mass2) + 2 * mass2 * speed2) / (mass1 + mass2);
newSpeeds.y = (speed2 * (mass2 - mass1) + 2 * mass1 * speed1) / (mass1 + mass2);
return newSpeeds;
}
int main()
{
InitWindow(screenWidth, screenHeight, "1D Elastic Collision Simulation");
Rectangle square1 = { 90.0f, screenHeight / 2, 50.0f, 50.0f };
Vector2 speed1 = { 0.0f, 0.0f };
float mass1 = 1.0f;
Rectangle square2 = { 700.0f, screenHeight / 2, 50.0f, 50.0f };
Vector2 speed2 = { -200.0f, 0.0f };
float mass2 = 1000000.0f;
Rectangle wall = { 0, 0, 20, screenHeight };
Color wallColor = LIGHTGRAY;
int collisionCount = 0;
bool touching = false;
while (!WindowShouldClose())
{
ClearBackground(RAYWHITE);
if (CheckCollisionRecs(square1, wall)) {
speed1.x = -speed1.x;
collisionCount++;
}
if (CheckCollisionRecs(square1, square2))
{
if (!touching) {
Vector2 newSpeeds = GetNewSpeeds(mass1, speed1.x, mass2, speed2.x);
speed1.x = newSpeeds.x;
speed2.x = newSpeeds.y;
collisionCount++;
touching = true;
}
}
else {
touching = false;
}
square1.x += speed1.x * GetFrameTime();
square2.x += speed2.x * GetFrameTime();
DrawRectangleRec(square1, BLUE);
DrawRectangleRec(square2, RED);
DrawRectangleRec(wall, wallColor);
char text[32];
sprintf_s(text, "Collision Count: %d", collisionCount);
DrawText(text, 10, 10, 20, BLACK);
EndDrawing();
}
CloseWindow();
return 0;
}
I was expecting blocks to smoothly collide and have a perfect number of collision physically correct. But its about frametime or something. When i increase mass or speed it loses its smoothness and starts giving unexpected results.
I'm trying to implement the flood fill algorithm in OpenGL, but I'm encountering an error doing so. The error is that the algorithm does not stop at the boundary, and simply keeps going until the edge of the window, and eventually crashes with a bad memory access error. I'm working on MacOS Mojave 10.14.4.
I think my implementation's logic is correct, however, I've printed out the color of each pixel from getPixel, and it is always white (the background color), even when getting the color of boundary pixels.
The code below draws a circle using Bresenham's Line algorithm (midpoint algorithm), and then flood fills it (unsuccessfully).
#include <GLUT/GLUT.h>
#include <iostream>
struct Color {
GLubyte r;
GLubyte g;
GLubyte b;
};
Color getPixelColor(GLint x, GLint y) {
Color color;
glReadPixels(x, y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &color);
return color;
}
void setPixel (GLint x, GLint y) {
glBegin(GL_POINTS);
glVertex2i(x, y);
glEnd();
Color color = getPixelColor(x, y);
}
void setPixelColor(GLint x, GLint y, Color color) {
glColor3ub(color.r, color.g, color.b);
setPixel(x, y);
glEnd();
glFlush();
}
void floodFill4 (GLint x, GLint y, Color fillColor, Color interiorColor) {
Color color = getPixelColor(x, y);
if (color.r == interiorColor.r && color.g == interiorColor.g &&
color.b == interiorColor.b) {
setPixelColor(x, y, fillColor);
floodFill4 (x + 1, y, fillColor, interiorColor);
floodFill4 (x - 1, y, fillColor, interiorColor);
floodFill4 (x, y + 1, fillColor, interiorColor);
floodFill4 (x, y - 1, fillColor, interiorColor);
}
}
void drawCirclePoint(GLint x, GLint y, GLint cx, GLint cy) {
setPixel(cx+x, cy+y);
setPixel(cx+y, cy+x);
setPixel(cx-y, cy+x);
setPixel(cx-x, cy+y);
setPixel(cx-x, cy-y);
setPixel(cx-y, cy-x);
setPixel(cx+y, cy-x);
setPixel(cx+x, cy-y);
}
void drawCircle(GLint cx, GLint cy, GLint radius) {
int p = 1 - radius;
GLint x = 0;
GLint y = radius;
while (x < y) {
drawCirclePoint(x, y, cx, cy);
if (p < 0) {
x++;
p += (2 * x) + 1;
} else {
x++;
y--;
p += (2 * x) + 1 - (2 * y);
}
}
}
void displayMe(void) {
glClear(GL_COLOR_BUFFER_BIT);
glColor3ub(0, 0, 0);
GLint cx = 0;
GLint cy = 0;
GLint radius = 200;
// Draw head
glColor3ub(0, 0, 0);
drawCircle(cx, cy, radius);
glEnd();
glFlush();
Color interiorColor = {255, 255, 255};
Color fillColor = {0, 0, 255};
// floodFill4(100, 100, fillColor, interiorColor);
}
void init (void) {
glClearColor(1.0, 1.0, 1.0, 0.0); // Set display-window color to white.
glMatrixMode(GL_PROJECTION); // Set projection parameters.
glLoadIdentity();
gluOrtho2D(-1000.0, 1000.0, -1000.0, 1000.0);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(1000, 1000);
glutInitWindowPosition(100, 100);
glutCreateWindow("My Drawing");
init();
glutDisplayFunc(displayMe);
glutMainLoop();
return 0;
}
I've looked at this post, which seems similar, but wasn't able to find a solution.
If you're going to persist with glVertex() for point plotting make sure you set up your matrix stack transforms (GL_PROJECTION/GL_MODELVIEW) so they match the glReadPixels() coordinate system:
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluOrtho2D( 0, glutGet(GLUT_WINDOW_WIDTH), 0, glutGet(GLUT_WINDOW_HEIGHT) );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
Or switch to glRasterPos() + glDrawPixels() for setPixel*().
Better yet, do the flood-fill logic host-side & upload the results to a GL texture for display.
Either way you're going to run into a stack overflow with that recursive solution on even fairly reasonably sized inputs so you'll probably want to switch to an explicit stack/queue:
void floodFill4( GLint aX, GLint aY, Color fillColor, Color interiorColor )
{
typedef std::pair< GLint, GLint > Location;
std::queue< Location > locations;
locations.push( Location( aX, aY ) );
while( !locations.empty() )
{
const Location loc = locations.front();
locations.pop();
GLint x = loc.first;
GLint y = loc.second;
Color color = getPixelColor( x, y );
if( color.r == interiorColor.r &&
color.g == interiorColor.g &&
color.b == interiorColor.b )
{
setPixelColor( x, y, fillColor );
locations.push( Location( x, y - 1 ) );
locations.push( Location( x, y + 1 ) );
locations.push( Location( x - 1, y ) );
locations.push( Location( x + 1, y ) );
}
}
}
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 just started learning OpenGL with the help of FLTK because I need some GUI functionality. My IDE is VS13 on Windows 7 and my graphics card driver supports OpenGL 2.1.
What I did was simply to run one of their examples and try to modify it a little bit but it failed to compile with something that should be pretty basic - the glCreateShader method which is included in OpenGL 2.1, it says "Error: identifier "glCreateShader" is undefined" although there are a lot of other gl- functions that are recognized. Here is the code, my function is at the end. If I comment it out it builds and runs:
//
// "$Id: cube.cxx 8864 2011-07-19 04:49:30Z greg.ercolano $"
//
// Another forms test program for the Fast Light Tool Kit (FLTK).
//
// Modified to have 2 cubes to test multiple OpenGL contexts
//
// Copyright 1998-2010 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
// file is missing or damaged, see the license at:
//
// http://www.fltk.org/COPYING.php
//
// Please report all bugs and problems on the following page:
//
// http://www.fltk.org/str.php
//
#include <config.h>
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Radio_Light_Button.H>
#include <FL/Fl_Slider.H>
#include <stdlib.h>
#include <string>
#include <FL/Fl_Gl_Window.H>
#include <FL/gl.h>
class cube_box : public Fl_Gl_Window {
void draw();
int handle(int);
public:
double lasttime;
int wire;
double size;
double speed;
cube_box(int x, int y, int w, int h, const char *l = 0)
: Fl_Gl_Window(x, y, w, h, l) {
lasttime = 0.0;
}
};
/* The cube definition */
float v0[3] = { 0.0, 0.0, 0.0 };
float v1[3] = { 1.0, 0.0, 0.0 };
float v2[3] = { 1.0, 1.0, 0.0 };
float v3[3] = { 0.0, 1.0, 0.0 };
float v4[3] = { 0.0, 0.0, 1.0 };
float v5[3] = { 1.0, 0.0, 1.0 };
float v6[3] = { 1.0, 1.0, 1.0 };
float v7[3] = { 0.0, 1.0, 1.0 };
#define v3f(x) glVertex3fv(x)
void drawcube(int wire) {
/* Draw a colored cube */
glBegin(wire ? GL_LINE_LOOP : GL_POLYGON);
glColor3ub(0, 0, 255);
v3f(v0); v3f(v1); v3f(v2); v3f(v3);
glEnd();
glBegin(wire ? GL_LINE_LOOP : GL_POLYGON);
glColor3ub(0, 255, 255); v3f(v4); v3f(v5); v3f(v6); v3f(v7);
glEnd();
glBegin(wire ? GL_LINE_LOOP : GL_POLYGON);
glColor3ub(255, 0, 255); v3f(v0); v3f(v1); v3f(v5); v3f(v4);
glEnd();
glBegin(wire ? GL_LINE_LOOP : GL_POLYGON);
glColor3ub(255, 255, 0); v3f(v2); v3f(v3); v3f(v7); v3f(v6);
glEnd();
glBegin(wire ? GL_LINE_LOOP : GL_POLYGON);
glColor3ub(0, 255, 0); v3f(v0); v3f(v4); v3f(v7); v3f(v3);
glEnd();
glBegin(wire ? GL_LINE_LOOP : GL_POLYGON);
glColor3ub(255, 0, 0); v3f(v1); v3f(v2); v3f(v6); v3f(v5);
glEnd();
}
void cube_box::draw() {
lasttime = lasttime + speed;
if (!valid()) {
glLoadIdentity();
glViewport(0, 0, w(), h());
glEnable(GL_DEPTH_TEST);
glFrustum(-1, 1, -1, 1, 2, 10000);
glTranslatef(0, 0, -10);
gl_font(FL_HELVETICA_BOLD, 16);
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(float(lasttime*1.6), 0, 0, 1);
glRotatef(float(lasttime*4.2), 1, 0, 0);
glRotatef(float(lasttime*2.3), 0, 1, 0);
glTranslatef(-1.0, 1.2f, -1.5);
glScalef(float(size), float(size), float(size));
drawcube(wire);
glPopMatrix();
gl_color(FL_GRAY);
glDisable(GL_DEPTH_TEST);
gl_draw(wire ? "Cube: wire" : "Cube: flat", -4.5f, -4.5f);
glEnable(GL_DEPTH_TEST);
}
int cube_box::handle(int e) {
switch (e) {
case FL_ENTER: cursor(FL_CURSOR_CROSS); break;
case FL_LEAVE: cursor(FL_CURSOR_DEFAULT); break;
}
return Fl_Gl_Window::handle(e);
}
Fl_Window *form;
Fl_Slider *speed, *size;
Fl_Button *button, *wire, *flat;
cube_box *cube;
void makeform(const char *name) {
form = new Fl_Window(510 + 390, 390, name);
new Fl_Box(FL_DOWN_FRAME, 20, 20, 350, 350, "");
new Fl_Box(FL_DOWN_FRAME, 510, 20, 350, 350, "");
speed = new Fl_Slider(FL_VERT_SLIDER, 390, 90, 40, 220, "Speed");
size = new Fl_Slider(FL_VERT_SLIDER, 450, 90, 40, 220, "Size");
wire = new Fl_Radio_Light_Button(390, 20, 100, 30, "Wire");
flat = new Fl_Radio_Light_Button(390, 50, 100, 30, "Flat");
button = new Fl_Button(390, 340, 100, 30, "Exit");
cube = new cube_box(23, 23, 344, 344, 0);
Fl_Box *b = new Fl_Box(FL_NO_BOX, cube->x(), size->y(),
cube->w(), size->h(), 0);
form->resizable(b);
b->hide();
form->end();
}
int main(int argc, char **argv) {
makeform(argv[0]);
// added to demo printing
form->begin();
form->end();
// end of printing demo
speed->bounds(4, 0);
speed->value(cube->speed = 1.0);
size->bounds(4, 0.01);
size->value(cube->size = 1.0);
flat->value(1);
cube->wire = 0;
form->label("cube");
form->show(argc, argv);
cube->show();
for (;;) {
if (form->visible() && speed->value()) {
if (!Fl::check()) break;
} // returns immediately
else {
if (!Fl::wait()) break;} // waits until something happens
cube->wire = wire->value();
cube->size = size->value();
cube->speed = speed->value();
cube->redraw();
if (Fl::readqueue() == button) break;
}
return 0;
}
//////////////////////////// Testing
GLuint CreateShader(GLenum eShaderType, const std::string &strShaderFile)
{
GLuint shader = glCreateShader(eShaderType);
return shader;
}
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.