#include "precompiled.h" #include "MathUtil.h" #include "EditorData.h" #include "ui/UIGlobals.h" #include "ToolManager.h" #include "ObjectManager.h" #include "UnitManager.h" #include "TextureManager.h" #include "TextureEntry.h" #include "Model.h" #include "SkeletonAnimManager.h" #include "Unit.h" #include "ogl.h" #include "lib/res/graphics/tex.h" #include "time.h" #include "BaseEntityCollection.h" #include "Entity.h" #include "EntityHandles.h" #include "EntityManager.h" #include "ConfigDB.h" #include "Scheduler.h" #include "Loader.h" #include "XML/XML.h" #include "Game.h" #include "GameAttributes.h" const int NUM_ALPHA_MAPS = 14; Handle AlphaMaps[NUM_ALPHA_MAPS]; extern CLightEnv g_LightEnv; CMiniMap g_MiniMap; CEditorData g_EditorData; CEditorData::CEditorData() { m_ModelMatrix.SetIdentity(); m_ScenarioName="Scenario01"; } void CEditorData::SetMode(EditMode mode) { if (m_Mode==TEST_MODE && mode!=TEST_MODE) StopTestMode(); m_Mode=mode; if (m_Mode==TEST_MODE) StartTestMode(); } bool CEditorData::InitScene() { // setup default lighting environment g_LightEnv.m_SunColor=RGBColor(1,1,1); g_LightEnv.m_Rotation=DEGTORAD(270); g_LightEnv.m_Elevation=DEGTORAD(45); g_LightEnv.m_TerrainAmbientColor=RGBColor(0,0,0); g_LightEnv.m_UnitsAmbientColor=RGBColor(0.4f,0.4f,0.4f); g_Renderer.SetLightEnv(&g_LightEnv); // load the default if (!LoadTerrain("temp/terrain.png")) return false; // get default texture to apply to terrain CTextureEntry* texture=g_TexMan.FindTexture("aaa.dds"); CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); // cover entire terrain with default texture u32 patchesPerSide=terrain->GetPatchesPerSide(); for (uint pj=0; pjGetPatch(pi,pj); for (int j=0;jm_MiniPatches[j][i].Tex1=texture ? texture->GetHandle() : 0; } } } } // setup camera InitCamera(); // build the terrain plane float h=128*HEIGHT_SCALE; u32 mapSize=terrain->GetVerticesPerSide(); CVector3D pt0(0,h,0),pt1(float(CELL_SIZE*mapSize),h,0),pt2(0,h,float(CELL_SIZE*mapSize)); m_TerrainPlane.Set(pt0,pt1,pt2); m_TerrainPlane.Normalize(); return true; } struct TGAHeader { // header stuff unsigned char iif_size; unsigned char cmap_type; unsigned char image_type; unsigned char pad[5]; // origin : unused unsigned short d_x_origin; unsigned short d_y_origin; // dimensions unsigned short width; unsigned short height; // bits per pixel : 16, 24 or 32 unsigned char bpp; // image descriptor : Bits 3-0: size of alpha channel // Bit 4: must be 0 (reserved) // Bit 5: should be 0 (origin) // Bits 6-7: should be 0 (interleaving) unsigned char image_descriptor; }; static bool saveTGA(const char* filename,int width,int height,unsigned char* data) { FILE* fp=fopen(filename,"wb"); if (!fp) return false; // fill file header TGAHeader header; header.iif_size=0; header.cmap_type=0; header.image_type=2; memset(header.pad,0,sizeof(header.pad)); header.d_x_origin=0; header.d_y_origin=0; header.width=width; header.height=height; header.bpp=24; header.image_descriptor=0; if (fwrite(&header,sizeof(TGAHeader),1,fp)!=1) { fclose(fp); return false; } // write data if (fwrite(data,width*height*3,1,fp)!=1) { fclose(fp); return false; } // return success .. fclose(fp); return true; } ///////////////////////////////////////////////////////////////////////////////////////////////// // Init: perform one time initialisation of the editor bool CEditorData::Init() { // Set attributes for the game g_GameAttributes.m_MapFile = L""; // start without a map for (int i=1; i<8; ++i) g_GameAttributes.GetSlot(i)->AssignLocal(); // Set up the actual game g_Game = new CGame(); PSRETURN ret = g_Game->StartGame(&g_GameAttributes); if (ret != PSRETURN_OK) { // Failed to start the game delete g_Game; g_Game = NULL; return false; } LDR_NonprogressiveLoad(); // create the scene - terrain, camera, light environment etc if (!InitScene()) return false; // set up an empty minimap g_MiniMap.Initialise(); // set up the info box m_InfoBox.Initialise(); return true; } ///////////////////////////////////////////////////////////////////////////////////////////////// // Terminate: close down the editor (destroy singletons in reverse order to construction) void CEditorData::Terminate() { } void CEditorData::InitCamera() { g_NaviCam.GetCamera().SetProjection(1.0f,10000.0f,DEGTORAD(90)); g_NaviCam.GetCamera().m_Orientation.SetIdentity(); #ifdef TOPDOWNVIEW g_NaviCam.GetCamera().m_Orientation.RotateX(DEGTORAD(90)); g_NaviCam.GetCamera().m_Orientation.Translate(CELL_SIZE*250*0.5, 80, CELL_SIZE*250*0.5); #else g_NaviCam.GetCamera().m_Orientation.RotateX(DEGTORAD(40)); g_NaviCam.GetCamera().m_Orientation.RotateY(DEGTORAD(-45)); g_NaviCam.GetCamera().m_Orientation.Translate(600, 200, 125); #endif OnCameraChanged(); } void CEditorData::OnCameraChanged() { int width=g_Renderer.GetWidth(); int height=g_Renderer.GetHeight(); // resize viewport SViewPort viewport; viewport.m_X=0; viewport.m_Y=0; viewport.m_Width=width; viewport.m_Height=height; g_NaviCam.GetCamera().SetViewPort(&viewport); // rebuild object camera m_ObjectCamera.SetViewPort(&viewport); m_ObjectCamera.SetProjection(1.0f,10000.0f,DEGTORAD(90)); // recalculate projection matrix g_NaviCam.GetCamera().SetProjection(1.0f,10000.0f,DEGTORAD(20)); // update viewing frustum g_NaviCam.GetCamera().UpdateFrustum(); // calculate intersection of camera stabbing lines with terrain plane // get points of back plane of frustum in camera space float aspect=height>0 ? float(width)/float(height) : 1.0f; float zfar=g_NaviCam.GetCamera().GetFarPlane(); CVector3D cPts[4]; float x=zfar*float(tan(g_NaviCam.GetCamera().GetFOV()*aspect*0.5)); float y=zfar*float(tan(g_NaviCam.GetCamera().GetFOV()*0.5)); cPts[0].X=-x; cPts[0].Y=-y; cPts[0].Z=zfar; cPts[1].X=x; cPts[1].Y=-y; cPts[1].Z=zfar; cPts[2].X=x; cPts[2].Y=y; cPts[2].Z=zfar; cPts[3].X=-x; cPts[3].Y=y; cPts[3].Z=zfar; // transform to world space CVector3D wPts[4]; for (int i=0;i<4;i++) { wPts[i]=g_NaviCam.GetCamera().m_Orientation.Transform(cPts[i]); } // now intersect a ray from the camera through each point CVector3D rayOrigin=g_NaviCam.GetCamera().m_Orientation.GetTranslation(); CVector3D rayDir=g_NaviCam.GetCamera().m_Orientation.GetIn(); CVector3D hitPt[4]; for (int i=0;i<4;i++) { CVector3D rayDir=wPts[i]-rayOrigin; rayDir.Normalize(); // get intersection point m_TerrainPlane.FindRayIntersection(rayOrigin,rayDir,&hitPt[i]); } CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); for (int i=0;i<4;i++) { // convert to minimap space float px=hitPt[i].X; float pz=hitPt[i].Z; g_MiniMap.m_ViewRect[i][0]=(197*px/float(CELL_SIZE*terrain->GetVerticesPerSide())); g_MiniMap.m_ViewRect[i][1]=197*pz/float(CELL_SIZE*terrain->GetVerticesPerSide()); } } void CEditorData::RenderTerrain() { CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); CFrustum frustum=g_NaviCam.GetCamera().GetFrustum(); u32 patchesPerSide= g_Game->GetWorld()->GetTerrain()->GetPatchesPerSide(); for (uint j=0; jGetPatch(i,j); if (frustum.IsBoxVisible (CVector3D(0,0,0),patch->GetBounds())) { g_Renderer.Submit(patch); } } } } void CEditorData::OnScreenShot(const char* filename) { g_Renderer.SetClearColor(0); g_Renderer.BeginFrame(); g_Renderer.SetCamera(g_NaviCam.GetCamera()); RenderWorld(); g_Renderer.EndFrame(); int width=g_Renderer.GetWidth(); int height=g_Renderer.GetHeight(); unsigned char* data=new unsigned char[width*height*3]; glReadBuffer(GL_BACK); glReadPixels(0,0,width,height,GL_BGR_EXT,GL_UNSIGNED_BYTE,data); saveTGA(filename,width,height,data); delete[] data; } ////////////////////////////////////////////////////////////////////////////////////////////////// // SubmitModelRecursive: recurse down given model, submitting it and all its descendants to the // renderer void SubmitModelRecursive(CModel* model) { g_Renderer.Submit(model); const std::vector& props=model->GetProps(); for (uint i=0;i& units=g_UnitMan.GetUnits(); for (i=0;iGetModel()); } CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); u32 patchesPerSide=terrain->GetPatchesPerSide(); for (j=0; jGetPatch(i,j); g_Renderer.Submit(patch); } } g_Renderer.FlushFrame(); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); g_Renderer.EndFrame(); } void CEditorData::RenderModels() { CFrustum frustum=g_NaviCam.GetCamera().GetFrustum(); const std::vector& units=g_UnitMan.GetUnits(); uint i; for (i=0;iGetModel()->GetBounds())) { SubmitModelRecursive(units[i]->GetModel()); } } } void CEditorData::RenderWorld() { // render terrain RenderTerrain(); // render all the units RenderModels(); // flush prior to rendering overlays etc g_Renderer.FlushFrame(); } void CEditorData::RenderObEdGrid() { int i; const int numSteps=32; const CVector3D start(-numSteps*CELL_SIZE/2,0,-numSteps*CELL_SIZE/2); const CVector3D end(numSteps*CELL_SIZE/2,0,numSteps*CELL_SIZE/2); glDisable(GL_TEXTURE_2D); glDepthMask(0); glColor4f(0.5f,0.5f,0.5f,0.35f); glLineWidth(1.0f); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glBegin(GL_LINES); for (i=0;i<=numSteps;i++) { if (i%8==0) continue; CVector3D v0(start.X+(i*(end.X-start.X))/float(numSteps),start.Y,start.Z); glVertex3fv(&v0.X); CVector3D v1(v0.X,end.Y,end.Z); glVertex3fv(&v1.X); } for (i=0;i<=numSteps;i++) { if (i%8==0) continue; CVector3D v0(start.X,start.Y,start.Z+(i*(end.Z-start.Z))/float(numSteps)); glVertex3fv(&v0.X); CVector3D v1(end.X,end.Y,v0.Z); glVertex3fv(&v1.X); } glEnd(); glDisable(GL_BLEND); glColor3f(0,0,0.5); glLineWidth(2.0f); glBegin(GL_LINES); for (i=0;i<=numSteps;i+=8) { CVector3D v0(start.X+(i*(end.X-start.X))/float(numSteps),start.Y,start.Z); glVertex3fv(&v0.X); CVector3D v1(v0.X,end.Y,end.Z); glVertex3fv(&v1.X); } for (i=0;i<=numSteps;i+=8) { CVector3D v0(start.X,start.Y,start.Z+(i*(end.Z-start.Z))/float(numSteps)); glVertex3fv(&v0.X); CVector3D v1(end.X,end.Y,v0.Z); glVertex3fv(&v1.X); } glEnd(); glDepthMask(1); } void CEditorData::OnDraw() { if (m_Mode==SCENARIO_EDIT || m_Mode==TEST_MODE) { g_Renderer.SetClearColor(0x00000000); g_Renderer.BeginFrame(); // setup camera g_Renderer.SetCamera(g_NaviCam.GetCamera()); // render base terrain plus models RenderWorld(); if (m_Mode!=TEST_MODE) { // render the active tool g_ToolMan.OnDraw(); } // flush prior to rendering overlays .. g_Renderer.FlushFrame(); // .. and here's the overlays g_MiniMap.Render(); m_InfoBox.Render(); const std::vector& units=g_UnitMan.GetUnits(); for (size_t i=0;iGetEntity()) units[i]->GetEntity()->renderSelectionOutline(); } else { g_Renderer.SetClearColor(0x00453015); g_Renderer.BeginFrame(); // CObjectEntry* selobject=g_ObjMan.GetSelectedObject(); // if (selobject && selobject->m_Model) { // // setup camera such that object is in the centre of the viewport // m_ModelMatrix.SetIdentity(); // selobject->m_Model->SetTransform(m_ModelMatrix); // // const CBound& bound=selobject->m_Model->GetBounds(); // CVector3D pt((bound[0].X+bound[1].X)*0.5f,(bound[0].Y+bound[1].Y)*0.5f,bound[0].Z); // // float hfov=tan(DEGTORAD(45)); // float vfov=hfov/g_Renderer.GetAspect(); // float zx=(bound[1].X-bound[0].X)*0.5f/hfov; // float zy=(bound[1].Y-bound[0].Y)*0.5f/vfov; // float z=zx>zy ? zx : zy; // z=(z+1)*2; // // m_ObjectCamera.m_Orientation.SetIdentity(); // m_ObjectCamera.m_Orientation.Translate(pt.X,pt.Y,-z); // // g_Renderer.SetCamera(m_ObjectCamera); // // RenderObEdGrid(); // // g_Renderer.Submit(selobject->m_Model); // } // flush prior to rendering overlays .. g_Renderer.FlushFrame(); // .. and here's the overlays m_InfoBox.Render(); } g_Renderer.EndFrame(); // notify info box frame is complete; gives it chance to accumulate stats, check // fps, etc m_InfoBox.OnFrameComplete(); } bool CEditorData::LoadTerrain(const char* filename) { Tex t; if(tex_load(filename, &t) < 0) { char buf[1024]; sprintf(buf,"Failed to load \"%s\"",filename); ErrorBox(buf); return false; } uint width=t.w, height=t.h, bpp=t.bpp; void *ptr=tex_get_data(&t); // rescale the texture to fit to the nearest of the 4 possible map sizes u32 mapsize=9; // assume smallest map if (width>11*PATCH_SIZE+1) mapsize=11; if (width>13*PATCH_SIZE+1) mapsize=13; if (width>17*PATCH_SIZE+1) mapsize=17; u32 targetsize=mapsize*PATCH_SIZE+1; unsigned char* data=new unsigned char[targetsize*targetsize*bpp/8]; u32 fmt=(bpp==8) ? GL_RED : ((bpp==24) ? GL_RGB : GL_RGBA); gluScaleImage(fmt,width,height,GL_UNSIGNED_BYTE,ptr, targetsize,targetsize,GL_UNSIGNED_BYTE,data); // build 16 bit heightmap from red channel of texture u16* heightmap=new u16[targetsize*targetsize]; int stride=bpp/8; u16* hmptr=heightmap; // get src of copy const u8* dataptr = (bpp==8) ? data : ((bpp==24) ? data+2 : data+3); // build heightmap for (uint j=0;jGetWorld()->GetTerrain()->Resize(mapsize); g_Game->GetWorld()->GetTerrain()->SetHeightMap(heightmap); // clean up delete[] data; delete[] heightmap; (void)tex_free(&t); // re-initialise minimap - terrain size may have changed g_MiniMap.Initialise(); return true; } // UpdateWorld: update time dependent data in the world to account for changes over // the given time (in s) void CEditorData::UpdateWorld(float time) { if (m_Mode==SCENARIO_EDIT || m_Mode==TEST_MODE) { g_EntityManager.interpolateAll(0.f); const std::vector& units=g_UnitMan.GetUnits(); for (uint i=0;iGetModel()->Update(time); } // if (m_Mode==TEST_MODE) { // g_EntityManager.updateAll( time ); // } } else { // CObjectEntry* selobject=g_ObjMan.GetSelectedObject(); // if (selobject && selobject->m_Model) { // selobject->m_Model->Update(time); // } } } void CEditorData::StartTestMode() { // initialise entities g_EntityManager.InitializeAll(); } void CEditorData::StopTestMode() { // make all units idle again const std::vector& units=g_UnitMan.GetUnits(); for (uint i=0;iSetRandomAnimation("idle"); } }