I wrote an obj loader and as far as i can tell all the loading works fine, however when i try to draw the textures it doesn't work.
i've looked into devil and there are no errors after i load, everything has data but when i draw it doesn't show the image just black.
is there anything you guys could recommend i look into
i have already looked at a few things, but couldn't find the solution.
with how i do things
i have an mtl created per a texture
Loader.h
#pragma once
#include "typedef.h"
#include <string>
#include <vector>
#include <fstream>
#include "MTL.h"
#include "../freeglut.h"
#include <iostream> // this is just for testing, you can remove this with all the cout's
class Loader
{
public:
/**
* \brief string location of the obj file
*
* In Order for you to Load the 3D object you need to specify its location
* in a string.
*
*
*/
Loader( std::string input);
~Loader(void);
void draw(); // this function takes the obj file and draws it
//this can be ignored, it does not make any changes to the problem
void move(float x, float y, float z);
void getPos();
void setPos(float x, float y, float z); // set position
void find_box(float &maxX,float &minX,float &maxY, float &minY, float &maxZ,float &minZ);
private:
std::ifstream m_inFile;
// the list of vectors that i will be using
std::vector<points> m_points;
std::vector<normal> m_normals;
std::vector<coordinate> m_coords;
std::vector<MTL> m_mtl;
std::vector<face> m_faces;
void process(std::string input);
void processMTL(std::string input);
void inputPoints(points temp);
void inputNormals(normal temp);
void inputCoordinates(coordinate temp);
void createFaces(face temp);
};
Loader.cpp
void Loader::process(std::string input)
{
std::string identifier; //used to identify where the input should go
points temppoint;
normal tempnormal;
coordinate tempcoord;
face tempface;
std::string read; // used to read the curent line
int readNum; // this is the number that has just been read in
char skip; // a char to skip thr /
int i;
int count= 1;
//other things to take into account
//****************************************
std::string l_name;
bool firstRun = true;
std::string parse;
//**************************************
m_inFile.open(input);
//creation of the reading loop
m_inFile >> identifier;
do {
// check to see what the opening is
if (identifier =="#")
{
getline(m_inFile,read); // use this to read the whole line
}
else if(identifier == "v")
{
m_inFile >> temppoint.x >> temppoint.y >> temppoint.z;
inputPoints(temppoint);
}
else if(identifier == "vn")
{
m_inFile >> tempnormal.vn[0] >> tempnormal.vn[1] >> tempnormal.vn[2];
inputNormals(tempnormal);
}
else if (identifier == "vt")
{
m_inFile >> tempcoord.vt[0] >> tempcoord.vt[1] >> tempcoord.vt[2];
inputCoordinates(tempcoord);
}
else if(identifier == "f")
{
for( i =0; i < 3; i++)
{
count++;
m_inFile >> readNum;
if(readNum == 0)
break;
readNum--;
tempface.p[i].x = m_points[readNum].x;
tempface.p[i].y = m_points[readNum].y;
tempface.p[i].z = m_points[readNum].z;
m_inFile >> skip >> readNum;
readNum--;
tempface.coord[i].vt[0] = m_coords[readNum].vt[0];
tempface.coord[i].vt[1] = m_coords[readNum].vt[1];
tempface.coord[i].vt[2] = m_coords[readNum].vt[2];
m_inFile >> skip >> readNum;
readNum--;
tempface.norm[i].vn[0] = m_normals[readNum].vn[0];
tempface.norm[i].vn[1] = m_normals[readNum].vn[1];
tempface.norm[i].vn[2] = m_normals[readNum].vn[2];
}
tempface.name = l_name; // this gives the mtl name to the face so it can be compared and applied later
createFaces(tempface);
}
else if(identifier =="mtllib")
{
m_inFile >> identifier;
identifier = "test/" + identifier;
processMTL(identifier);
}
else if(identifier == "usemtl")
{
// chnages the mtl that is being applied
m_inFile >> read;
l_name = read; // so the face can have
}
else
{
getline(m_inFile,read);
std::cout << "Not Processed From Loader" << identifier << " " << read <<std::endl;
}
m_inFile >> identifier;
} while (!m_inFile.eof());
//m_inFile.close();
//m_inFile.~basic_ifstream();
}
void Loader::draw()
{
int i;
int j;
int k;
std::string currentTex;
glEnable(GL_TEXTURE_2D);
//glDisable(GL_TEXTURE_2D);
//glBegin(GL_TRIANGLES);
for (i=0; i < m_faces.size();i++)
{
//bind a certain image
for (k=0; k<m_mtl.size();k++)
{
if (m_mtl[k].compare(m_faces[i].name) == true)
{
//these next two lines do the same thing
//m_mtl[k].draw();
glBindTexture(GL_TEXTURE_2D,m_mtl[k].getGLID());
//break; // break out of the loop
}
}
glBegin(GL_TRIANGLES);
for(j = 0 ; j < 3; j++)
{
glNormal3f(m_faces[i].norm[j].vn[0],m_faces[i].norm[j].vn[1],m_faces[i].norm[j].vn[2]);
glTexCoord2f(m_faces[i].coord[j].vt[0],m_faces[i].coord[j].vt[1]);
glVertex3f(m_faces[i].p[j].x,m_faces[i].p[j].y,m_faces[i].p[j].z);
}
glEnd();
}
}
void Loader::processMTL(std::string input)
{
std::string identifier;
std::string read; //for reading whole lines
MTL mtlTemp;
std::ifstream l_inMtl;
//for reading in numbers to give to the mtl
float ka0, ka1, ka2;
float kd0, kd1, kd2;
float ks0, ks1, ks2;
//so that an empty mtl is not pushed back into the vector
bool firstRun = true;
l_inMtl.open(input);
l_inMtl >> identifier;
do{
if(identifier == "#")
{
getline(l_inMtl,read);
}
else if(identifier == "newmtl")
{
//checks to see if it has run before if it has not run before don't push back the last read
if (firstRun == false)
m_mtl.push_back(mtlTemp);
else
firstRun = false;
l_inMtl >> identifier;
mtlTemp.setName(identifier);
}
else if(identifier == "Ka")
{
l_inMtl >>ka0 >> ka1 >> ka2;
mtlTemp.setKa(ka0,ka1,ka2);
}
else if(identifier == "Kd")
{
l_inMtl >> kd0 >>kd1 >> kd2;
mtlTemp.setKd(kd0,kd1,kd2);
}
else if(identifier =="Ks")
{
l_inMtl >> ks0 >> ks1 >> ks2;
mtlTemp.setKs(ks0, ks1, ks2);
}
else if(identifier == "map_Ka")
{
getline(l_inMtl,identifier);
//l_inMtl >> identifier;
mtlTemp.setLoc(identifier);
}
else
{
getline(l_inMtl,read);
std::cout << "Not Processed MTL" << identifier << " " << read << std::endl;
}
l_inMtl >> identifier;
}while(!l_inMtl.eof());
l_inMtl.close();
m_mtl.push_back(mtlTemp); // so the last one is pushed back
}
MTL.h
#pragma once
#include "../freeglut.h"
#include <string>
#include <fstream>
#include "typedef.h"
#include "../lib/IL/il.h"
#include <iostream>
//#include <IL/il.h>
class MTL
{
public:
MTL(); //name of the file
~MTL(void);
void bind(std::string bindType);// somehow set the bind type eg tile stretch ect
void setVar(float ka0, float ka1, float ka2,float kd0, float kd1, float kd2, float ks0, float ks1, float ks2); // takes in all the inputs and sets them to the class
void setLoc(std::string inLocation); // set the location
void setName(std::string inName);
void setKa(float ka0, float ka1, float ka2);
void setKd(float kd0, float kd1, float kd2);
void setKs(float ks0, float ks1, float ks2);
void setNs(float inNs);
bool compare(std::string inName); // compare the string with another
void draw(); // change the binds
GLuint getGLID() { return texture;};
private:
std::string name;
std::string location; // the location of the image
float ka[3];
float kd[3];
float ks[3];
// must have freeglut in order to use this
BYTE *pixmap; // contains the data (not yet set)
GLuint texture;
//two functions that you need to load and display
void LoadThing();
void createTex(int width, int height, int chan);
};
MTL.cpp
#include "MTL.h"
MTL::MTL() /
{
}
MTL::~MTL()
{
}
void MTL::setName(std::string inName)
{
name = inName;
}
void MTL::setLoc(std::string inLocation)
{
location = inLocation;
LoadThing();
}
bool MTL::compare(std::string inName) // compare the string with another
{
//return true if they are the same
if (name == inName)
return true;
else
return false;
}
void MTL::draw() // change the binds
{
glBindTexture(GL_TEXTURE_2D, texture);
}
void MTL::setKa(float ka0, float ka1, float ka2)
{
ka[0] = ka0;
ka[1] = ka1;
ka[2] = ka2;
}
void MTL::setKd(float kd0, float kd1, float kd2)
{
kd[0] = kd0;
kd[1] = kd1;
kd[2] = kd2;
}
void MTL::setKs(float ks0, float ks1, float ks2)
{
ks[0] = ks0;
ks[1] = ks1;
ks[2] = ks2;
}
void MTL::LoadThing()
{
ILuint devImg;
ilGenImages(1,&devImg);
ilBindImage(devImg);
int error = ilLoadImage("marble_floor2.png");
int e = ilGetError();
pixmap = ilGetData();
int width = ilGetInteger(IL_IMAGE_WIDTH);
int height = ilGetInteger(IL_IMAGE_HEIGHT);
int chan = ilGetInteger(IL_IMAGE_BYTES_PER_PIXEL);
createTex(width,height,chan);
}
void MTL::createTex(int width, int height, int chan)
{
glEnable(GL_TEXTURE_2D);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGenTextures(1, &texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, chan, width, height, 0, (chan == 4)?GL_RGBA: GL_RGB, GL_UNSIGNED_BYTE, pixmap);
//no clue
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
Edit:First thanks to the guys who down voted me, took me a while to realize but i had a lot of functions that you guys didn't need to see so its been reduced.
the places i think could contain a problem would be
draw()
process() from Loader
and
Draw()
LoadThings()
createTex() from MTL
EDIT:
alright guys i found the solution, turns out for some reason opengl uses the glColor when displaying textures, so what is was doing was ... opengl
solution:
add this line just above your glBegin(poly?triangle)
glColor3f(1.0f,1.0f,1.0f)
alright guys i found the solution, turns out for some reason opengl uses the glColor when displaying textures, so what is was doing was ... opengl
solution: add this line just above your glBegin(poly?triangle) glColor3f(1.0f,1.0f,1.0f)
Related
What I have to do is to display an image using a .ptm file.
So, I open the file, read the W and H and set the RGBA to each pixel. But when I try to display I get an Access Violation error at glutSwapBuffers().
Here is the code. It's kind of a mess because I'm trying many different things to fix it but I'm starting to think that each time I create a new problem :D
Image.h
class Image {
public:
Image() {};
Image(int w, int h);
~Image();
void setPixel(int rgb, int x, int y) {
pixels[x + y] = rgb;
}
int setRgb(int r, int g, int b);
int setRgb(int r, int g, int b, int a);
int getPixel(int x, int y) {
return pixels[x + y*width];
}
int * getPixel() { return pixels; }
int getWidth() { return width; }
int getHeight() { return height; }
private:
int *pixels;
int width, height;
};
Image.cpp
#include "Image.h"
#include <stdlib.h>
Image::Image(int w, int h)
{
width = w; height = h;
pixels = (int*)malloc(h*w);
}
Image::~Image()
{
}
int Image::setRgb(int r, int g, int b)
{
int rgb;
rgb = (r << 16) | (g << 8) | b;
return rgb;
}
int Image::setRgb(int r, int g, int b, int a)
{
int rgba;
rgba = (a<< 24) | (r << 16) | (g << 8) | b;
return rgba;
}
source.cpp
#include <GL\freeglut.h>
#include <GL\GL.h>
#include <iostream>
#include <fstream>
#include <string>
#include <Windows.h>
#include "Image.h"
using namespace std;
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
Image *img = new Image(800, 500);
int w, h, max; //width height MaxValue
char *w_ = new char; //in case of the file doesn't have a comment
string fileModel, comment;
ifstream myfile("dba.ptm"); //open the file
if (myfile.is_open())
{
myfile >> fileModel;
if (fileModel == "P7")
{
myfile >> w_;
if (*w_ == '#')
getline(myfile, comment);
else
w = atoi(w_);
myfile >> h;
int a, r, g, b, rgba;
myfile >> max;
for (int i = 0; i < w; i++)
{
for (int k = 0; k < h; k++)
{
myfile >> a;
myfile >> r;
myfile >> g;
myfile >> b;
rgba = img->setRgb(r, g, b, a);
img->setPixel(rgba, i, k);
}
}
}
}
myfile.close();
glDrawPixels(img->getWidth(), img->getHeight(), GL_BGRA_EXT, GL_UNSIGNED_BYTE, img->getPixel());
glutSwapBuffers();
}
void init(void)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 800.0, 0.0, 500.0, -1.0, 1.0);
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize(800, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow("PTM");
init();
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
Sorry, but you have LOTS wrong... :)
You're using malloc instead of new[]
You never free or delete anything
In most cases (apart from pixels) you don't need to create things on the heap anyway
This pixels[x + y] = rgb; is obviously wrong
This : char *w_ = new char; //in case of the file doesn't have a comment
myfile >> w_;
if (*w_ == '#')
.. absolutely does NOT do what you think it does, or what you want it to do.
There's probably more. :(
malloc(h*w) should be malloc(h*w*sizeof(int)), otherwise you're only allocating enough memory for a quarter of your image.
You also seem to be leaking the entire image every single frame, which will quickly exhaust your available RAM. You need to free and delete everything you malloc and new, respectively.
You probably also want to clear the memory you allocate for your image right away to avoid problems where only some of the pixels are set (the rest will be random values, which is likely less preferable than e.g. full transparency). You can do this with a memset or std::fill after the malloc.
I have this error:
Exception thrown at 0x0108C6E9 in myprojectname.exe: 0xC0000005: Access violation reading location 0x00000028.
However, this only happens when I call a function from the base class via the derived class.
derived class:
#pragma once
#include "Player.h"
class Space;
class Enemy : public Player{
public:
void init(Space * s);
private:
//Space * space = nullptr;
};
CPP file:
#include "Space.h"
#include "Enemy.h"
#include "Player.h"
void Enemy::init(Space * s) {
//space = s;
}
I need a pointer to the space object because my base class also needs that. I am not sure if this is needed.
This is how I call the functions of the base(Player) class:
space->getEnemy().drawPlayer(); //FIRST I GET THE OBJECT OF THE DERIVED(ENEMY CLASS) AND THAN I CALL A FUNCTION FROM THE BASE CLASS(PLAYER CLASSS)
The error message "Unable to read memory" happens in getter functions in a class that the base class needs(for example a pointer to the window).
Does anyone know what I am doing wrong?
EDIT
I forgot to tell: I initialize that space pointer to my import class named Space, in every class of my project. The program works fine with those space pointers if I don't call the inherited stuff of Enemy class
Space.h
#pragma once
#include "Window.h"
#include "Game.h"
#include "Input.h"
#include "Text.h"
#include "Player.h"
#include "Enemy.h"
#include <ctime>
class Space {
public:
void init();
int getStartTime();
Window & getWindow();
Game & getGame();
Input & getInput();
Text & getText();
Player & getPlayer();
Enemy & getEnemy();
private:
Text textObj;
Window windowObj;
Game gameObj;
Input inputObj;
Player playerObj;
Enemy enemyObj;
int startTime = clock();
};
Space.cpp:
#include "Space.h"
//PASSING THE SPACE CLASS OBJECT TO THE INIT FUNCTIONS OF THE OTHER CLASSES
void Space::init(){
windowObj.init(this);
gameObj.init(this);
inputObj.init(this);
textObj.init(this);
playerObj.init(this);
enemyObj.init(this);
//STARTING THE GAME ACTUALLY
windowObj.createWindow();
}
Enemy & Space::getEnemy() {
return enemyObj;
}
Window & Space::getWindow(){
return windowObj;
}
Game & Space::getGame() {
return gameObj;
}
Input & Space::getInput() {
return inputObj;
}
Text & Space::getText() {
return textObj;
}
Player & Space::getPlayer(){
return playerObj;
}
int Space::getStartTime(){
return startTime;
}
Player.h(has space pointer):
#pragma once
class Space;
class Player {
public:
void init(Space * s);
void drawPlayer();
void setPlayerXSpeed(float speed);
void move();
void jump();
void checkFalling();
void setJumping(bool value);
void setAttacking(bool value);
void projectileAttack();
float getPlayerX();
float getPlayerY();
private:
Space * space;
int sprites = 8;
int chanceToMove = 0;
int times = 0;
int spriteCount = 0;
float spritePart = 0.0f;
float spritePiece;
float playerX = -0.7f;
float playerY = -0.42f;
float playerXSpeed = 0.0f;
float playerYSpeed = 0.0f;
bool ableToChangeY = true;
bool jumping = false;
bool falling = false;
bool strafeRight = true;
bool attacking = false;
};
Player.cpp:
#include "Player.h"
#include "Space.h"
#include <SDL2\SDL_opengl.h>
#include <iostream>
#define MAX_JUMP_HEIGHT 0.2f
#define SPAWN_X -0.42f
void Player::init(Space * s){ //INITIALIZING SPACE CLASS OBJECT
space = s;
spritePiece = 0.125f;
}
void Player::drawPlayer(){
glPushMatrix();
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindTexture(GL_TEXTURE_2D, space->getWindow().getTexture(1));
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glBegin(GL_QUADS);
//PART OF THE SPRITESHEET DRAWING COORDINATES
glTexCoord2f(spritePart, 0.0f); if (strafeRight) { glVertex2f(playerX , playerY + 0.52f); } else { glVertex2f(playerX , playerY + 0.52f); }
glTexCoord2f(spritePart + spritePiece, 0.0f); if (strafeRight) { glVertex2f(playerX + 0.13f, playerY + 0.52f); } else { glVertex2f(playerX - 0.13f, playerY + 0.52f); }
glTexCoord2f(spritePart + spritePiece, 1.0f); if (strafeRight) { glVertex2f(playerX + 0.13f, playerY) ; } else { glVertex2f(playerX - 0.13f, playerY ); }
glTexCoord2f(spritePart, 1.0f); if (strafeRight) { glVertex2f(playerX , playerY) ; } else { glVertex2f(playerX , playerY ); }
glEnd();
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glPopMatrix();
}
void Player::move(){
chanceToMove++;
if (!attacking){ //NORMAL WALK ANIMATION
if (playerXSpeed != 0.0f) {
if (spriteCount != sprites - 3) { //IF CURRENT PART IS NOT THE LAST PART
if (chanceToMove % 4 == 0) { //SO THE ANIMATION IS NOT AS FAST AS SANIC IS
spritePart += spritePiece;
spriteCount++;
}
}else {
spritePart = 0.0f;
spriteCount = 0;
}
}else {
spritePart = 0.0f; //ALSO RESET
}
}else { //ATTACKING
spritePart = spritePiece * (sprites - 2); //ATTACK SPRITE
projectileAttack();
if (times == 5) {
attacking = false;
times = 0;
}else {
times++;
}
}
if (playerXSpeed < 0) { //IF PLAYER IS MOVING LEFT
strafeRight = false;
}else {
strafeRight = true; //MOVING RIGHT
}
if (jumping) {
jump();
}
playerX += playerXSpeed; //UPDATING PLAYER POSITIONS
playerY += playerYSpeed;
}
void Player::checkFalling() {
if ((playerX < space->getGame().getPlatformLeft() - 0.1f || playerX > space->getGame().getPlatformRight() - 0.05f) && playerY < -0.4f) { //IF PLAYER JUMPED OFF THE PLATFORM
ableToChangeY = false;
playerYSpeed = -0.03f;
}if (playerY < -2.0f) { //IF PLAYER FELL TO DEATH(RIP)
space->getGame().stopGame();
}
}
void Player::setJumping(bool value){
jumping = value;
}
void Player::setAttacking(bool value){
attacking = value;
}
void Player::projectileAttack(){
}
void Player::jump(){
spritePart = spritePiece * (sprites-1); //JUMPING SPRITE
if (ableToChangeY) { //IF PLAYER IS NOT FALLING RIP
if (playerY < MAX_JUMP_HEIGHT && !falling) { //WHILE THE PLAYER DID NOT PASS THE MAXIMUM JUMP HEIGHT
playerYSpeed = 0.03f;
}else { //IF THE PLAYER JUMPED TOO HIGH
falling = true;
if (playerY > SPAWN_X) {
playerYSpeed = -0.03f;
}else { //PLAYER IS BACK ON EARTH
jumping = false;
falling = false;
playerYSpeed = 0.0f;
}
}
}
}
void Player::setPlayerXSpeed(float speed){
playerXSpeed = speed;
}
float Player::getPlayerX()
{
return playerX;
}
float Player::getPlayerY(){
return playerY;
}
EDIT MAIN FUNCTION
#include "Space.h"
#include <iostream>
#include <SDL2\SDL.h>
#include <SDL2\SDL_opengl.h>
#include <SDL2\SDL_ttf.h>
#undef main
int main(int argc, char** argv) {
SDL_Init(SDL_INIT_EVERYTHING);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
TTF_Init();
Space space;
space.init();
std::cout << "Type something and press ENTER to quit..." << std::endl;
char temp;
std::cin >> temp;
TTF_Quit();
SDL_Quit();
return 0;
}
I'm having trouble mapping a texture to an object imported into Opengl. I found a tutorial to import an obj file, but I can't figure out mapping a texture.
This is the code I have written:
class Model
{
public:
Model();
Model(string modelFilename, string textureFilename);
void LoadTexture(string fileName);
void LoadObj(const string& filename, vector<glm::vec4> &vertices, vector<glm::vec3> &normals, vector<GLushort> &elements);
void Draw();
private:
vector<glm::vec4> m_Vertices;
vector<glm::vec3> m_Normals;
vector<GLushort> m_Elements;
string m_ModelFilename;
int m_Texture;
string m_TextureName;
};
Model::Model(string modelFilename, string textureFilename)
{
m_ModelFilename = modelFilename;
m_TextureName = textureFilename;
LoadObj(m_ModelFilename, m_Vertices, m_Normals, m_Elements);
LoadTexture(m_TextureName);
}
void Model::LoadTexture(string TextureName)
{
// Local storage for bmp image data.
BitMapFile *image[1];
string filename = TextureName;
filename.append(".bmp");
// Load the texture.
image[0] = getBMPData(filename);
// Bind grass image to texture index[i].
glBindTexture(GL_TEXTURE_2D, m_Texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image[0]->sizeX, image[0]->sizeY, 0,
GL_RGB, GL_UNSIGNED_BYTE, image[0]->data);
}
void Model::LoadObj(const string& filename, vector<glm::vec4> &vertices, vector<glm::vec3> &normals, vector<GLushort> &elements) {
ifstream in(filename, ios::in);
if (!in) { cerr << "Cannot open " << filename << endl; exit(1); }
string line;
while (getline(in, line)) {
if (line.substr(0,2) == "v ") {
istringstream s(line.substr(2));
glm::vec4 v; s >> v.x; s >> v.y; s >> v.z; v.w = 1.0f;
vertices.push_back(v);
} else if (line.substr(0,2) == "f ") {
istringstream s(line.substr(2));
GLushort a,b,c;
s >> a; s >> b; s >> c;
a--; b--; c--;
elements.push_back(a); elements.push_back(b); elements.push_back(c);
}
else if (line[0] == '#') { /* ignoring this line */}
// else { /* ignoring this line */ }
}
normals.resize(vertices.size(), glm::vec3(0.0, 0.0, 0.0));
for (int i = 0; i < elements.size(); i+=3) {
GLushort ia = elements[i];
GLushort ib = elements[i+1];
GLushort ic = elements[i+2];
glm::vec3 normal = glm::normalize(glm::cross(glm::vec3(vertices[ib]) - glm::vec3(vertices[ia]), glm::vec3(vertices[ic]) - glm::vec3(vertices[ia])));
normals[ia] = normals[ib] = normals[ic] = normal;
}
}
void Model::Draw()
{
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, m_Texture);
for (int i = 0; i < m_Elements.size(); i+=3)
{
GLushort ia = m_Elements[i];
GLushort ib = m_Elements[i+1];
GLushort ic = m_Elements[i+2];
glBegin(GL_TRIANGLES);
glBegin(GL_TRIANGLES);
glNormal3f(m_Normals[ia].x,m_Normals[ia].y,m_Normals[ia].z);//
glNormal3f(m_Normals[ib].x,m_Normals[ib].y,m_Normals[ib].z);//
glNormal3f(m_Normals[ic].x,m_Normals[ic].y,m_Normals[ic].z);//
glTexCoord2f(0.0, 0.0);glVertex3f(m_Vertices[ia].x,m_Vertices[ia].y,m_Vertices[ia].z);
glTexCoord2f(1.0, 1.0);glVertex3f(m_Vertices[ib].x,m_Vertices[ib].y,m_Vertices[ib].z);
glTexCoord2f(0.0, 1.0);glVertex3f(m_Vertices[ic].x,m_Vertices[ic].y,m_Vertices[ic].z);
glEnd();
glEnd();
}
glDisable(GL_TEXTURE_2D);
}
Model model;
void setup(void)
{
glClearColor(1.0, 1.0, 1.0, 0.0);
model = Model("monkey.obj", "launch");
// Specify how texture values combine with current surface color values.
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glEnable(GL_BLEND); // Enable blending.
// Cull back faces.
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
// stops GL_QUAD from showing faces by priority
glEnable(GL_DEPTH_TEST);
}
// Drawing routine.
void drawScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
model.Draw();
glutSwapBuffers();
}
When i run the program this is what happens: http://imgur.com/okMul77
It seems to be mapping the entire image to each triangle, but I don't know how to fix it. Anyone have any ideas? Thank you in advance
I'm trying to generate all the bitmaps for characters from ' ' to '~' and add them to one long texture. I intend to position them in a fixed width texture but for now I just wanted to make sure the concept would work.
But I am having problems. Instead of getting the expected texture I just get the below for a 16px font:
It looks to me as if I'm copying it wrong but no matter what I seem to do I seem to always get the same output.
Finally, the code:
Font.h
#ifndef _FONT_H_
#define _FONT_H_
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <GL/gl.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include "vector2.h"
#include "math_helper.h"
class Font {
public:
Font(const std::string font_path, int size);
~Font();
int get_texture() const { return texture_; }
private:
unsigned int width_, height_, texture_;
static FT_Library LIBRARY;
static const char START_CHAR = ' ';
static const char END_CHAR = '~';
static void initialize_library();
};
#endif
Font.cpp
#include "font.h"
FT_Library Font::LIBRARY = NULL;
Font::Font(const std::string font_path, int size)
: width_(64), height_(2), texture_(0) {
initialize_library();
FT_Face face = NULL;
int error = FT_New_Face(Font::LIBRARY, font_path.c_str(), 0, &face);
if(error == FT_Err_Unknown_File_Format) {
std::cout << "Error: Unknown file format for font \"" << font_path << "\"" << std::endl;
} else if(error) {
std::cout << "Error: Could not open font \"" << font_path << "\"" << std::endl;
}
error = FT_Set_Pixel_Sizes(face, 0, size);
if(error) {
std::cout << "Error: Could not set pixel size for font \"" << font_path << "\"" << std::endl;
}
int num_chars = (END_CHAR - START_CHAR);
width_ = to_nearest_pow2(num_chars * size);
height_ = to_nearest_pow2(size);
std::vector<unsigned char> buffer(width_ * height_, 0);
Vector2 pen;
for(char c = START_CHAR; c <= END_CHAR; ++c) {
error = FT_Load_Char(face, c, FT_LOAD_RENDER);
if(error) {
std::cout << "Error: Could not load char \"" << c << "\"" << std::endl;
continue;
}
FT_Bitmap bmp = face->glyph->bitmap;
int advance = (face->glyph->advance.x >> 6);
int bitmapWidth = bmp.width; //I have tried pitch, same problem
int bitmapHeight = bmp.rows;
for(int h = 0; h < bitmapHeight; ++h) {
for(int w = 0; w < bitmapWidth; ++w) {
int index = h * bitmapWidth + pen.x;
buffer[index + w] = bmp.buffer[w + bitmapWidth * h];
}
}
pen.x += advance;
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGenTextures(1, &texture_);
glBindTexture(GL_TEXTURE_2D, texture_);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width_, height_, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &buffer[0]);
FT_Done_Face(face);
}
Font::~Font() {
if(texture_ != 0) {
glDeleteTextures(1, &texture_);
}
}
void Font::initialize_library() {
if(Font::LIBRARY == NULL) {
if(FT_Init_FreeType(&Font::LIBRARY) != 0) {
std::cout << "Error: Unable to initialize FreeType Library" << std::endl;
return;
}
}
}
Vector2 is just a simple struct with an x and y field that are initialized to 0 on construction.
to_nearest_pow2 is defined as:
template<typename T>
T to_nearest_pow2(const T num) {
T nearest = 2;
while((nearest <<= 1) < num);
return nearest;
}
Oh and here's how I am drawing it to screen (I am using orthographic projection)
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, test->get_texture());
glBegin(GL_QUADS);
glTexCoord2i(0, 0); glVertex2i(0, 0);
glTexCoord2i(1, 0); glVertex2i(400, 0);
glTexCoord2i(1, 1); glVertex2i(400, 400);
glTexCoord2i(0, 1); glVertex2i(0, 400);
glEnd();
Edit
I changed index to what was suggested by #shouston and now I get this output
Rescale your output image to something like 1000x60, and you'll get a surprise. Here's what paint.net made of the PNG you attached.
Obvious things first. The characters are basically there, but for some reason you;'re just rendering them very small (what value of size did you pass?)
Also, you're not trying to handle any of the freetype character metrics, so don't expect them to all line up nicely. yet...
The problem is with the index into your texture buffer:
int index = h * bitmapWidth + pen.x;
should be
int index = h * width_ + pen.x;
i.e multiply h by the full width of the texture, not the width of the glyph.
I writing small program in OpenGL, and I have problem ( textures are skew, and I dont know why, this model work in another obj viewer)
What I have:
http://img696.imageshack.us/i/obrazo.png/
What I want
http://img88.imageshack.us/i/obraz2d.jpg/
Code of project (I use devil for images):
#pragma once
#include <windows.h>
#define GLUT_DISABLE_ATEXIT_HACK
#include <glut.h>
#include <GL/glu.h>
#include <GL/gl.h>
#include <GL/GLEXT.h>
#include <iostream>
#include <cmath>
#include <IL/il.h>
#include <vector>
#include <fstream>
#include <string>
#include <cstdlib>
#include <sstream>
#include <clocale>
class TextureManager
{
struct TextureInfo{
std::string name;
GLuint image;
};
private:
std::vector<TextureInfo> textures;
public:
TextureManager(void);
~TextureManager(void);
bool AddTexture(std::string name, std::string fileName);
int GetTexture(std::string name);
};
TextureManager::TextureManager(void)
{
ilInit();
}
TextureManager::~TextureManager(void)
{
}
bool TextureManager::AddTexture(std::string name, std::string fileName)
{
bool success;
ILuint texId;
GLuint image;
ilGenImages(1, &texId);
ilBindImage(texId);
success = ilLoadImage((WCHAR*)fileName.c_str());
if(success)
{
success = ilConvertImage(IL_RGB, IL_UNSIGNED_BYTE);
if(!success)
{
return false;
}
}
else
{
return false;
}
glGenTextures(1, &image);
glBindTexture(GL_TEXTURE_2D, image);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_NEAREST_MIPMAP_LINEAR);
gluBuild2DMipmaps( GL_TEXTURE_2D, 3, ilGetInteger(IL_IMAGE_WIDTH), ilGetInteger(IL_IMAGE_HEIGHT),GL_RGB, GL_UNSIGNED_BYTE, ilGetData());
ilDeleteImages(1, &texId);
TextureInfo ti;
ti.name = name;
ti.image = image;
textures.push_back(ti);
return true;
}
int TextureManager::GetTexture(std::string name)
{
int size = textures.size();
for(int i=0;i<size;i++)
{
if(textures.at(i).name.compare(name) == 0)
{
return textures.at(i).image;
}
}
return -1;
}
using namespace std;
TextureManager tm;
struct Point
{
double x,y,z;
};
struct Normal
{
double x,y,z;
};
struct Triangle
{
int a,b,c;
int at,bt,ct;
int an,bn,cn;
};
struct TexCord
{
float x,y;
};
vector<Point> points;
vector<Normal> normals;
vector<Triangle> triangles;
vector<TexCord> texcords;
int w,h;
double j = 0.0;
double k = 0.0;
int mode = 1;
bool showNormals = false;
void setCamera(double eyex,double eyey, double eyez, double centerx, double centery, double centerz)
{
gluLookAt(eyex,eyey,eyez,centerx,centery,centerz,0,1,0);
}
void DrawPoint(TexCord tc,Point p,Normal n)
{
glTexCoord2f(tc.x,tc.y);
glNormal3f(n.x,n.y,n.z);
glVertex3f(p.x,p.y,p.z);
}
void DrawNormal(Point p,Normal n)
{
glPushMatrix();
glTranslated(p.x,p.y,p.z);
glBegin(GL_LINES);
glVertex3f(0,0,0);
glVertex3f(n.x*2,n.y*2,n.z*2);
glEnd();
glPopMatrix();
}
void processNormalKeys(unsigned char key, int x, int y) {
if (key == 27)
exit(0);
if (key == 'q')
{
mode = 0;
}
if (key == 'w')
{
mode = 1;
}
if (key == 'a')
{
k -= 0.1;
}
if (key == 's')
{
k += 0.1;
}
if (key == 'z')
{
j -= 0.1;
}
if (key == 'x')
{
j += 0.1;
}
if (key == 'n')
{
if(showNormals == true)
{
showNormals = false;
}
else
{
showNormals = true;
}
}
glutPostRedisplay();
}
void renderScene(void) {
//j+=0.0005;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, (GLfloat)w / (GLfloat)h, 1.0, 100.0);
setCamera(15*sin(j),15*cos(k),15*cos(j)*sin(k),0,0,0);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
//glEnable(GL_LIGHT0);
float ambient[]={ 1.0, 1.0, 1.0, 0.0};
float diffuse[]={1.0, 1.0, 1.0, 1.0};
float position[]={25.0,25.0, 25.0, 1.0};
glLightfv(GL_LIGHT0, GL_AMBIENT, diffuse);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT0, GL_POSITION, position);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tm.GetTexture("tex"));
if(mode == 0 )
{
glBegin(GL_TRIANGLES);
}
else
{
glBegin(GL_LINES);
}
for(int i=0;i<triangles.size();i++)
{
//double r = rand()/(double)RAND_MAX;
//glColor3f(r,r,r);
DrawPoint(texcords[triangles[i].ct-1],points[triangles[i].c-1],normals[triangles[i].cn-1]);
DrawPoint(texcords[triangles[i].bt-1],points[triangles[i].b-1],normals[triangles[i].bn-1]);
DrawPoint(texcords[triangles[i].at-1],points[triangles[i].a-1],normals[triangles[i].an-1]);
}
glEnd();
glDisable(GL_TEXTURE_2D);
if(showNormals == true)
{
glDisable(GL_LIGHTING);
glDisable(GL_LIGHT0);
glColor3f(1,0.5f,0.25f);
for(int i = 0;i<points.size();i++)
{
DrawNormal(points[i],normals[i]);
}
}
glFlush();
glutSwapBuffers();
}
void reshape (int width, int height) {
w = width; h = height;
glViewport(0, 0, (GLsizei)width, (GLsizei)height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, (GLfloat)width / (GLfloat)height, 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
}
void update(int value) {
j += 0.1f;
glutPostRedisplay(); //Tell GLUT that the scene has changed
//Tell GLUT to call update again in 25 milliseconds
// glutTimerFunc(100, update, 0);
}
int main(int argc, char **argv) {
vector<Normal> *nn = &normals;
vector<Point> *pp = &points;
vector<Triangle> *tt = &triangles;
vector<TexCord> *ttcc = &texcords;
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(100,100);
glutInitWindowSize(320,320);
glutCreateWindow("Model view");
glutKeyboardFunc(processNormalKeys);
glutDisplayFunc(renderScene);
//glutIdleFunc(renderScene);
glutReshapeFunc(reshape);
ifstream f;
string cmd;
f.open ("model.obj");
if (f.is_open())
{
while(!f.eof())
{
f>>cmd;
if(cmd=="v")
{
Point p;
f>>p.x;
f>>p.y;
f>>p.z;
points.push_back(p);
}
if(cmd=="vn")
{
Normal n;
f>>n.x;
f>>n.y;
f>>n.z;
normals.push_back(n);
}
if(cmd=="vt")
{
TexCord tc;
f>>tc.x;
f>>tc.y;
texcords.push_back(tc);
}
if(cmd=="f")
{
Triangle t;
string str;
string pointStr,normalStr,cordStr;
string delimeter("/");
int pos,pos2;
stringstream ss (stringstream::in | stringstream::out);
f>>str;
pos = str.find(delimeter);
pointStr = str.substr(0,pos);
cordStr = str.substr(pos+delimeter.length());
pos2 = cordStr.find(delimeter);
normalStr = cordStr.substr(pos2+delimeter.length());
cordStr = cordStr.substr(0,pos2);
ss<<pointStr;
ss>>t.a;
ss.clear();
ss<<normalStr;
ss>>t.an;
ss.clear();
ss<<cordStr;
ss>>t.at;
ss.clear();
f>>str;
pos = str.find(delimeter);
pointStr = str.substr(0,pos);
cordStr = str.substr(pos+delimeter.length());
pos2 = cordStr.find(delimeter);
normalStr = cordStr.substr(pos2+delimeter.length());
cordStr = cordStr.substr(0,pos2);
ss<<pointStr;
ss>>t.b;
ss.clear();
ss<<normalStr;
ss>>t.bn;
ss.clear();
ss<<cordStr;
ss>>t.bt;
ss.clear();
f>>str;
pos = str.find(delimeter);
pointStr = str.substr(0,pos);
cordStr = str.substr(pos+delimeter.length());
pos2 = cordStr.find(delimeter);
normalStr = cordStr.substr(pos2+delimeter.length());
cordStr = cordStr.substr(0,pos2);
ss<<pointStr;
ss>>t.c;
ss.clear();
ss<<normalStr;
ss>>t.cn;
ss.clear();
ss<<cordStr;
ss>>t.ct;
ss.clear();
triangles.push_back(t);
}
cmd = "";
}
f.close(); }
tm.AddTexture("tex","texture.png");
//glutTimerFunc(100, update, 0);
glutMainLoop();
}
I think I'd just push a dummy point on the beginning of your points vector, and leave the point references 1-based. I'd also get rid of the while (!in.eof()), which will normally read the last line twice. Finally, I'd use a few overloads of operator>> to read most of the data, giving a result that looked something like this:
#include <locale>
#include <vector>
#include <sstream>
#include <string>
#include <fstream>
/* change to "#if 0" for normal compilation: */
#if 1
struct Triangle { float a, an, atc, b, bn, btc, c, cn, ctc; };
struct Vector2d { float x, y; };
struct Vector3d { float x, y, z; };
std::vector<Triangle> triangles;
std::vector<Vector3d> points, normals;
std::vector<Vector2d> texcords;
#endif
namespace {
struct slashsep: std::ctype<char> {
slashsep(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table() {
static std::vector<std::ctype_base::mask>
rc(std::ctype<char>::table_size,std::ctype_base::mask());
rc['/'] = std::ctype_base::space; // Treat '/' as a separator between numbers.
rc[' '] = std::ctype_base::space;
rc['\n'] = std::ctype_base::space;
rc['\t'] = std::ctype_base::space;
return &rc[0];
}
};
std::istream &operator>>(std::istream &in, Triangle &triangle) {
std::string str;
std::getline(in, str);
std::istringstream temp(str);
slashsep loc;
temp.imbue(std::locale(std::locale(), &loc));
temp >> triangle.a >> triangle.an >> triangle.atc;
temp >> triangle.b >> triangle.bn >> triangle.btc;
temp >> triangle.c >> triangle.cn >> triangle.ctc;
return in;
}
std::istream &operator>>(std::istream &in, Vector3d &v) {
return in >> v.x >> v.y >> v.z;
}
std::istream &operator>>(std::istream &in, Vector2d &v) {
return in >> v.x >> v.y;
}
}
bool read_obj(std::string const &fileName) {
points.clear();
points.push_back(Vector3d());
triangles.clear();
std::ifstream in(fileName.c_str());
std::string cmd;
if (!in.is_open())
return false;
while(in>>cmd) {
if(cmd=="v") {
Vector3d vector;
in >> vector;
points.push_back(vector);
}
if(cmd=="vt") {
Vector2d texcord;
in >> texcord;
texcords.push_back(texcord);
}
if(cmd=="vn"){
Vector3d normal;
in >> normal;
normals.push_back(normal);
}
if(cmd=="f") {
Triangle triangle;
in >> triangle;
triangles.push_back(triangle);
}
}
return true;
}
One minor point: while using the locale to treat '/' as a separator between numbers works for the specific variant of OBJ that you're looking at, it will not work for files that contain lines like:
f a//b c//d e//f
Nonetheless, the general idea (most reading with operator>>) will be fine when/if you decide to enhance it to handle this variant of the format.
Edit: I think I just realized part of the problem. The code to read a face should be like this:
temp >> triangle.a >> triangle.atc >> triangle.an;
temp >> triangle.b >> triangle.btc >> triangle.bn;
temp >> triangle.c >> triangle.ctc >> triangle.cn;
I.e., in the file, it's arranged as vertex/texcoord/normal, but your code and my previous version above tried to read it as vertex/normal/texcoord). Once the code was arranged this way, checking against a reference made the problem fairly obvious.
Ok i fix all :D:D
What I do:
change
glTexCoord2f(tc.x,tc.y);
to
glTexCoord2f(tc.x,1-tc.y);
and the most important thing I change image resolution to 1024x1024 ( I useing mipmaping so I think correct image resolution is important)
Now:
Can sameone explain me why lTexCoord2f(tc.x,1-tc.y); work ?
and is it important to make every image 2^x resolution ?