⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 modelcanvas.cpp

📁 wowmodelview魔兽世界的模型查看工具。下了看看吧
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#include "modelcanvas.h"
#include "video.h"
#include "animcontrol.h"
#include "gifexporter.h"

float animSpeed = 1.0f;const float piover180 = 0.0174532925f;

IMPLEMENT_CLASS(ModelCanvas, wxGLCanvas)

BEGIN_EVENT_TABLE(ModelCanvas, wxGLCanvas)
    EVT_SIZE(ModelCanvas::OnSize)
    EVT_PAINT(ModelCanvas::OnPaint)
    EVT_ERASE_BACKGROUND(ModelCanvas::OnEraseBackground)
    EVT_MOUSE_EVENTS(ModelCanvas::OnMouse)
	EVT_KEY_DOWN(ModelCanvas::OnKey)

    EVT_TIMER(TIMER_ID, ModelCanvas::OnTimer)
	EVT_IDLE(ModelCanvas::OnIdle)

END_EVENT_TABLE()

#ifdef _WIN32
	// for timeGetTime:
	#pragma comment(lib,"Winmm.lib")

#else // for linux
	#include <sys/time.h>

	//typedef int DWORD;
	int timeGetTime()
	{
		static int start=0;
		static struct timeval t;
		gettimeofday(&t, NULL);
		if (start==0){
			start = t.tv_sec;
		}

		return (int)((t.tv_sec-start)*1000 + t.tv_usec/1000);
	}
#endif

DWORD pauseTime;

ModelCanvas::ModelCanvas(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name, int *attribList, const wxPalette& palette)
    : wxGLCanvas(parent, id, pos, size, style|wxFULL_REPAINT_ON_RESIZE, name, attribList, palette)
{
    init = false;
	
	srand(timeGetTime());

	time = 0;

	timer.SetOwner(this, TIMER_ID);
	timer.Start(TIME_STEP);
	//wxIdleEvent::SetMode(wxIDLE_PROCESS_SPECIFIED);

	fov = 45.0f;
	vRot = Vec3D(0.0f, 0.0f, 0.0f);
	vPos = Vec3D(0.0f, 0.0f, 5.0f);

	// Setup our 'default' lighting values.
	//Vec4D pos(0.8f, 0.2f, 0.5f, 0);
	lPos = Vec4D(-4.371f, 0.2f, 1.0f, 0.0f);
	lDif = Vec4D(1.0f, 1.0f, 1.0f, 1.0f);
	lAmb = Vec4D(0.2f, 0.2f, 0.2f, 0.0f);
	lightType = LT_DIRECTIONAL;

	// Setup our default colour values.
	bgcolor = Vec3D(0.1f, 0.2f, 0.4f);
	ltColor = Vec3D(1.0f, 1.0f, 1.0f);
	baseTrans = Vec3D(0.0f, 0.0f, 0.0f);

	model = 0;
	skyModel = 0;
	wmo = 0;
	animControl = 0;
	viewControl = 0;
	gifExporter = 0;
	modelType = MT_NORMAL;

	drawModel = true;
	drawParticles = true;
	drawMask = false;
	drawBones = false;
	drawBounds = false;
	drawLightDir = false;

	drawBackground = false;
	drawSky = false;
	bMouseLight = false;
	//useLights = true;
	useCamera = false;

	bSaving = false;
	
	root = new Attachment(NULL, NULL, -1, -1);
	sky = new Attachment(NULL, NULL, -1, -1);
}

ModelCanvas::~ModelCanvas()
{
	//clearAttachments();
	delete root;
	delete sky;
}


void ModelCanvas::OnSize(wxSizeEvent& event)
{
	wxGLCanvas::OnSize(event);

	if (init) 
		InitView();
}

void ModelCanvas::SetupProjection(float scale)
{
	glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
	if (scale < 100.0f) {
		// "near" projection
	    gluPerspective(fov, aspect, 0.1f, 256.0f);
	} else {
		// "far" projection
	    gluPerspective(fov, aspect, 1.0f, 1024.0f);
	}
	glMatrixMode(GL_MODELVIEW);
}


void ModelCanvas::InitView()
{
	// set GL viewport
	int w, h;
	GetClientSize(&w, &h);
	SetCurrent();
	glViewport(0, 0, (GLint) w, (GLint) h);

	aspect = (float)w / (float)h;

	gXres = w;
	gYres = h;

	// update projection
	SetupProjection();
}

void ModelCanvas::OnEraseBackground(wxEraseEvent& WXUNUSED(event))
{
	// Do nothing
}

