Original Post
Hello all, I hope you're doing fine :) Because I am having a small problem ;) First, my normalization code wasn't working correctly. For anyone interested I posted some new code that DOES work. Now, my true problem is that cel shading isn't working exactly. Read below for further details. md2object.cpp Any information, tip, etc would be nice :)! Thank you. [Edited by - PinguinDude on April 9, 2007 2:54:33 PM]
/* ==== md2object.cpp ========================================================
* Copyright (c) 2007, Led Engine Project.
* All rights reserved.
* ===========================================================================
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* == Description ============================================================
* The Engine singleton class. Wraps around all subsystems in 1 single class.
*/
/* == Notes ==================================================================
* SubRender is the actual render function, it is used to allow special effects.
*/
// System headers.
#include <windows.h>
#include <gl/gl.h>
#include <gl/glut.h>
// Engine headers.
#include "common.h"
#include "system.h"
using namespace Led::System;
using namespace Led::Math;
/// Constructor. Initializes the object class.
MD2Object::MD2Object()
{
// Make sure the texture is NULL.
gltexture = NULL;
glshader = NULL;
}
/// Destructor. Destroys the object class.
MD2Object::~MD2Object()
{
}
/// Load. Loads the model.
/// @param string filename the path to the file.
int MD2Object::Load(std::string filename)
{
std::string imagefile;
snorm *norms = NULL;
FILE *file = fopen(filename.c_str(), "rb");
// Couldn't find the model file.
if (!file)
{
engine->GetLogger()->Log(Led::System::error, std::string("Couldn't load md2 model:") + filename);
return 0; // Error.
}
// Read in the header and check if the file version corresponds to the one we want to load.
fread(&header, sizeof(md2_header_t), 1, file);
if ((header.ident != 844121161) || (header.version != 8))
{
engine->GetLogger()->Log(Led::System::error, std::string("MD2 File version is incorrect: ") + filename);
// Stop reading the file.
fclose(file);
return 0; // Error.
}
// Allocate memory.
skins = new md2_skin_t[header.num_skins];
texcoords = new md2_texcoord_t[header.num_st];
triangles = new md2_triangle_t[header.num_tris];
frames = new md2_frame_t[header.num_frames];
glcommands = new int[header.num_glcmds];
// Read in model data.
fseek(file, header.offset_skin, SEEK_SET);
fread(skins, header.num_skins, sizeof(md2_skin_t), file);
fseek(file, header.offset_st, SEEK_SET);
fread(texcoords, header.num_st, sizeof(md2_texcoord_t), file);
fseek(file, header.offset_tris, SEEK_SET);
fread(triangles, header.num_tris, sizeof(md2_triangle_t), file);
fseek(file, header.offset_glcmds, SEEK_SET);
fread(glcommands, header.num_skins, sizeof(int), file);
// Read in frames.
fseek(file, header.offset_frames, SEEK_SET);
for (int i = 0; i < header.num_frames; i++)
{
// Allocate vertices.
frames.verts = new md2_vertex_t[header.num_vertices];
// Allocate normals.
frames.normals = new vec3_t[header.num_tris];
// Read in data.
fread(frames.scale, 1, sizeof(vec3_t), file);
fread(frames.translate, 1, sizeof(vec3_t), file);
fread(frames.name, 16, sizeof(char), file);
fread(frames.verts, header.num_vertices, sizeof (md2_vertex_t), file);
}
// Close the file, we're done reading.
fclose(file);
/*
Normal calculation. The most messy and complicated part of it all.
*/
for (int i = 0; i < header.num_frames; i++)
{
norms = new snorm[header.num_vertices];
for (int j = 0; j < header.num_tris; j++)
{
md2_vertex_t *vertex1 = &frames[0].verts[triangles[j].vertex[0]];
md2_vertex_t *vertex2 = &frames[0].verts[triangles[j].vertex[1]];
md2_vertex_t *vertex3 = &frames[0].verts[triangles[j].vertex[2]];
Vector p1 = Vector(vertex1->v[0], vertex1->v[1], vertex1->v[2], 1);
Vector p2 = Vector(vertex2->v[0], vertex2->v[1], vertex2->v[2], 1);
Vector p3 = Vector(vertex3->v[0], vertex3->v[1], vertex3->v[2], 1);
Vector v1 = p1 - p2;
Vector v2 = p1 - p3;
Vector normal = v1.CrossProduct(v2);
normal.Normalize();
norms[triangles[j].vertex[0]].sum_normals = normal;
norms[triangles[j].vertex[0]].normals ++;
norms[triangles[j].vertex[1]].sum_normals = normal;
norms[triangles[j].vertex[1]].normals ++;
norms[triangles[j].vertex[2]].sum_normals = normal;
norms[triangles[j].vertex[2]].normals ++;
}
for (int k = 0; k < header.num_vertices; k++)
{
frames.normals[0] = norms[k].sum_normals.GetX() / norms[k].normals;
frames.normals[1] = norms[k].sum_normals.GetY() / norms[k].normals;
frames.normals[2] = norms[k].sum_normals.GetZ() / norms[k].normals;
}
// Not required anymore.
delete norms;
}
return 1;
}
/// Update. Updates the object ( Animations etc. )
int MD2Object::Update()
{
frametime_t *timer = engine->GetTimer();
float curtime = timer->curframe * 0.01f;
// Did the interpolation for this frame finish ?
if (curtime - oldtime > (1.0f / fps))
{
// Move on to the next frame.
curframe = nextframe;
nextframe++;
// Reset for smooth animation.
if (nextframe > endframe)
nextframe = startframe;
// Store the last time.
oldtime = curtime;
}
// Make sure we don't go out of bounds.
if (curframe > header.num_frames - 1)
curframe = 0;
if (nextframe > header.num_frames - 1)
nextframe = 0;
// Calculate interpolation value.
interp = fps * (curtime - oldtime);
return 0;
}
/// Render. Renders the object.
int MD2Object::Render()
{
if (curframe < 0 || curframe > header.num_frames - 1)
return 0; // Bad frame.
if (!gltexture)
return 0; // No valid texture. Stop rendering.
// Start rendering.
glPushMatrix();
// Position.
glTranslatef(position.GetX(), position.GetY(), position.GetZ());
glRotatef(rotation.GetX() - -90.0f, 1, 0, 0);
glRotatef(rotation.GetY() - 180, 0, 1, 0);
glRotatef(rotation.GetZ() - -90.0f, 0, 0, 1);
// Bind the texture.
gltexture->BindTexture();
// Check for effects.
switch(gleffect)
{
case effect_outline:
// Push the GL attribute bits so that we don't wreck any settings
glPushAttrib( GL_ALL_ATTRIB_BITS );
// Enable polygon offsets, and offset filled polygons forward by 2.5
glEnable( GL_POLYGON_OFFSET_FILL );
glPolygonOffset( -2.5f, -2.5f );
// Set the render mode to be line rendering with a thick line width
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
glLineWidth( 4.0f );
// Set the colour to be white
glColor3f( 0.0f, 0.0f, 0.0f );
SubRender();
// Set the polygon mode to be filled triangles
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
//glEnable( GL_LIGHTING );
// Set the colour to the background
glColor3f( 1.0f, 1.0f, 1.0f );
break;
default:
break;
}
// Enable a shader if we have one.
if (glshader)
glshader->Bind();
SubRender();
// Pop the state changes off the attribute stack
// to set things back how they were
glPopAttrib();
if (glshader)
glshader->UnBind();
gltexture->UnBindTexture();
// Done rendering.
glPopMatrix();
return 1;
}
/// SubRender. TRUELY Render the model.
int MD2Object::SubRender()
{
GLfloat s, t;
vec3_t v, v_current, v_next, n, n_current, n_next, *normals, *normals_next;
md2_frame_t *frame;
md2_frame_t *frame_next;
md2_vertex_t *vertex;
md2_vertex_t *vertex_next;
glBegin(GL_TRIANGLES);
for (int i = 0; i < header.num_tris; ++i)
{
for (int j = 0; j < 3; ++j)
{
// Get the pointers.
frame = &frames[curframe];
frame_next = &frames[nextframe];
vertex = &frame->verts[triangles.vertex[j]];
vertex_next = &frame_next->verts[triangles.vertex[j]];
// Catch normals.
normals = &frames[0].normals[triangles.vertex[j]];
normals_next = &frame_next->normals[triangles.vertex[j]];
// Calculate texture coordinates.
s = (GLfloat)texcoords[triangles.st[j]].s / header.skinwidth;
t = (GLfloat)texcoords[triangles.st[j]].t / header.skinheight;
// Render the model.
glTexCoord2f(s, t);
// Interpolate normals.
/* n_current[0] = frame->scale[0] * *normals[0] + frame->translate[0];
n_current[1] = frame->scale[1] * *normals[1] + frame->translate[1];
n_current[2] = frame->scale[2] * *normals[2] + frame->translate[2];
n_next[0] = frame_next->scale[0] * *normals_next[0] + frame_next->translate[0];
n_next[1] = frame_next->scale[1] * *normals_next[1] + frame_next->translate[1];
n_next[2] = frame_next->scale[2] * *normals_next[2] + frame_next->translate[2];
n[0] = n_current[0] + interp * (n_next[0] - n_current[0]);
n[1] = n_current[1] + interp * (n_next[1] - n_current[1]);
n[2] = n_current[2] + interp * (n_next[2] - n_current[2]);*/
// Interpolate vertices.
v_current[0] = frame->scale[0] * vertex->v[0] + frame->translate[0];
v_current[1] = frame->scale[1] * vertex->v[1] + frame->translate[1];
v_current[2] = frame->scale[2] * vertex->v[2] + frame->translate[2];
v_next[0] = frame_next->scale[0] * vertex_next->v[0] + frame_next->translate[0];
v_next[1] = frame_next->scale[1] * vertex_next->v[1] + frame_next->translate[1];
v_next[2] = frame_next->scale[2] * vertex_next->v[2] + frame_next->translate[2];
v[0] = v_current[0] + interp * (v_next[0] - v_current[0]);
v[1] = v_current[1] + interp * (v_next[1] - v_current[1]);
v[2] = v_current[2] + interp * (v_next[2] - v_current[2]);
glNormal3fv(*normals);
glVertex3fv(v);
}
}
glEnd();
return 0;
}
/// Destroy. Destroys the object.
int MD2Object::Destroy()
{
if (gltexture)
{
gltexture->Destroy();
delete gltexture;
gltexture = NULL;
}
delete skins;
delete texcoords;
delete triangles;
delete frames->normals;
delete frames->verts;
delete frames;
delete glcommands;
return 0;
}
/// SetAnimation. Sets the animation frames.
/// @param int start the starting frame.
/// @param int end the ending frame.
/// @param float fps the frames per second.
int MD2Object::SetAnimation(int start, int end, float framefps)
{
nextframe = start;
startframe = start;
endframe = end;
fps = framefps;
return 0;
}
/// SetTexture. Sets the texture of the object.
/// @param Texture2D texture a pointer to the texture object.
int MD2Object::SetTexture(Texture2D *texture)
{
gltexture = texture;
return 0;
}
/// SetEffect. Allows you to specify a model effect, outlining etc.
/// @param int effect the effect.
int MD2Object::SetEffect(int effect)
{
gleffect = effect;
return 0;
}
/// SetShader. Sets the current shader of the object.
/// @param BaseShader shader a pointer to the shader object.
int MD2Object::SetShader(BaseShader *shader)
{
glshader = shader;
return 0;
}
/// SetPosition. Sets the position of the object in the scene.
/// @param vector vector determines the position.
int MD2Object::SetPosition(Led::Math::Vector &vector)
{
position = vector;
return 0;
}
// SetRotation. Sets the rotation of the object in the scene.
/// @param vector vector determines the position.
int MD2Object::SetRotation(Led::Math::Vector &vector)
{
rotation = vector;
return 0;
}
/// GetPosition. Returns a reference to the object's position.
const Vector &MD2Object::GetPosition() const
{
return position;
}
/// GetRotation. Returns a reference to the object's rotation.
const Vector &MD2Object::GetRotation() const
{
return rotation;
}