📄 modelcanvas.cpp
字号:
#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 + -