Has anyone used this tutorial / code to load md2 models?
http://www.videotuto...mation/text.php
I can load the template included in the code perfectly, including its texture.
But when I try to load another model with the same code is not loaded anything on the screen.
This code / tutorial is not to load any model md2?
It was written just for the model that comes with the code?
MD2 Loader
Started by VitaliBR, Jul 13 2010 05:47 PM
9 replies to this topic
#1
Posted 13 July 2010 - 05:47 PM
#2
Posted 13 July 2010 - 07:40 PM
There's probably some problem or difference with the exported model you have. I know the Blender MD2 exporter hasn't been working for a long time now. You'd have to find a very old version to get it to work. There's a place somewhere on the the Blender site where you can download old versions.
Currently using Blender and Unity.
#3
Posted 13 July 2010 - 07:45 PM
Thanks for the reply guy! :)
You know another lib that I can use to md2?
Edit:
Actually, I opened the template that came with the tutorial in MilkShape 3D and exported it to md2
And the model has not appeared on screen as it appeared before being exported by MilkShape. I tried to send an email to the writer of the tutorial, but the e-mail back
You know another lib that I can use to md2?
Edit:
Actually, I opened the template that came with the tutorial in MilkShape 3D and exported it to md2
And the model has not appeared on screen as it appeared before being exported by MilkShape. I tried to send an email to the writer of the tutorial, but the e-mail back
#4
Posted 13 July 2010 - 11:14 PM
Milkshape really keeps up with their exporters so I'd say it's a problem with the tutorial code. You might want to find another tutorial. I saw this one on a search:
http://tfc.duke.free.../models/md2.htm
http://tfc.duke.free.../models/md2.htm
Currently using Blender and Unity.
#5
Posted 14 July 2010 - 12:47 AM
thanks fireside,
I had already seen this tutorial, your explanation is good. But the sample code is very confusing. (I own more easily understand the subject, analyzing the code)
:/
Edit: I did the test, I downloaded the same version (blender 2.42) as the writer said in the tutorial use.
But the model is not loaded yet, only two models used in the example
I had already seen this tutorial, your explanation is good. But the sample code is very confusing. (I own more easily understand the subject, analyzing the code)
:/
Edit: I did the test, I downloaded the same version (blender 2.42) as the writer said in the tutorial use.
But the model is not loaded yet, only two models used in the example
#6
Posted 14 July 2010 - 01:42 PM
md2model.h
vec3f.h
md2model.cpp
#ifndef MD2_MODEL_H_INCLUDED
#define MD2_MODEL_H_INCLUDED
#ifdef __APPLE__
#include <OpenGL/OpenGL.h>
#include <GLUT/glut.h>
#else
#include <GL/GL.h>
#include <GL/Glu.h>
#endif
#include "vec3f.h"
struct MD2Vertex {
Vec3f pos;
Vec3f normal;
};
struct MD2Frame {
char name[16];
MD2Vertex* vertices;
};
struct MD2TexCoord {
float texCoordX;
float texCoordY;
};
struct MD2Triangle {
int vertices[3]; //The indices of the vertices in this triangle
int texCoords[3]; //The indices of the texture coordinates of the triangle
};
class MD2Model {
private:
MD2Frame* frames;
int numFrames;
MD2TexCoord* texCoords;
MD2Triangle* triangles;
int numTriangles;
GLuint textureId;
int startFrame; //The first frame of the current animation
int endFrame; //The last frame of the current animation
/* The position in the current animation. 0 indicates the beginning of
* the animation, which is at the starting frame, and 1 indicates the
* end of the animation, which is right when the starting frame is
* reached again. It always lies between 0 and 1.
*/
float time;
MD2Model();
public:
~MD2Model();
//Switches to the given animation
void setAnimation(const char* name);
//Advances the position in the current animation. The entire animation
//lasts one unit of time.
void advance(float dt);
//Draws the current state of the animated model.
void draw();
//Loads an MD2Model from the specified file. Returns NULL if there was
//an error loading it.
static MD2Model* load(const char* filename);
};
#endif
vec3f.h
#ifndef VEC3F_H_INCLUDED
#define VEC3F_H_INCLUDED
#include <iostream>
class Vec3f {
private:
float v[3];
public:
Vec3f();
Vec3f(float x, float y, float z);
float &operator[](int index);
float operator[](int index) const;
Vec3f operator*(float scale) const;
Vec3f operator/(float scale) const;
Vec3f operator+(const Vec3f &other) const;
Vec3f operator-(const Vec3f &other) const;
Vec3f operator-() const;
const Vec3f &operator*=(float scale);
const Vec3f &operator/=(float scale);
const Vec3f &operator+=(const Vec3f &other);
const Vec3f &operator-=(const Vec3f &other);
float magnitude() const;
float magnitudeSquared() const;
Vec3f normalize() const;
float dot(const Vec3f &other) const;
Vec3f cross(const Vec3f &other) const;
};
Vec3f operator*(float scale, const Vec3f &v);
std::ostream &operator<<(std::ostream &output, const Vec3f &v);
#endif
[/source]
[b]imageloader.h[/b]
[source lang="cpp"]#ifndef IMAGE_LOADER_H_INCLUDED
#define IMAGE_LOADER_H_INCLUDED
//Represents an image
class Image {
public:
Image(char* ps, int w, int h);
~Image();
/* An array of the form (R1, G1, B1, R2, G2, B2, ...) indicating the
* color of each pixel in image. Color components range from 0 to 255.
* The array starts the bottom-left pixel, then moves right to the end
* of the row, then moves up to the next column, and so on. This is the
* format in which OpenGL likes images.
*/
char* pixels;
int width;
int height;
};
//Reads a bitmap image from file.
Image* loadBMP(const char* filename);
#endif
md2model.cpp
#include <fstream>
#include <string.h>
#include "imageloader.h"
#include "md2model.h"
using namespace std;
namespace {
//Normals used in the MD2 file format
float NORMALS[486] =
{-0.525731f, 0.000000f, 0.850651f,
-0.442863f, 0.238856f, 0.864188f,
-0.295242f, 0.000000f, 0.955423f,
-0.309017f, 0.500000f, 0.809017f,
-0.162460f, 0.262866f, 0.951056f,
0.000000f, 0.000000f, 1.000000f,
0.000000f, 0.850651f, 0.525731f,
-0.147621f, 0.716567f, 0.681718f,
0.147621f, 0.716567f, 0.681718f,
0.000000f, 0.525731f, 0.850651f,
0.309017f, 0.500000f, 0.809017f,
0.525731f, 0.000000f, 0.850651f,
0.295242f, 0.000000f, 0.955423f,
0.442863f, 0.238856f, 0.864188f,
0.162460f, 0.262866f, 0.951056f,
-0.681718f, 0.147621f, 0.716567f,
-0.809017f, 0.309017f, 0.500000f,
-0.587785f, 0.425325f, 0.688191f,
-0.850651f, 0.525731f, 0.000000f,
-0.864188f, 0.442863f, 0.238856f,
-0.716567f, 0.681718f, 0.147621f,
-0.688191f, 0.587785f, 0.425325f,
-0.500000f, 0.809017f, 0.309017f,
-0.238856f, 0.864188f, 0.442863f,
-0.425325f, 0.688191f, 0.587785f,
-0.716567f, 0.681718f, -0.147621f,
-0.500000f, 0.809017f, -0.309017f,
-0.525731f, 0.850651f, 0.000000f,
0.000000f, 0.850651f, -0.525731f,
-0.238856f, 0.864188f, -0.442863f,
0.000000f, 0.955423f, -0.295242f,
-0.262866f, 0.951056f, -0.162460f,
0.000000f, 1.000000f, 0.000000f,
0.000000f, 0.955423f, 0.295242f,
-0.262866f, 0.951056f, 0.162460f,
0.238856f, 0.864188f, 0.442863f,
0.262866f, 0.951056f, 0.162460f,
0.500000f, 0.809017f, 0.309017f,
0.238856f, 0.864188f, -0.442863f,
0.262866f, 0.951056f, -0.162460f,
0.500000f, 0.809017f, -0.309017f,
0.850651f, 0.525731f, 0.000000f,
0.716567f, 0.681718f, 0.147621f,
0.716567f, 0.681718f, -0.147621f,
0.525731f, 0.850651f, 0.000000f,
0.425325f, 0.688191f, 0.587785f,
0.864188f, 0.442863f, 0.238856f,
0.688191f, 0.587785f, 0.425325f,
0.809017f, 0.309017f, 0.500000f,
0.681718f, 0.147621f, 0.716567f,
0.587785f, 0.425325f, 0.688191f,
0.955423f, 0.295242f, 0.000000f,
1.000000f, 0.000000f, 0.000000f,
0.951056f, 0.162460f, 0.262866f,
0.850651f, -0.525731f, 0.000000f,
0.955423f, -0.295242f, 0.000000f,
0.864188f, -0.442863f, 0.238856f,
0.951056f, -0.162460f, 0.262866f,
0.809017f, -0.309017f, 0.500000f,
0.681718f, -0.147621f, 0.716567f,
0.850651f, 0.000000f, 0.525731f,
0.864188f, 0.442863f, -0.238856f,
0.809017f, 0.309017f, -0.500000f,
0.951056f, 0.162460f, -0.262866f,
0.525731f, 0.000000f, -0.850651f,
0.681718f, 0.147621f, -0.716567f,
0.681718f, -0.147621f, -0.716567f,
0.850651f, 0.000000f, -0.525731f,
0.809017f, -0.309017f, -0.500000f,
0.864188f, -0.442863f, -0.238856f,
0.951056f, -0.162460f, -0.262866f,
0.147621f, 0.716567f, -0.681718f,
0.309017f, 0.500000f, -0.809017f,
0.425325f, 0.688191f, -0.587785f,
0.442863f, 0.238856f, -0.864188f,
0.587785f, 0.425325f, -0.688191f,
0.688191f, 0.587785f, -0.425325f,
-0.147621f, 0.716567f, -0.681718f,
-0.309017f, 0.500000f, -0.809017f,
0.000000f, 0.525731f, -0.850651f,
-0.525731f, 0.000000f, -0.850651f,
-0.442863f, 0.238856f, -0.864188f,
-0.295242f, 0.000000f, -0.955423f,
-0.162460f, 0.262866f, -0.951056f,
0.000000f, 0.000000f, -1.000000f,
0.295242f, 0.000000f, -0.955423f,
0.162460f, 0.262866f, -0.951056f,
-0.442863f, -0.238856f, -0.864188f,
-0.309017f, -0.500000f, -0.809017f,
-0.162460f, -0.262866f, -0.951056f,
0.000000f, -0.850651f, -0.525731f,
-0.147621f, -0.716567f, -0.681718f,
0.147621f, -0.716567f, -0.681718f,
0.000000f, -0.525731f, -0.850651f,
0.309017f, -0.500000f, -0.809017f,
0.442863f, -0.238856f, -0.864188f,
0.162460f, -0.262866f, -0.951056f,
0.238856f, -0.864188f, -0.442863f,
0.500000f, -0.809017f, -0.309017f,
0.425325f, -0.688191f, -0.587785f,
0.716567f, -0.681718f, -0.147621f,
0.688191f, -0.587785f, -0.425325f,
0.587785f, -0.425325f, -0.688191f,
0.000000f, -0.955423f, -0.295242f,
0.000000f, -1.000000f, 0.000000f,
0.262866f, -0.951056f, -0.162460f,
0.000000f, -0.850651f, 0.525731f,
0.000000f, -0.955423f, 0.295242f,
0.238856f, -0.864188f, 0.442863f,
0.262866f, -0.951056f, 0.162460f,
0.500000f, -0.809017f, 0.309017f,
0.716567f, -0.681718f, 0.147621f,
0.525731f, -0.850651f, 0.000000f,
-0.238856f, -0.864188f, -0.442863f,
-0.500000f, -0.809017f, -0.309017f,
-0.262866f, -0.951056f, -0.162460f,
-0.850651f, -0.525731f, 0.000000f,
-0.716567f, -0.681718f, -0.147621f,
-0.716567f, -0.681718f, 0.147621f,
-0.525731f, -0.850651f, 0.000000f,
-0.500000f, -0.809017f, 0.309017f,
-0.238856f, -0.864188f, 0.442863f,
-0.262866f, -0.951056f, 0.162460f,
-0.864188f, -0.442863f, 0.238856f,
-0.809017f, -0.309017f, 0.500000f,
-0.688191f, -0.587785f, 0.425325f,
-0.681718f, -0.147621f, 0.716567f,
-0.442863f, -0.238856f, 0.864188f,
-0.587785f, -0.425325f, 0.688191f,
-0.309017f, -0.500000f, 0.809017f,
-0.147621f, -0.716567f, 0.681718f,
-0.425325f, -0.688191f, 0.587785f,
-0.162460f, -0.262866f, 0.951056f,
0.442863f, -0.238856f, 0.864188f,
0.162460f, -0.262866f, 0.951056f,
0.309017f, -0.500000f, 0.809017f,
0.147621f, -0.716567f, 0.681718f,
0.000000f, -0.525731f, 0.850651f,
0.425325f, -0.688191f, 0.587785f,
0.587785f, -0.425325f, 0.688191f,
0.688191f, -0.587785f, 0.425325f,
-0.955423f, 0.295242f, 0.000000f,
-0.951056f, 0.162460f, 0.262866f,
-1.000000f, 0.000000f, 0.000000f,
-0.850651f, 0.000000f, 0.525731f,
-0.955423f, -0.295242f, 0.000000f,
-0.951056f, -0.162460f, 0.262866f,
-0.864188f, 0.442863f, -0.238856f,
-0.951056f, 0.162460f, -0.262866f,
-0.809017f, 0.309017f, -0.500000f,
-0.864188f, -0.442863f, -0.238856f,
-0.951056f, -0.162460f, -0.262866f,
-0.809017f, -0.309017f, -0.500000f,
-0.681718f, 0.147621f, -0.716567f,
-0.681718f, -0.147621f, -0.716567f,
-0.850651f, 0.000000f, -0.525731f,
-0.688191f, 0.587785f, -0.425325f,
-0.587785f, 0.425325f, -0.688191f,
-0.425325f, 0.688191f, -0.587785f,
-0.425325f, -0.688191f, -0.587785f,
-0.587785f, -0.425325f, -0.688191f,
-0.688191f, -0.587785f, -0.425325f};
//Returns whether the system is little-endian
bool littleEndian() {
//The short value 1 has bytes (1, 0) in little-endian and (0, 1) in
//big-endian
short s = 1;
return (((char*)&s)[0]) == 1;
}
//Converts a four-character array to an integer, using little-endian form
int toInt(const char* bytes) {
return (int)(((unsigned char)bytes[3] << 24) |
((unsigned char)bytes[2] << 16) |
((unsigned char)bytes[1] << 8) |
(unsigned char)bytes[0]);
}
//Converts a two-character array to a short, using little-endian form
short toShort(const char* bytes) {
return (short)(((unsigned char)bytes[1] << 8) |
(unsigned char)bytes[0]);
}
//Converts a two-character array to an unsigned short, using little-endian
//form
unsigned short toUShort(const char* bytes) {
return (unsigned short)(((unsigned char)bytes[1] << 8) |
(unsigned char)bytes[0]);
}
//Converts a four-character array to a float, using little-endian form
float toFloat(const char* bytes) {
float f;
if (littleEndian()) {
((char*)&f)[0] = bytes[0];
((char*)&f)[1] = bytes[1];
((char*)&f)[2] = bytes[2];
((char*)&f)[3] = bytes[3];
}
else {
((char*)&f)[0] = bytes[3];
((char*)&f)[1] = bytes[2];
((char*)&f)[2] = bytes[1];
((char*)&f)[3] = bytes[0];
}
return f;
}
//Reads the next four bytes as an integer, using little-endian form
int readInt(ifstream &input) {
char buffer[4];
input.read(buffer, 4);
return toInt(buffer);
}
//Reads the next two bytes as a short, using little-endian form
short readShort(ifstream &input) {
char buffer[2];
input.read(buffer, 2);
return toShort(buffer);
}
//Reads the next two bytes as an unsigned short, using little-endian form
unsigned short readUShort(ifstream &input) {
char buffer[2];
input.read(buffer, 2);
return toUShort(buffer);
}
//Reads the next four bytes as a float, using little-endian form
float readFloat(ifstream &input) {
char buffer[4];
input.read(buffer, 4);
return toFloat(buffer);
}
//Calls readFloat three times and returns the results as a Vec3f object
Vec3f readVec3f(ifstream &input) {
float x = readFloat(input);
float y = readFloat(input);
float z = readFloat(input);
return Vec3f(x, y, z);
}
//Makes the image into a texture, and returns the id of the texture
GLuint loadTexture(Image *image) {
GLuint textureId;
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexImage2D(GL_TEXTURE_2D,
0,
GL_RGB,
image->width, image->height,
0,
GL_RGB,
GL_UNSIGNED_BYTE,
image->pixels);
return textureId;
}
}
MD2Model::~MD2Model() {
if (frames != NULL) {
for(int i = 0; i < numFrames; i++) {
delete[] frames[i].vertices;
}
delete[] frames;
}
if (texCoords != NULL) {
delete[] texCoords;
}
if (triangles != NULL) {
delete[] triangles;
}
}
MD2Model::MD2Model() {
frames = NULL;
texCoords = NULL;
triangles = NULL;
time = 0;
}
//Loads the MD2 model
MD2Model* MD2Model::load(const char* filename) {
ifstream input;
input.open(filename, istream::binary);
char buffer[64];
input.read(buffer, 4); //Should be "IPD2", if this is an MD2 file
if (buffer[0] != 'I' || buffer[1] != 'D' ||
buffer[2] != 'P' || buffer[3] != '2') {
return NULL;
}
if (readInt(input) != 8) { //The version number
return NULL;
}
int textureWidth = readInt(input); //The width of the textures
int textureHeight = readInt(input); //The height of the textures
readInt(input); //The number of bytes per frame
int numTextures = readInt(input); //The number of textures
if (numTextures != 1) {
return NULL;
}
int numVertices = readInt(input); //The number of vertices
int numTexCoords = readInt(input); //The number of texture coordinates
int numTriangles = readInt(input); //The number of triangles
readInt(input); //The number of OpenGL commands
int numFrames = readInt(input); //The number of frames
//Offsets (number of bytes after the beginning of the file to the beginning
//of where certain data appear)
int textureOffset = readInt(input); //The offset to the textures
int texCoordOffset = readInt(input); //The offset to the texture coordinates
int triangleOffset = readInt(input); //The offset to the triangles
int frameOffset = readInt(input); //The offset to the frames
readInt(input); //The offset to the OpenGL commands
readInt(input); //The offset to the end of the file
//Load the texture
input.seekg(textureOffset, ios_base::beg);
input.read(buffer, 64);
if (strlen(buffer) < 5 ||
strcmp(buffer + strlen(buffer) - 4, ".bmp") != 0) {
return NULL;
}
Image* image = loadBMP(buffer);
GLuint textureId = loadTexture(image);
delete image;
MD2Model* model = new MD2Model();
model->textureId = textureId;
//Load the texture coordinates
input.seekg(texCoordOffset, ios_base::beg);
model->texCoords = new MD2TexCoord[numTexCoords];
for(int i = 0; i < numTexCoords; i++) {
MD2TexCoord* texCoord = model->texCoords + i;
texCoord->texCoordX = (float)readShort(input) / textureWidth;
texCoord->texCoordY = 1 - (float)readShort(input) / textureHeight;
}
//Load the triangles
input.seekg(triangleOffset, ios_base::beg);
model->triangles = new MD2Triangle[numTriangles];
model->numTriangles = numTriangles;
for(int i = 0; i < numTriangles; i++) {
MD2Triangle* triangle = model->triangles + i;
for(int j = 0; j < 3; j++) {
triangle->vertices[j] = readUShort(input);
}
for(int j = 0; j < 3; j++) {
triangle->texCoords[j] = readUShort(input);
}
}
//Load the frames
input.seekg(frameOffset, ios_base::beg);
model->frames = new MD2Frame[numFrames];
model->numFrames = numFrames;
for(int i = 0; i < numFrames; i++) {
MD2Frame* frame = model->frames + i;
frame->vertices = new MD2Vertex[numVertices];
Vec3f scale = readVec3f(input);
Vec3f translation = readVec3f(input);
input.read(frame->name, 16);
for(int j = 0; j < numVertices; j++) {
MD2Vertex* vertex = frame->vertices + j;
input.read(buffer, 3);
Vec3f v((unsigned char)buffer[0],
(unsigned char)buffer[1],
(unsigned char)buffer[2]);
vertex->pos = translation + Vec3f(scale[0] * v[0],
scale[1] * v[1],
scale[2] * v[2]);
input.read(buffer, 1);
int normalIndex = (int)((unsigned char)buffer[0]);
vertex->normal = Vec3f(NORMALS[3 * normalIndex],
NORMALS[3 * normalIndex + 1],
NORMALS[3 * normalIndex + 2]);
}
}
model->startFrame = 0;
model->endFrame = numFrames - 1;
return model;
}
void MD2Model::setAnimation(const char* name) {
/* The names of frames normally begin with the name of the animation in
* which they are, e.g. "run", and are followed by a non-alphabetical
* character. Normally, they indicate their frame number in the animation,
* e.g. "run_1", "run_2", etc.
*/
bool found = false;
for(int i = 0; i < numFrames; i++) {
MD2Frame* frame = frames + i;
if (strlen(frame->name) > strlen(name) &&
strncmp(frame->name, name, strlen(name)) == 0 &&
!isalpha(frame->name[strlen(name)])) {
if (!found) {
found = true;
startFrame = i;
}
else {
endFrame = i;
}
}
else if (found) {
break;
}
}
}
void MD2Model::advance(float dt) {
if (dt < 0) {
return;
}
time += dt;
if (time < 1000000000) {
time -= (int)time;
}
else {
time = 0;
}
}
void MD2Model::draw() {
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//Figure out the two frames between which we are interpolating
int frameIndex1 = (int)(time * (endFrame - startFrame + 1)) + startFrame;
if (frameIndex1 > endFrame) {
frameIndex1 = startFrame;
}
int frameIndex2;
if (frameIndex1 < endFrame) {
frameIndex2 = frameIndex1 + 1;
}
else {
frameIndex2 = startFrame;
}
MD2Frame* frame1 = frames + frameIndex1;
MD2Frame* frame2 = frames + frameIndex2;
//Figure out the fraction that we are between the two frames
float frac =
(time - (float)(frameIndex1 - startFrame) /
(float)(endFrame - startFrame + 1)) * (endFrame - startFrame + 1);
//Draw the model as an interpolation between the two frames
glBegin(GL_TRIANGLES);
for(int i = 0; i < numTriangles; i++) {
MD2Triangle* triangle = triangles + i;
for(int j = 0; j < 3; j++) {
MD2Vertex* v1 = frame1->vertices + triangle->vertices[j];
MD2Vertex* v2 = frame2->vertices + triangle->vertices[j];
Vec3f pos = v1->pos * (1 - frac) + v2->pos * frac;
Vec3f normal = v1->normal * (1 - frac) + v2->normal * frac;
if (normal[0] == 0 && normal[1] == 0 && normal[2] == 0) {
normal = Vec3f(0, 0, 1);
}
glNormal3f(normal[0], normal[1], normal[2]);
MD2TexCoord* texCoord = texCoords + triangle->texCoords[j];
glTexCoord2f(texCoord->texCoordX, texCoord->texCoordY);
glVertex3f(pos[0], pos[1], pos[2]);
}
}
glEnd();
}
#7
Posted 14 July 2010 - 01:42 PM
vec3f.cpp
imageloader.cpp
imageloader.h
#include <math.h>
#include "vec3f.h"
using namespace std;
Vec3f::Vec3f() {
}
Vec3f::Vec3f(float x, float y, float z) {
v[0] = x;
v[1] = y;
v[2] = z;
}
float &Vec3f::operator[](int index) {
return v[index];
}
float Vec3f::operator[](int index) const {
return v[index];
}
Vec3f Vec3f::operator*(float scale) const {
return Vec3f(v[0] * scale, v[1] * scale, v[2] * scale);
}
Vec3f Vec3f::operator/(float scale) const {
return Vec3f(v[0] / scale, v[1] / scale, v[2] / scale);
}
Vec3f Vec3f::operator+(const Vec3f &other) const {
return Vec3f(v[0] + other.v[0], v[1] + other.v[1], v[2] + other.v[2]);
}
Vec3f Vec3f::operator-(const Vec3f &other) const {
return Vec3f(v[0] - other.v[0], v[1] - other.v[1], v[2] - other.v[2]);
}
Vec3f Vec3f::operator-() const {
return Vec3f(-v[0], -v[1], -v[2]);
}
const Vec3f &Vec3f::operator*=(float scale) {
v[0] *= scale;
v[1] *= scale;
v[2] *= scale;
return *this;
}
const Vec3f &Vec3f::operator/=(float scale) {
v[0] /= scale;
v[1] /= scale;
v[2] /= scale;
return *this;
}
const Vec3f &Vec3f::operator+=(const Vec3f &other) {
v[0] += other.v[0];
v[1] += other.v[1];
v[2] += other.v[2];
return *this;
}
const Vec3f &Vec3f::operator-=(const Vec3f &other) {
v[0] -= other.v[0];
v[1] -= other.v[1];
v[2] -= other.v[2];
return *this;
}
float Vec3f::magnitude() const {
return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
}
float Vec3f::magnitudeSquared() const {
return v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
}
Vec3f Vec3f::normalize() const {
float m = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
return Vec3f(v[0] / m, v[1] / m, v[2] / m);
}
float Vec3f::dot(const Vec3f &other) const {
return v[0] * other.v[0] + v[1] * other.v[1] + v[2] * other.v[2];
}
Vec3f Vec3f::cross(const Vec3f &other) const {
return Vec3f(v[1] * other.v[2] - v[2] * other.v[1],
v[2] * other.v[0] - v[0] * other.v[2],
v[0] * other.v[1] - v[1] * other.v[0]);
}
Vec3f operator*(float scale, const Vec3f &v) {
return v * scale;
}
ostream &operator<<(ostream &output, const Vec3f &v) {
cout << '(' << v[0] << ", " << v[1] << ", " << v[2] << ')';
return output;
}
imageloader.cpp
#include <assert.h>
#include <fstream>
#include "imageloader.h"
using namespace std;
Image::Image(char* ps, int w, int h) : pixels(ps), width(w), height(h) {
}
Image::~Image() {
delete[] pixels;
}
namespace {
//Converts a four-character array to an integer, using little-endian form
int toInt(const char* bytes) {
return (int)(((unsigned char)bytes[3] << 24) |
((unsigned char)bytes[2] << 16) |
((unsigned char)bytes[1] << 8) |
(unsigned char)bytes[0]);
}
//Converts a two-character array to a short, using little-endian form
short toShort(const char* bytes) {
return (short)(((unsigned char)bytes[1] << 8) |
(unsigned char)bytes[0]);
}
//Reads the next four bytes as an integer, using little-endian form
int readInt(ifstream &input) {
char buffer[4];
input.read(buffer, 4);
return toInt(buffer);
}
//Reads the next two bytes as a short, using little-endian form
short readShort(ifstream &input) {
char buffer[2];
input.read(buffer, 2);
return toShort(buffer);
}
//Just like auto_ptr, but for arrays
template<class T>
class auto_array {
private:
T* array;
mutable bool isReleased;
public:
explicit auto_array(T* array_ = NULL) :
array(array_), isReleased(false) {
}
auto_array(const auto_array<T> &aarray) {
array = aarray.array;
isReleased = aarray.isReleased;
aarray.isReleased = true;
}
~auto_array() {
if (!isReleased && array != NULL) {
delete[] array;
}
}
T* get() const {
return array;
}
T &operator*() const {
return *array;
}
void operator=(const auto_array<T> &aarray) {
if (!isReleased && array != NULL) {
delete[] array;
}
array = aarray.array;
isReleased = aarray.isReleased;
aarray.isReleased = true;
}
T* operator->() const {
return array;
}
T* release() {
isReleased = true;
return array;
}
void reset(T* array_ = NULL) {
if (!isReleased && array != NULL) {
delete[] array;
}
array = array_;
}
T* operator+(int i) {
return array + i;
}
T &operator[](int i) {
return array[i];
}
};
}
Image* loadBMP(const char* filename) {
ifstream input;
input.open(filename, ifstream::binary);
assert(!input.fail() || !"Could not find file");
char buffer[2];
input.read(buffer, 2);
assert(buffer[0] == 'B' && buffer[1] == 'M' || !"Not a bitmap file");
input.ignore(8);
int dataOffset = readInt(input);
//Read the header
int headerSize = readInt(input);
int width;
int height;
switch(headerSize) {
case 40:
//V3
width = readInt(input);
height = readInt(input);
input.ignore(2);
assert(readShort(input) == 24 || !"Image is not 24 bits per pixel");
assert(readShort(input) == 0 || !"Image is compressed");
break;
case 12:
//OS/2 V1
width = readShort(input);
height = readShort(input);
input.ignore(2);
assert(readShort(input) == 24 || !"Image is not 24 bits per pixel");
break;
case 64:
//OS/2 V2
assert(!"Can't load OS/2 V2 bitmaps");
break;
case 108:
//Windows V4
assert(!"Can't load Windows V4 bitmaps");
break;
case 124:
//Windows V5
assert(!"Can't load Windows V5 bitmaps");
break;
default:
assert(!"Unknown bitmap format");
}
//Read the data
int bytesPerRow = ((width * 3 + 3) / 4) * 4 - (width * 3 % 4);
int size = bytesPerRow * height;
auto_array<char> pixels(new char[size]);
input.seekg(dataOffset, ios_base::beg);
input.read(pixels.get(), size);
//Get the data into the right format
auto_array<char> pixels2(new char[width * height * 3]);
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
for(int c = 0; c < 3; c++) {
pixels2[3 * (width * y + x) + c] =
pixels[bytesPerRow * y + 3 * x + (2 - c)];
}
}
}
input.close();
return new Image(pixels2.release(), width, height);
}
imageloader.h
#ifndef IMAGE_LOADER_H_INCLUDED
#define IMAGE_LOADER_H_INCLUDED
//Represents an image
class Image {
public:
Image(char* ps, int w, int h);
~Image();
/* An array of the form (R1, G1, B1, R2, G2, B2, ...) indicating the
* color of each pixel in image. Color components range from 0 to 255.
* The array starts the bottom-left pixel, then moves right to the end
* of the row, then moves up to the next column, and so on. This is the
* format in which OpenGL likes images.
*/
char* pixels;
int width;
int height;
};
//Reads a bitmap image from file.
Image* loadBMP(const char* filename);
#endif
#8
Posted 14 July 2010 - 06:49 PM
You'll have to try to debug it yourself then. Maybe write to a text file or cout to the screen in the load and draw methods of the md2 model file and see if it is reading the information correctly. Also, possibly check some more free models that are on the internet, see if they load all right. Good luck on that.
Currently using Blender and Unity.
#9
Posted 04 May 2011 - 03:17 AM
Sigh
This will NOT return the endianness during run-time. This will return the endianness during compile-time. When do people start to realize compilers will optimize tests like this out, to replace with a fixed value? If you want to compile stuff like this, then you should be disabling compiler optimization for the specific code. And even then, this will mostlikely result in machine instructions loading the address pointed to in a machine register, which will still output the same result if you're not careful and endian-aware enough.
Disassembled
Disassembled (optimization turned off)
).
And no, this has nothing to do with the reason for your stuff being flipped..... Hint: bottom-up raster data.
Quote
//Returns whether the system is little-endian
bool littleEndian() {
//The short value 1 has bytes (1, 0) in little-endian and (0, 1) in
//big-endian
short s = 1;
return (((char*)&s)[0]) == 1;
}
This will NOT return the endianness during run-time. This will return the endianness during compile-time. When do people start to realize compilers will optimize tests like this out, to replace with a fixed value? If you want to compile stuff like this, then you should be disabling compiler optimization for the specific code. And even then, this will mostlikely result in machine instructions loading the address pointed to in a machine register, which will still output the same result if you're not careful and endian-aware enough.
Disassembled
PUBLIC _littleEndian ; Function compile flags: /Ogtpy ; File c:\development\dna\source\tests\testconsole\main.c ; COMDAT _littleEndian _TEXT SEGMENT _littleEndian PROC ; COMDAT ; 12 : //The short value 1 has bytes (1, 0) in little-endian and (0, 1) in ; 13 : //big-endian ; 14 : short s = 1; ; 15 : return (((char*)&s)[0]) == 1; mov eax, 1 ; 16 : } ret 0 _littleEndian ENDP _TEXT ENDS
Disassembled (optimization turned off)
;#pragma optimize( "", off )
PUBLIC _littleEndian
; Function compile flags: /Odtp
; File c:\development\dna\source\tests\testconsole\main.c
; COMDAT _littleEndian
_TEXT SEGMENT
_s$ = -4 ; size = 2
_littleEndian PROC ; COMDAT
; 12 : int littleEndian() {
push ebp
mov ebp, esp
push ecx
; 13 : //The short value 1 has bytes (1, 0) in little-endian and (0, 1) in
; 14 : //big-endian
; 15 : short s = 1;
mov eax, 1
mov WORD PTR _s$[ebp], ax
; 16 : return (((char*)&s)[0]) == 1;
movsx eax, BYTE PTR _s$[ebp]
sub eax, 1
neg eax
sbb eax, eax
add eax, 1
; 17 : }
mov esp, ebp
pop ebp
ret 0
_littleEndian ENDP
_TEXT ENDS
#pragma optimize( "", on )Stop wasting your time writing crappy code, and begin to take a look at your disassembled code every now and then. Debug, test, verify, iterate over all desired platform configurations, and mark done. Especially if you apparantly don't know what you're doing. The compiler is there to serve you, but it will need help doing so correctly. You cannot possibly assume the compiler just 'knows' what you're trying to do all the time. It's the other way around (no pun intended
And no, this has nothing to do with the reason for your stuff being flipped..... Hint: bottom-up raster data.
#10
Posted 05 May 2011 - 02:51 PM
There is nothing wrong with compile-time endianness and optimizing out such functions is action that compiler expected to do. Run-time endianness does not make sense at all (well, theoretically it is possible to make chip with run-time endianness switch, but it is simply waste of chip area). So endianness is constant for every architecture and good compiler optimize such checking correctly then compiling for that architecture.
Sorry my broken english!
1 user(s) are reading this topic
0 members, 1 guests, 0 anonymous users