void ModelCanvas::ClearModel()
{
	if (model || wmo || root->model) {
		if (model)
			delete model;

		if (wmo)
			delete wmo;

		clearAttachments();

		model = NULL;
		wmo = NULL;
		root->model = NULL;
	}
}

Attachment* ModelCanvas::LoadModel(const char *fn)
{
	if (root->model != NULL) {
		clearAttachments();
		delete model;		model = NULL;		root->model = NULL;	}	if (wmo != NULL) {
		delete wmo;
		wmo = NULL;	}
	model = new Model(fn, false);
	root->model = model;	
	viewingModel = true;
	baseTrans = Vec3D(0.0f, 0.0f, 0.0f);
	return root;
}

Attachment* ModelCanvas::LoadCharModel(const char *fn)
{
	// Problem!  There seems to be 2 character models. 1 visible, 1 hidden (but there none the less)
	// Why are we doing it this way?  Is it to support mounts?  Just seems excess.
	
	//root->model = 0;
	return LoadModel(fn); //root->addChild(model, 0, -1);

	//ClearModel();
	//return root->addChild(fn, 0, -1);
}

void ModelCanvas::LoadWMO(std::string fn)
{
	if (root->model) 
		delete model;

	clearAttachments();
	model = 0;

	if (wmo) {
		if (wmo->name != fn) {
			delete wmo;
			wmo = 0;
		}
	}
	if (!wmo) {
		wmo = new WMO(fn);
		root->model = wmo;
	}
	viewingModel = false;
}


void ModelCanvas::clearAttachments()
{
	root->delChildren();
}

void ModelCanvas::OnMouse(wxMouseEvent& event)
{
	int px = event.GetX();
	int py = event.GetY();
	int pz = event.GetWheelRotation();

	// mul = multiplier in which to multiply everything to achieve a sense of control over the amount to move stuff by
	float mul = 1.0f;
	if (event.m_shiftDown)
		mul /= 10;
	if (event.m_controlDown)
		mul *= 10;
	if (event.m_altDown)
		mul *= 50;

	mul *= animSpeed;

	if (event.ButtonDown()) {
		mx = px;
		my = py;
		if (bMouseLight) // going to use vRot to hold our temp light position (technically, our lights rotation).
			vRot0 = Vec3D(lPos.x, lPos.y, lPos.z);
		else
			vRot0 = vRot;
		vPos0 = vPos;

	} else if (event.Dragging()) {
		int dx = mx - px;
		int dy = my - py;

		if (event.LeftIsDown()) {
			if (bMouseLight)
				return;

			vRot.x = vRot0.x - ((dy / 2.0f) * mul);
			vRot.y = vRot0.y - ((dx / 2.0f) * mul);

			viewControl->Refresh();

		} else if (event.RightIsDown()) {
			mul /= 100.0f;

			if (bMouseLight) {
				lPos.y = vRot0.y + dy*mul;
				lPos.x = vRot0.x - dx*mul;
			} else {
				vPos.x = vPos0.x - dx*mul;
				vPos.y = vPos0.y + dy*mul;

				viewControl->Refresh();
			}

		} else if (event.MiddleIsDown()) {
			if (!event.m_altDown) {
				mul = (mul / 20.0f) * dy;

				if (bMouseLight)
					lPos.z = vRot0.z - mul;
				else {
					Zoom(mul, false);
					my = py;
				}

			} else {
				mul = (mul / 1200.0f) * dy;
				Zoom(mul, true);
				my = py;
			}
		}

	} else if (event.GetEventType() == wxEVT_MOUSEWHEEL) {
		if (pz != 0) {
			mul = (mul / 120.0f) * pz;
			if (!wxGetKeyState(WXK_ALT)) {
				if (bMouseLight)
					lPos.z -= mul / 120.0f;
				else
					Zoom(mul, false);

			} else {
				mul /= 50.0f;
				Zoom(mul, true);
			}
		}
	} else if (event.GetEventType() == wxEVT_ENTER_WINDOW) {
		SetFocus();
	}
}

void ModelCanvas::InitGL()
{
	// init stuff
	InitExtensions();
	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_NORMAL_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);

	/*
	if(supportAntiAlias)
		glEnable(GL_MULTISAMPLE_ARB);
	*/
	glShadeModel(GL_SMOOTH);
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

	glPixelStorei(GL_PACK_ALIGNMENT, 1);
	glPixelStorei(GL_PACK_SWAP_BYTES, false);
	glPixelStorei(GL_PACK_LSB_FIRST, false);

	InitView();
	init = true;
	//drawBackground = false;
}

