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.
Related
I'm learning how to use OpenGL by doing an online course and the practice problem asks to create a function to draw pixels:
void SetPixel(int x, int y, char r, char g, char b){}
I know I could do something like this to draw one:
glBegin(GL_POINTS);
glColor3f(1.0,1.0,1.0);
glVertex2i(100,100);
glEnd();
However given the context of the problem it's not a valid solution.
The problem also asks to use the SetPixel function by calling it within a loop to randomly place pixels across the screen. I understand how to implement that, but it's the drawing the actual pixel I don't understand, especially within the context of the program given.
The program (using GLUT):
#include <stdlib.h> //- for exit()
#include <stdio.h> //- for sprintf()
#include <string.h> //- for memset()
#ifdef _WIN32
#include "libs/glut.h"
#include <windows.h>
#pragma comment(lib, "winmm.lib") //- not required but have it in anyway
#pragma comment(lib, "libs/glut32.lib")
#elif __APPLE__
#include <GLUT/glut.h>
#elif __unix__
#include <GL/glut.h>
#endif
#define FRAME_WIDE 1000
#define FRAME_HIGH 600
//====== Structs & typedefs =========
typedef unsigned char BYTE;
struct POINT2D {int x, y;};
//====== Global Variables ==========
BYTE pFrameL[FRAME_WIDE * FRAME_HIGH * 3];
BYTE pFrameR[FRAME_WIDE * FRAME_HIGH * 3];
int shade = 0;
POINT2D xypos = {0,0};
int stereo = 0;
int eyes = 10;
//===== Forward Declarations ========
void ClearScreen();
void DrawFrame();
void Interlace(BYTE* pL, BYTE* pR);
void BuildFrame(BYTE *pFrame, int view);
void OnIdle(void);
void OnDisplay(void);
void reshape(int w, int h);
////////////////////////////////////////////////////////
// Program Entry Poinr
////////////////////////////////////////////////////////
int main(int argc, char** argv)
{
//-- setup GLUT --
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); //GLUT_3_2_CORE_PROFILE |
glutInitWindowSize(FRAME_WIDE, FRAME_HIGH);
glutInitWindowPosition(100, 100);
glutCreateWindow(argv[0]);
//--- set openGL state --
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
//-- register call back functions --
glutIdleFunc(OnIdle);
glutDisplayFunc(OnDisplay);
glutReshapeFunc(reshape);
//-- run the program
glutMainLoop();
return 0;
}
////////////////////////////////////////////////////////
// Event Handers
////////////////////////////////////////////////////////
void OnIdle(void)
{
DrawFrame();
glutPostRedisplay();
}
void OnDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glRasterPos2i(0, 0);
glDrawPixels(FRAME_WIDE, FRAME_HIGH, GL_RGB,GL_UNSIGNED_BYTE, (GLubyte*)pFrameR);
glutSwapBuffers();
glFlush();
}
void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, (GLdouble) w, 0.0, (GLdouble) h);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
////////////////////////////////////////////////////////
// Utility Functions
////////////////////////////////////////////////////////
void ClearScreen()
{
memset(pFrameL, 0, FRAME_WIDE * FRAME_HIGH * 3);
memset(pFrameR, 0, FRAME_WIDE * FRAME_HIGH * 3);
}
void Interlace(BYTE* pL, BYTE* pR)
{
int rowlen = 3 * FRAME_WIDE;
for (int y = 0; y < FRAME_HIGH; y+=2)
{
for (int x = 0; x < rowlen; x++) *pR++ = *pL++;
pL += rowlen;
pR += rowlen;
}
}
void DrawFrame()
{
ClearScreen();
if (!stereo) BuildFrame(pFrameR, 0);
else {
BuildFrame(pFrameL, -eyes);
BuildFrame(pFrameR, +eyes);
Interlace((BYTE*)pFrameL, (BYTE*)pFrameR);
}
}
////////////////////////////////////////////////////////
// Drawing Function
////////////////////////////////////////////////////////
void BuildFrame(BYTE *pFrame, int view)
{
// create a loop in here that uses SetPixel function to randomly place 10,000 pixels
}
void SetPixel(int x, int y, char r, char g, char b)
{
}
Can someone please help me work this out? How would I implement the SetPixel function elegantly?
Based on your configurations for the pixel format, the red component of the pixel at (x, y) is at index 3 * (y * width + x), and +1 / 2 for green / blue:
void SetPixel(int x, int y, char r, char g, char b)
{
if (x < 0 || x >= FRAME_WIDE || y < 0 || y >= FRAME_HIGH)
return; // out of bounds
int index = 3 * (y * FRAME_WIDE + x);
pFrame[index] = r;
pFrame[index+1] = g;
pFrame[index+2] = b;
}
Note that it is unclear whether SetPixel should write both buffers or there should be a flag indicating which one, so I just wrote pFrame as a placeholder.
I have recently decided to try to learn c++. My major road block so far is object/class declaration I am reasonably experienced in java but the way c++ works confuses me. Can someone please show me a example of using a object (like the one below if possible) inside one file or multiple files? here is my current code (object is not implemented).
//inclusions
#include <GLUT/glut.h>
#include <OpenGL/glu.h>
#include <OpenGL/gl.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
//declarations
void keyboard (unsigned char key, int x, int y);
void keyboardUp (unsigned char key, int x, int y);
void mouseLocation(int,int);
int onMouse;
int rightClick;
int a = 0;
int mx;
int my;
float red=1.0, blue=0, green=0;
class Ant
{
private:
int x;
int y;
int speed;
Ant() { } // private default constructor
public:
Ant(int nx, int ny, int nspeed)
{
SetX(nx);
SetY(ny);
SetSpeed(nspeed);
}
void SetX(int nx)
{
x = nx;
}
void SetY(int ny)
{
y = ny;
}
void SetSpeed(int nspeed)
{
speed = nspeed;
}
int GetX() { return x; }
int GetY() { return y; }
int GetSpeed() { return speed; }
};
//mouse listener methods
void mouseLocation(int x,int y) {
mx = x;
my = y;
}
void mouseClicks(int button, int state, int x, int y) {
mx = x;
my = y;
if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
onMouse = 1;
}
if(button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
onMouse = 0;
}
if(button == GLUT_RIGHT_BUTTON && state == GLUT_UP) {
rightClick = 0;
}
if(button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) {
rightClick = 1;
}
}
//keylistner methods
void keyboard (unsigned char key, int x, int y)
{
if (key == 'a')
{
a = 1;
}
}
void keyboardUp (unsigned char key, int x, int y)
{
if(key == 'a')
{
a = 0;
}
}
//drawing methods
void line1()
{
if(a == 1)
{
glLineWidth(2.5);
glBegin(GL_LINES);
glVertex2i(20,20);
glVertex2i(100,400);
glEnd();
}
}
void line2()
{
if(onMouse == 1)
{
glLineWidth(2.5);
glBegin(GL_LINES);
glVertex2i(200,20);
glVertex2i(100,400);
glEnd();
}
}
void rect1()
{
if(mx >= 50 && my >= 50)
{
int x = 100;
int y = 100;
int w = 100;
int h = 100;
unsigned int rgba = 0xff0000ff; // red, no alpha
glBegin(GL_QUADS);
glColor4f(((rgba>>24)&0xff)/255.0f,
((rgba>>16)&0xff)/255.0f,
((rgba>>8)&0xff)/255.0f,
(rgba&0xff)/255.0f);
glVertex3f(x,y,0);
glVertex3f(x+w,y,0);
glVertex3f(x+w,y+h,0);
glVertex3f(x,y+h,0);
glEnd();
glColor4f(1, 1, 1, 1);
}
}
void rect2()
{
if(rightClick == 1)
{
int x = 100;
int y = 100;
int w = 100;
int h = 100;
unsigned int rgba = 0xff0000ff; // red, no alpha
glBegin(GL_QUADS);
glColor4f(((rgba>>24)&0xff)/255.0f,
((rgba>>16)&0xff)/255.0f,
((rgba>>8)&0xff)/255.0f,
(rgba&0xff)/255.0f);
glVertex3f(mx,my,0);
glVertex3f(mx+w,my,0);
glVertex3f(mx+w,my+h,0);
glVertex3f(mx,my+h,0);
glEnd();
glColor4f(1, 1, 1, 1);
}
}
//render drawing methods
void renderScence(void){
glClear (GL_COLOR_BUFFER_BIT);
glColor3f(red, green, blue);
line1();
line2();
rect1();
rect2();
glFlush();
}
//graphics init method
void init(void)
{
glutInitDisplayMode(GLUT_SINGLE |GLUT_RGB);
glutInitWindowSize (500,500);
glutInitWindowPosition (100, 100);
glutCreateWindow ("Testing");
glClearColor (0, 0, 0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, 500, 0, 500);
}
//main/graphics calls
int main(int argc,char** argv)
{
glutInit(&argc, argv);
init();
glutDisplayFunc(renderScence);
glutIdleFunc(renderScence);
glutMouseFunc(mouseClicks);
glutPassiveMotionFunc(mouseLocation);
glutKeyboardUpFunc (keyboardUp);
glutKeyboardFunc (keyboard);
glutMainLoop();
return 0;
}
Your class definition is correct (although a bit Javaish). You can create and use an object of type Ant like this:
Ant a(3, 7, 82);
a.SetSpeed(42);
int speed = a.GetSpeed();
I can't get my GLUT program to work properly.I want to draw text (a char array) letter by letter with some miliseconds interval. My program:
#include <string.h>
#include <windows.h>
#include <glut.h>
#include<iostream>
int hei = glutGet(GLUT_SCREEN_HEIGHT)/2;
int wid = glutGet(GLUT_SCREEN_WIDTH)/2;
void *font = GLUT_BITMAP_TIMES_ROMAN_24;
void *fonts[] =
{
GLUT_BITMAP_9_BY_15,
GLUT_BITMAP_TIMES_ROMAN_10,
GLUT_BITMAP_TIMES_ROMAN_24
};
void selectFont(int newfont)
{
font = fonts[newfont];
glutPostRedisplay();
}
void selectColor(float r, float g, float b)
{
glColor3f(r, g, b);
glutPostRedisplay();
}
char *msg;
void tick(void)
{
glutPostRedisplay();
}
void timer(int value) {
}
int element=0;
void output(int x, int y, char *string, bool center=true) {
int len;
len = strlen(string);
if(center){
glRasterPos2f((wid-len), y);
}
else {
glRasterPos2f(x, y);
}
for(int i=0;i<len;i++) {
glutBitmapCharacter(font, string[i]);
glPopMatrix();
glutSwapBuffers();
Sleep(500);
}
}
void outputmsg(int x, int y, bool center=true) {
int len;
len = strlen(msg);
if(center){
glRasterPos2f((wid-len), y);
}
else {
glRasterPos2f(x, y);
}
for(int i=0;i<len;i++) {
glutBitmapCharacter(font, msg[i]);
}
}
void updatemsg() {
msg="test msg letter by letter";
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
msg="|";
updatemsg();
if(msg!="|")
output(wid, hei, msg, true);
else
output(wid,hei,msg,true);
}
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, w, h, 0);
glMatrixMode(GL_MODELVIEW);
}
void keyboard(unsigned char key, int x, int y) {
switch(key){
case 27:
exit(1);
break;
}
}
int main(int argc, char **argv)
{
int i, msg_submenu, color_submenu;
glutInit(&argc, argv);
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-mono")) {
font = GLUT_BITMAP_9_BY_15;
}
}
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(wid*2, hei*2);
glutCreateWindow("CHAT");
glutFullScreen();
glClearColor(0.0, 0.0, 0.0, 1.0);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutIdleFunc(tick);
selectFont(0);
glutMainLoop();
return 0; /* ANSI C requires main to return int. */
}
It does really weird stuff like erasing the previus one char then printing then printing the next one and the erased one. I tried everything what i could find about this topic on the forums. How can i fix it?
What you should do is also hold the length of the string you want to display and increment it every few milliseconds:
int len;
char *msg;
void incrementLength(int value){
if(msg[len]==0)return; //end of string stop the callback
len++;
glutTimerFunc(100, incrementLength, 0);
glutPostRedisplay();
}
void updatemsg() {
msg="test msg letter by letter";
len=0;
glutTimerFunc(100, incrementLength, 0);
}
And then in outputmsg (if you actually call it) you only loop until len:
void outputmsg(int x, int y, bool center=true) {
if(center){
glRasterPos2f((wid-len), y);
}
else {
glRasterPos2f(x, y);
}
for(int i=0;i<len;i++) {
glutBitmapCharacter(font, msg[i]);
}
}
This code has a couple of issues:
for(int i=0;i<len;i++) {
glutBitmapCharacter(font, string[i]);
glPopMatrix();
glutSwapBuffers();
Sleep(500);
}
You are popping a matrix that you never pushed anywhere, and you are doing it len-many times.
You are swapping buffers without clearing the screen in-between... that's going to lead to undefined results (generally a garbled mess of characters from previous frames).
You really need to re-think how you've implemented this.
I would suggest you implement some elapsed time check in your display (...) function that determines which character to print, rather than doing this in a loop that calls Sleep (...).
I am trying to write my own rasterizer using only gldrawpixels() (and glfw).
I can't use opengl 3 or 4 stuff, because my laptop only has intelgraphics.
I want to keep my code cross-platform so no windows.h. I can't use pixeltoaster, because it does not build on mingw.
When i run my program it crashes why? I don't know which function causes the error.
Here is my code:
My main.cpp:
#include "main.h"
GLFWwindow* window;
unsigned int x ,y,size;
float* pixeldata;
// init
bool init()
{
bool init_val;
if(!glfwInit() )
{
std::cout << "GLFW failed to initialize \n";
init_val = false;
glfwTerminate();
return init_val;
}
init_val = true;
return init_val;
}
//creat window and allocate memory for pixelbuffer
int createwindow(int width, int height, char* window_name, int fullscreen)
{
x = width;
y = height;
size = x*y;
pixeldata = new float[size*3];
std::cout << size;
if (fullscreen == 1)
{
window = glfwCreateWindow( width, height, window_name ,glfwGetPrimaryMonitor(),NULL );
}
else
{
window = glfwCreateWindow( width, height, window_name ,NULL,NULL );
}
if(!window)
{
std::cout << "failed to open window! \n";
glfwTerminate();
return -1;
}
else
{
glfwMakeContextCurrent(window);
}
}
//places pixel on screen, doesn't work properly
void setpixel(unsigned int xloc,unsigned int yloc)
{
unsigned int pixloc;
pixloc = xloc * yloc;
if(pixloc > size)
{
std::cout << "TOO FAR!";
glfwWindowShouldClose(window);
glfwTerminate();
}
else
{
pixeldata[pixloc*3] = 10;
}
}
void render()
{
glClear(GL_COLOR_BUFFER_BIT);
glDrawPixels(x, y, GL_RGB, GL_FLOAT, pixeldata);
}
int main()
{
init();
createwindow(760, 360,"window", 0);
drawline(10,10, 380,180);
while (!glfwWindowShouldClose(window))
{
render();
glfwPollEvents();
glfwSwapBuffers(window);
}
glfwTerminate();
}
My main.h:
#ifndef MAIN_H_INCLUDED
#define MAIN_H_INCLUDED
//GL libs
#include <GL/glfw.h>
#include <GLM/glm.hpp>
// STD libs
#include <iostream>
#include <string>
#include <fstream>
#include <thread>
#include <cmath>
//shared functions
//main.cpp
void setpixel(unsigned int xloc, unsigned int yloc);
//draw.cpp
void drawline( unsigned int x0, unsigned int y0, unsigned int x1, unsigned int y1 );
my draw.cpp:
#include "main.h"
//does not work, should draw a line
void drawline( unsigned int x0, unsigned int y0, unsigned int x1, unsigned int y1 )
{
int dx = x1 - x0;
int dy = y1 - y0;
int a = dy/dx;
int x2 = x0, y2 = y0;
int b = (a*x2) - y2;
b *= -1;
for (int i = x0; x0 <= x1; i++)
{
y2 = a*x2 + b;
setpixel(i,y2);
}
}
I forgot to tell, this is a hobby project.
It looks like the problem may be in setpixel():
void setpixel(unsigned int xloc,unsigned int yloc)
{
unsigned int pixloc;
pixloc = xloc * yloc; // <- this is wrong
if(pixloc > size)
{
std::cout << "TOO FAR!";
glfwWindowShouldClose(window);
glfwTerminate();
}
else
{
pixeldata[pixloc*3] = 10; // <- and this is wrong
}
}
The first wrong line needs to be:
pixloc = (yloc * bytesPerRow) + (xloc * bytesPerPixel);
where bytesPerRow is width * bytesPerPixel in this case and bytesPerPixel is 3
The second wrong line can then just be:
pixeldata [ pixloc ] = 10;
All that said, you shouldn't write your own line drawing routine. You should just use OpenGL's line drawing capabilities (GL_LINES).
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 ?