MD2, Lighting, Normalizing.

Started by
4 comments, last by PinguinDude 17 years ago
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

/* ==== 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;
}

Any information, tip, etc would be nice :)! Thank you. [Edited by - PinguinDude on April 9, 2007 2:54:33 PM]
http://sourceforge.net/projects/pingux/ <-- you know you wanna see my 2D Engine which supports DirectX and OpenGL or insert your renderer here :)
Advertisement
Though it may not be of any help, this is my code, it seems to work.
typedef struct avector{   float x,y,z,nx,ny,nz;} avector;typedef struct animframe{   avector * vers;   char name[16];} animframe;typedef struct poly{   short verindex[3];   short texindex[3];} poly;typedef struct anim{   int numframes;   int numvers;   int numpolys;   poly *polys;   uv *uvs;   animframe *frames;} anim;typedef unsigned char md2vertex[3];typedef struct md2point{   unsigned char triple[3];   unsigned char lightindexnormal;} md2point;typedef struct md2texcoord{   short u;   short v;} md2texcoord;typedef struct md2frame{   float scale[3];   float trans[3];   char name[16];   md2point vers[1];} md2frame;typedef struct md2header{   int id;   int version;   int texw;   int texh;   int framesize;   int numskins;   int numvers;   int numtex;   int numpolys;   int numcmds;   int numframes;   int skinoffset;   int texcoordoffset;   int polyoffset;   int frameoffset;   int cmdoffset;   int endoffset;} md2header; void normalize(avector * v){   float d=(float)sqrt(v->nx*v->nx+v->ny*v->ny+v->nz*v->nz);   if(d!=0){      v->nx/=d;      v->ny/=d;      v->nz/=d;   }}int loadanim(anim * a, char * filename){   md2header header;   md2frame * frame;   char * buffer;   FILE *file=NULL;   if(!(file=fopen(filename,"rb"))){      return(1);   }   fread(&header,sizeof(md2header),1,file);   a->numframes=header.numframes;//set the num of frAMES in the a to the num loaded   a->numvers=header.numvers;   a->numpolys=header.numpolys;   a->frames=(animframe *)malloc(sizeof(animframe)*header.numframes);   buffer=(char *)malloc(header.numframes*header.framesize);   fseek(file,header.frameoffset,SEEK_SET);   fread(buffer,header.framesize,header.numframes,file);   for(int indexf=0;indexf<header.numframes;indexf++){      a->frames[indexf].vers=(avector *)malloc(sizeof(avector)*header.numvers);      frame=(md2frame *)&buffer[header.framesize*indexf];      strcpy(a->frames[indexf].name,frame->name);      for(int indexv=0;indexv<header.numvers;indexv++){         a->frames[indexf].vers[indexv].x=(((float)frame->vers[indexv].triple[0]*frame->scale[0])+frame->trans[0]);         a->frames[indexf].vers[indexv].z=(((float)frame->vers[indexv].triple[1]*frame->scale[1])+frame->trans[1]);         a->frames[indexf].vers[indexv].y=(((float)frame->vers[indexv].triple[2]*frame->scale[2])+frame->trans[2]);      }   }   if(buffer){      free(buffer);   }   char str[1000];   a->uvs=(uv *)malloc(sizeof(uv)*header.numtex);   short uvcoord=0;   fseek(file,header.texcoordoffset,SEEK_SET);   for(int index=0;index<header.numtex;index++){      fread(&uvcoord,sizeof(short),1,file);      a->uvs[index].u=(float)uvcoord/(float)header.texw;      fread(&uvcoord,sizeof(short),1,file);      a->uvs[index].v=-1.0f*((float)uvcoord/(float)header.texh);   }   a->polys=(poly *)malloc(sizeof(poly)*header.numpolys);   fseek(file,header.polyoffset,SEEK_SET);   for(int indexp=0;indexp<header.numpolys;indexp++){      fread(&(a->polys[indexp]),sizeof(poly),1,file);   }   //fread(&(a->polys),sizeof(poly)*header.numpolys,1,file);   fclose(file);   for(int findex=0;findex<a->numframes;findex++){      for(int vindex=0;vindex<a->numvers;vindex++){         a->frames[findex].vers[vindex].nx=0;                 a->frames[findex].vers[vindex].ny=0;         a->frames[findex].vers[vindex].nz=0;      }      for(int tindex=0;tindex<a->numpolys;tindex++){         float nchunk[3];         normalchunk(a,tindex,findex,nchunk);         for(int temp=0;temp<3;temp++){            a->frames[findex].vers[a->polys[tindex].verindex[temp]].nx-=nchunk[0];            a->frames[findex].vers[a->polys[tindex].verindex[temp]].ny+=nchunk[2];            a->frames[findex].vers[a->polys[tindex].verindex[temp]].nz-=nchunk[1];            /*a->frames[findex].vers[a->polys[tindex].verindex[temp]].nx+=nchunk[0];            a->frames[findex].vers[a->polys[tindex].verindex[temp]].ny+=nchunk[1];            a->frames[findex].vers[a->polys[tindex].verindex[temp]].nz+=nchunk[2];*/               }      }      for(int vindex=0;vindex<a->numvers;vindex++)         normalize(&(a->frames[findex].vers[vindex]));           }   return(0);}