void ModelCanvas::OnPaint(wxPaintEvent& WXUNUSED(event))
{
	if (!init)
		InitGL();
// TODO: Fix for Linux//#ifdef _WIN32
//	CheckKeyInput();//#endif

	wxPaintDC dc(this);
	Render();

	if (bSaving == true) {
		gifExporter->SaveFrame();
		model->animManager->SetTimeDiff(gifExporter->TimeStep);
		model->animManager->Tick(gifExporter->TimeStep);
	}
}

inline void ModelCanvas::Render()
{
	//SetCurrent();

	glClearColor(bgcolor.x, bgcolor.y, bgcolor.z, 0.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// Ortho view, best way to understand it is to think of it as
	// being similar to DirectDraw
	// Draw the background image if any
	if(drawBackground && !drawMask)
	{
		glPushMatrix();

		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();

		glMatrixMode(GL_MODELVIEW);					// Select The Modelview Matrix
		glLoadIdentity();

		glOrtho(0, gXres, 0, gYres, -1, 1);
		glEnable(GL_TEXTURE_2D);				// Enable 2D Texture Mapping
		glDisable(GL_DEPTH_TEST);
		
		glBindTexture(GL_TEXTURE_2D, bgTexture);
		glBegin(GL_QUADS);
			glTexCoord2f(0.0f, 0.0f); glVertex2i(0, 0);
			glTexCoord2f(1.0f, 0.0f); glVertex2i(gXres, 0);
			glTexCoord2f(1.0f, 1.0f); glVertex2i(gXres, gYres);
			glTexCoord2f(0.0f, 1.0f); glVertex2i(0,  gYres);
		glEnd();

		glPopMatrix();								// Restore The Old Modelview Matrix
	}

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	//if (root->model) {
		if (model) 
			model->animcalc = false;		
		
		// All our lighting related rendering code
		bool lit = false;
		Vec4D la;

		// Use model lighting?
		if (model && (lightType == LT_MODEL_ONLY)) {
			if (model->header.nLights > 0) {
				la = Vec4D(0.0f, 0.0f, 0.0f, 1.0f);
				lit = true;
			} else {
				la = Vec4D(1.0f, 1.0f, 1.0f, 1.0f);
			}
		} else {
			la = Vec4D(0.5f, 0.5f, 0.5f, 1.0f);
		}

		glLightModelfv(GL_LIGHT_MODEL_AMBIENT, la);

		glEnable(GL_COLOR_MATERIAL);
		glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
		glColor4f(ltColor.x, ltColor.y, ltColor.z, 1.0f);

		// Why are we using all 8 lights?  
		// In fact, why are we setting all these settings then disabling the light?
		for (int i=0; i<8; i++) {
			GLuint light = GL_LIGHT0 + i;
			//GLuint light = GL_LIGHT4;
			glLightf(light, GL_CONSTANT_ATTENUATION, 0.0f);
			glLightf(light, GL_LINEAR_ATTENUATION, 0.7f);
			glLightf(light, GL_QUADRATIC_ATTENUATION, 0.03f);
			//glDisable(light);
		}

		if (!lit) {
			if (lightType == LT_DIRECTIONAL) {
				glLightfv(GL_LIGHT0, GL_POSITION, lPos);
				//glLightfv(GL_LIGHT0, GL_DIFFUSE, lDif);
				glLightfv(GL_LIGHT0, GL_DIFFUSE, ltColor);

				lAmb = Vec4D(ltColor.x / 5, ltColor.y / 5, ltColor.z / 5, 0.0f); // To keep the ambience lighting in the correct proportion.
				glLightfv(GL_LIGHT0, GL_AMBIENT, lAmb);

				glEnable(GL_LIGHT0);
			} else if (lightType==LT_AMBIENT) {
				glLightModelfv(GL_LIGHT_MODEL_AMBIENT, Vec4D(ltColor.x, ltColor.y, ltColor.z, 1.0f));
			}
		}

		// render the skybox, if any
		if (drawSky && skyModel && sky->model) {
			glPushMatrix();
			
			float fScale = 100.0f / skyModel->rad;
			
			glTranslatef(0.0f, 0.0f, -5.0f);
			glScalef(fScale, fScale, fScale);
			sky->draw(this);

			glPopMatrix();
		}

		// setup the view/projection
		if (model && useCamera && model->hasCamera) {
			model->cam.setup();
		} else {

			// update projection
			SetupProjection(modelsize);

			// update view

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -