Jump to content


MD2 Loader


9 replies to this topic

#1 VitaliBR

    New Member

  • Members
  • Pip
  • 5 posts

Posted 13 July 2010 - 05:47 PM

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?

#2 fireside

    Senior Member

  • Members
  • PipPipPipPip
  • 1588 posts

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 VitaliBR

    New Member

  • Members
  • Pip
  • 5 posts

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

#4 fireside

    Senior Member

  • Members
  • PipPipPipPip
  • 1588 posts

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
Currently using Blender and Unity.

#5 VitaliBR

    New Member

  • Members
  • Pip
  • 5 posts

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

#6 VitaliBR

    New Member

  • Members
  • Pip
  • 5 posts

Posted 14 July 2010 - 01:42 PM

md2model.h
#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 VitaliBR

    New Member

  • Members
  • Pip
  • 5 posts

Posted 14 July 2010 - 01:42 PM

vec3f.cpp
#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 fireside

    Senior Member

  • Members
  • PipPipPipPip
  • 1588 posts

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 Coriiander

    New Member

  • Members
  • Pip
  • 2 posts

Posted 04 May 2011 - 03:17 AM

Sigh

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 }:+()___ (Smile)

    Member

  • Members
  • PipPipPip
  • 169 posts

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