[Edited by - Th0ughtCr1me on April 7, 2007 8:14:10 PM]
_______________ Play my Game at neonswarm.com
Thanks, but it isn't really helping me figure out what's wrong at all.
http://sourceforge.net/projects/pingux/ <-- you know you wanna see my 2D Engine which supports DirectX and OpenGL or insert your renderer here :)
Anyone ? I'm really desperate. I found several tutorials and no matter what I try I keep failing on succeeding to add it in.
http://sourceforge.net/projects/pingux/ <-- you know you wanna see my 2D Engine which supports DirectX and OpenGL or insert your renderer here :)
Vector v1 = p2 - p1;
Vector v2 = p3 - p1;

Try this

Vector v1 = p1 - p2;
Vector v2 = p2 - p3;

and I don't see any code for the normalize() or cross product. I am not sure what those look like either....
Well, I managed to fix the normalization code after 1000 retries. I'll upload the new code. So, another problem pops up. I am trying to write a cel shader. It however doesn't seem to work exactly well ( I am very new to glsl ).

celshader.cpp
/* ==== baseobject.h ========================================================= * Copyright (c) 2007, Plastic 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 ============================================================ * CelShader. Cell Shades the currently rendered object. *//* == Notes ================================================================== * */// System headers#include <windows.h>#include <sdl/sdl.h>#include <gl/glew.h>#include <gl/gl.h>// Engine headers#include "common.h"#include "system.h"using namespace Led::System;using namespace Led::Math;/// CelShader. Constructor.CelShader::CelShader(){}/// Load. Loads the shader, and calls compile./// @param string filename the path to the file.int CelShader::Load(std::string filename){	std::string s_frag_file = filename + ".frag";	std::string s_vert_file = filename + ".vert";	// Load in the fragment shader string.	std::ifstream frag_file(s_frag_file.c_str());	if (frag_file.is_open())	{		while (!frag_file.eof())		{			std::string line;			getline(frag_file, line);			s_fragment += line;		}	}	frag_file.close();	// Load in vertex shader string.	std::ifstream vert_file(s_vert_file.c_str());	if (vert_file.is_open())	{		while (!vert_file.eof())		{			std::string line;			getline(vert_file, line);			s_vertex += line;		}	}	vert_file.close();	// Compile !.	Compile();	return 0;}/// Compile. Compiles the shader.int CelShader::Compile(){	const char *c_vertex = s_vertex.c_str();	GLint c_vertex_len = s_vertex.length();	const char *c_fragment = s_fragment.c_str();	GLint c_fragment_len = s_fragment.length();	GLint retval = GL_TRUE;	// Create the shader.	glsl_vertex = glCreateShader(GL_VERTEX_SHADER);	glsl_fragment = glCreateShader(GL_FRAGMENT_SHADER);		// Assign data.	glShaderSource(glsl_vertex, 1, &c_vertex, &c_vertex_len);	// Compile the shader.	glCompileShader(glsl_vertex);	//	// test for errors here.	//	glGetShaderiv(glsl_vertex, GL_COMPILE_STATUS, &retval);	if (retval != GL_TRUE)	{		engine->GetLogger()->Log(System::message, "Couldn't compile VertexShader: CelShader");		engine->GetLogger()->Log(System::message, s_vertex);	}	// Assign data.	glShaderSource(glsl_fragment, 1, &c_fragment, &c_fragment_len);	// Compile the shader.	glCompileShader(glsl_fragment);	//	// test for errors here.	//	glGetShaderiv(glsl_fragment, GL_COMPILE_STATUS, &retval);	if (retval != GL_TRUE)	{		engine->GetLogger()->Log(System::message, "Couldn't compile FragmentShader: CelShader");		engine->GetLogger()->Log(System::message, s_fragment);	}	// Create the program.	glsl_program = glCreateProgram();	// Link shaders into the program.	glAttachShader(glsl_program, glsl_vertex);	glAttachShader(glsl_program, glsl_fragment);	// Link the program.	glLinkProgram(glsl_program);	// Create a 1D toon texture.	float pixels[16] = {0.4f, 0.4f, 0.4f, 0.4f, 0.5f, 0.5f, 0.5f, 0.5f, 0.7f, 0.7f, 0.7f, 0.8f, 0.9f, 1.0f, 1.0f, 1.0f};	//float pixels[16] = {1.0f, 1.0f, 1.0f, 1.0f, 0.9f, 0.8f, 0.8f, 0.7f, 0.7f, 0.5f, 0.5f, 0.4f, 0.4f, 0.4f, 0.4f, 0.4f};	glGenTextures(1, (GLuint*)&tex[0]);	glBindTexture(GL_TEXTURE_1D, tex[0]);	glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);	glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);	glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);	glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 16, 0, GL_LUMINANCE, GL_FLOAT, pixels);	return 0;}/// Set functions./// @param Vector vector the new value./// @param string name the name of the var.int CelShader::SetVector3(Vector vector, std::string name){	int var = glGetUniformLocation(glsl_program, name.c_str());	glUniform3f(var, vector.GetX(), vector.GetY(), vector.GetZ());	return 0;}int CelShader::SetVector4(Vector vector, std::string name){	int var = glGetUniformLocation(glsl_program, name.c_str());	glUniform4f(var, vector.GetX(), vector.GetY(), vector.GetZ(), vector.GetW());	return 0;}/// Bind. Activates the current shader.int CelShader::Bind(){	int celtexture = 0;	int realtexture = 0;	// Use our shader.	glUseProgram(glsl_program);	// Retrieve texture acces.	celtexture = glGetUniformLocation(glsl_program, "celtex");	realtexture = glGetUniformLocation(glsl_program, "realtex");	// Tell it that the cell shade texture is on layer 2, normal texture on layer 1.	glActiveTexture(GL_TEXTURE1);	glUniform1i(celtexture, 1);	glBindTexture(GL_TEXTURE_1D, tex[0]);	glActiveTexture(GL_TEXTURE0);	glUniform1i(realtexture, 0);	return 0;}/// UnBind. UnBinds the shader.int CelShader::UnBind(){	glUseProgram(0);	glActiveTexture(GL_TEXTURE0);	glBindTexture(GL_TEXTURE_1D, 0);	glActiveTexture(GL_TEXTURE1);	glBindTexture(GL_TEXTURE_2D, 0);	return 0;}


cel.vert
varying vec3 lightdir, normal;uniform sampler1D celtex;uniform sampler2D realtex;void main(){	normal = gl_NormalMatrix * gl_Normal;		gl_TexCoord[0] = gl_MultiTexCoord0;	gl_Position = ftransform();}


cel.frag
varying vec3 lightdir, normal;uniform sampler1D celtex;uniform sampler2D realtex;void main(){	vec3 n = normalize(normal);	int light = dot(vec3(normalize(lightdir)),n) * 15;	gl_FragColor = texture2D(realtex, gl_TexCoord[0].st) * texture1D(celtex, gl_TexCoord[0].st + light);	}


And the result,
http://sourceforge.net/projects/pingux/ <-- you know you wanna see my 2D Engine which supports DirectX and OpenGL or insert your renderer here :)

This topic is closed to new replies.

Advertisement